Запуск/останов запуска агента запуска для всех пользователей с сеансами GUI

Мне нужно иметь возможность запускать/останавливать агент GUI за сеанс от демона уровня корня.

Подобные проблемы обсуждаются здесь, здесь и здесь.

То, что я хочу сделать, это в основном

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

но это только запускает/останавливает один экземпляр и запускается как root в текущем сеансе графического интерфейса пользователя. Если я оставлю sudo, начните, я получу

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

Я попытался объединиться с множеством других перестановок bsexec (включая вызов вторичного script из bsexec с помощью команды load/unload), но я никогда не смогу запустить экземпляр как ничего, кроме root и никогда в другом сеансе графического интерфейса.

Я также попытался объединиться с su - <user> ... и sudo -u <user> ..., но не повезло и там (как многие люди обсуждали в вышеупомянутых связанных статьях и в других местах).

Есть ли у кого-нибудь мысли?

EDIT: Я попытался сделать это с помощью инструмента-обертки, как предложено ниже Грэмом Ли, но я получаю следующую ошибку:

launch_msg(): Socket is not connected

Это команда командной строки, обертка и script Я использую (501 - это идентификатор пользователя и 63093 pid запуска для другого пользователя, подключенного к системе):

Командная строка:

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

Упаковочный:

#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

Ответ 1

Использование launchctl bsexec верное, но вам нужно запустить средство обертки, которое удаляет UID целевому пользователю перед запуском исполняемого файла "real". О, и, вероятно, лучше искать процессы loginwindow, поскольку они являются лидерами сеансов входа в систему (хотя launchd, скорее всего, тоже будет работать).

Ответ 2

Похоже, что экземпляры запуска каждого пользователя запускаются не в одном и том же пространстве имен начальной загрузки, поскольку launchctl запускается из терминала.

Используя Dock.app как донор pid и некоторую магию 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")}'

можно запустить агент во всех сеансах.

Неплохо, но работает.

Обновление: не будет работать на 10.7. Да, агент будет запущен, но, как я вижу, из тестов не в правильном контексте.

Ответ 3

Основываясь на обсуждениях здесь и этот script, я не думал, что инструмент обертки должен быть необходим. Эти два скрипта bash также могут помочь другим.

Разгрузить агентов

#!/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

Замените "MyAgent" на имя вашего агента запуска.

Агенты загрузки

#!/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

Вызывается из корневого демона, это загрузит и выгрузит агент запуска, указанный в myAgent.plist для всех зарегистрированных пользователей.

Обратите внимание, что из-за "rootless" в OS X El Capitan (10.11) использование bsexec может больше не работать, но до 10.10 это должно быть хорошо.

Ответ 4

У меня была та же проблема. Чтобы решить эту проблему, используйте pid "under" launchd, pid процесса, запуск которого запущен.

PID, который вы передаете "launchctlbsexec", используется для поиска правильного бутстрапа. Если вы используете pid launchd (из контекста пользователя), чем работаете в корневой загрузке rootd. Если вы используете pe. Finder или Dock pid пользователя, вы можете работать в этом бутстрапе "для каждого пользователя"