2009-07-09 5 views
11

Je dois pouvoir démarrer/arrêter un agent d'interface graphique par session à partir d'un démon de niveau racine. Des problèmes similaires sont discutés here, here et here.Démarrage/arrêt d'un agent launchd pour tous les utilisateurs ayant des sessions GUI

Ce que je veux être en mesure de faire est essentiellement

for num in `ps ax | grep [s]bin/launchd | cut -c 1-5`; 
do 
    if [ $num -ne 1 ]; 
    then 
     sudo launchctl bsexec $num launchctl (un)load -S Aqua /Library/LaunchAgents/com.mycompany.mydaemon.plist; 
    fi; 
done 

mais cela ne démarre/arrête une instance et il fonctionne en tant que root dans la session de l'interface actuelle. Si je quitte le sudo commencer là, je me

task_for_pid() (os/kern) failure 
Couldn't switch to new bootstrap port: (ipc/send) invalid port right 

J'ai essayé de déconner avec une variété d'autres permutations de bsexec (y compris appeler un script secondaire de bsexec à la charge/commande décharger), mais je ne peux ne jamais faire démarrer l'instance autrement que par root et jamais dans une autre session GUI.

J'ai également essayé de jouer avec su - <user> ... et sudo -u <user> ..., mais n'y ai pas eu de chance non plus (comme beaucoup de gens en ont parlé dans les articles ci-dessus et ailleurs).

Quelqu'un a-t-il des idées?

EDIT: J'ai essayé de le faire avec un outil d'emballage comme suggéré ci-dessous par Graham Lee, mais je reçois l'erreur suivante:

launch_msg(): Socket is not connected 

Ceci est la commande de ligne de commande, emballage et script que je suis l'utilisation (501 est le code d'utilisateur et le pid 63093 de launchd pour un autre utilisateur connecté au système):

ligne de commande:

sudo launchctl bsexec 63093 /path/TestSetUIDAndExecuteTool 501 /path/LoadBillingDialogAgent 

Wrapper:

#import <Foundation/Foundation.h> 

int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    if (argc != 3) { 
    NSLog(@"Tool called with improper arguments"); 
    return -1; 
    } 

    int uid = [[NSString stringWithUTF8String:argv[1]] intValue]; 
    // TODO: REMOVE 
    NSLog(@"Setting uid to |%i|", uid); 

    setuid(uid); 
    // TODO: REMOVE 
    char *command = (char *)argv[2]; 
    NSLog(@"Executing command |%s|", command); 
    system(command); 

    [pool drain]; 
    return 0; 
} 

Script:

/bin/launchctl load -S Aqua /Library/LaunchAgents/com.company.agent.plist 

Répondre

6

L'utilisation launchctl bsexec est correct, mais vous avez besoin de lancer un outil d'emballage qui tombe UID à l'utilisateur cible avant de lancer l'exécutable de l'agent 'réel'. Oh, et il est probablement préférable de rechercher des processus loginwindow, car ce sont les leaders des sessions de connexion (bien que launchd a de fortes chances de fonctionner aussi).

+0

Lorsque je fais cela (voir l'édition avec l'outil wrapper ci-dessus), j'obtiens une erreur 'launch_msg(): Socket is not connected' –

+0

Suis-je en train de supprimer l'UID de manière corrente? –

+0

En fait, j'ai compris celui-ci. Il semble que l'environnement de test que j'avais mis en place n'était pas tout à fait le même qu'un vrai démon de niveau racine. Merci pour l'aide. –

4

Il semble que les instances launchd par utilisateur ne s'exécutent pas dans le même espace de noms bootstrap que launchctl lancé à partir de Terminal.

En utilisant Dock.app comme donneur pid et un peu de magie sudo:

ps aux | grep Dock.app | grep -v grep | awk '{system("sudo launchctl bsexec "$2" sudo -u "$1" launchctl load -S Aqua /Library/LaunchAgents/com.my.agent.plist")}' 

il est possible de lancer un agent dans toutes les sessions en cours d'exécution.

Pas propre, mais ça marche.

Mise à jour: ne fonctionne pas sur 10.7. Oui, l'agent sera lancé, mais comme je peux le voir des tests ne sont pas dans le bon contexte.

+1

Aussi ne fonctionnera pas sur 10.9. L'agent sera lancé dans un contexte différent et, par exemple, il ne peut pas afficher d'interface utilisateur (pas d'erreurs, juste invisible). – esmirnov

1

J'ai eu le même problème. Pour résoudre ce problème, utilisez un pid "under" launchd, le pid d'un processus lancé par launchd.

Le pid que vous avez lancé sur 'launchctl bsexec' est utilisé pour trouver le bon bootstrap. Si vous utilisez le pid de launchd (à partir du contexte de l'utilisateur) que vous travaillez dans le bootstrap de launchd root. Si vous utilisez pe. le Finder ou le Dock pid de l'utilisateur, vous pouvez travailler dans ce bootstrap "par utilisateur"

3

Basé sur les discussions ici et this script, je ne pensais pas qu'un outil d'emballage devrait être nécessaire. Ces deux scripts bash peuvent aussi aider les autres.

Unload Agents

#!/bin/bash 
for id in `ps aux | grep -v grep | grep MyAgent | awk {'print $2'}` 
do 
    launchctl bsexec $id launchctl unload /Library/LaunchAgents/myAgent.plist 
done 

Remplacer 'myAgent' avec le nom de votre agent de lancement.

Load Agents

#!/bin/bash 
for pid_uid in $(ps -axo pid,uid,args | grep -i "[l]oginwindow.app" | awk '{print $1 "," $2}'); do 

    pid=$(echo $pid_uid | cut -d, -f1) 
    uid=$(echo $pid_uid | cut -d, -f2) 

    launchctl bsexec "$pid" chroot -u "$uid"/launchctl load /Library/LaunchAgents/myAgent.plist 
done 

Appelé à partir d'un démon racine, cela va charger et décharger l'agent de lancement référencé dans myAgent.plist pour tous les utilisateurs connectés.

Notez qu'en raison de 'rootless' dans OS X El Capitan (10.11), l'utilisation de bsexec peut ne plus fonctionner, mais jusqu'à 10.10, cela devrait aller.

+4

Pour El Capitan (10.11) Suivant devrait fonctionner 'launchctl bootstrap gui/$ uid/Bibliothèque/LaunchAgents/myAgent.plist' – vrrathod

+0

Merci @vrrathod, c'est bon à savoir. – TheDarkKnight

Questions connexes