2009-07-09 9 views
11

Necesito poder iniciar/detener un agente de GUI por sesión desde un daemon de nivel de raíz.Iniciar/detener un agente de inicio para todos los usuarios con sesiones de GUI

Se discuten los problemas similares here, here y here.

Lo que yo quiero ser capaz de hacer es básicamente

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 

pero esto sólo se inicia/detiene una instancia y se ejecuta como root en la sesión de interfaz gráfica de usuario actual. Si dejo el sudo fuera allí comenzar consigo

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

He intentado jugar un poco con una variedad de otras permutaciones de bsexec (incluyendo llama a un script secundaria de bsexec con la carga/descarga de comandos), pero no puedo nunca haga que la instancia comience como otra cosa que no sea root y nunca en otra sesión GUI.

También intenté meterme con su - <user> ... y sudo -u <user> ..., pero tampoco tuve suerte (como mucha gente ha discutido en los artículos vinculados anteriormente y en otros lugares).

¿Alguien tiene alguna idea?

EDIT: He intentado hacer esto con una herramienta envoltorio como se sugiere a continuación por Graham Lee, pero me sale el siguiente error:

launch_msg(): Socket is not connected 

Este es el comando de línea de comandos, envoltura, y el guión que estoy usando (501 es el ID de usuario y 63093 el pid de launchd para otro usuario conectado al sistema):

línea de comandos:

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; 
} 

Guión:

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

Respuesta

6

Usando launchctl bsexec es correcta, pero hay que poner en marcha una herramienta de envoltura que cae UID para el usuario de destino antes de ejecutar el ejecutable agente 'real'. Ah, y probablemente sea mejor buscar los procesos loginwindow, ya que esos son los líderes de las sesiones de inicio de sesión (aunque es muy probable que también funcione launchd).

+0

Cuando hago esto (vea la herramienta de edición con la herramienta de envoltura anterior), aparece el error 'launch_msg(): Socket is not connected' –

+0

¿Debo soltar el UID de la misma manera? –

+0

En realidad, pensé en esto. Parece que el entorno de prueba que había configurado no era lo mismo que un daemon de nivel raíz verdadero. Gracias por la ayuda. –

4

Parece que las instancias de launchd por usuario no se ejecutan en el mismo espacio de inicio de arranque como launchctl iniciado desde Terminal.

Mediante el uso de Dock.app como donante de PID y un poco de magia 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")}' 

es posible poner en marcha agente en todas las sesiones que se ejecutan.

No es ordenado, pero funciona.

Actualización: no funcionará en 10.7. Sí, se lanzará el agente, pero como puedo ver en las pruebas, no en el contexto correcto.

+1

Tampoco funcionará en 10.9. El agente se lanzará en un contexto diferente y, por ejemplo, no puede mostrar la interfaz de usuario (sin errores, simplemente invisible). – esmirnov

1

Tuve el mismo problema. Para resolver esto, use un pid "under" launchd, el pid de un proceso que se inició.

El pid que se compromete con 'launchctl bsexec' se usa para encontrar el bootstrap correcto. Si usa el pid de launchd (desde el contexto del usuario) que trabaja en el rootd bootstrap. Si usas pe. el Finder o el Dock pid del usuario, puede trabajar en este bootstrap "por usuario"

3

Basado en las discusiones aquí y this script, no creo que una herramienta contenedora deba ser necesaria. Estos dos scripts bash pueden ayudar a otros también.

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 

Reemplazar 'MyAgent' con el nombre de su Agente de lanzamiento.

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 

Llamado de un demonio de raíz, esto va a cargar y descargar el Agente lanzamiento hace referencia en myAgent.plist para todos los usuarios conectados.

Tenga en cuenta que debido a 'rootless' en OS X El Capitan (10.11), el uso de bsexec puede no funcionar, pero hasta 10.10, esto debería estar bien.

+4

Para El Capitan (10.11) Lo siguiente debería funcionar 'launchctl bootstrap gui/$ uid/Library/LaunchAgents/myAgent.plist' – vrrathod

+0

Gracias @vrrathod, eso es bueno saberlo. – TheDarkKnight

Cuestiones relacionadas