Как вы можете запустить LaunchAgent в первый раз без перезагрузки, когда ваш код работает как LaunchDaemon? - PullRequest
5 голосов
/ 26 октября 2011

У меня есть LaunchDaemon. Когда он работает, он проверяет, установлен ли SIMBL. Если SIMBL не установлен, он использует NSTask для запуска / usr / sbin / installer на SIMBL.pkg.

После этого сценарий SIMBL пытается запустить команду загрузки launchctl, чтобы немедленно запустить LaunchAgent SIMBL:

sudo -u "$USER" -- /bin/launchctl load -F -S Aqua -D user "${LAUNCHD_PLIST}"

Это не получится, потому что в моей среде LaunchDaemon NSTask не установлен $ USER.

Если мой демон обнаружит текущего пользователя с помощью инфраструктуры конфигурации системы и передаст его в NSTask с помощью setEnvironment, то у меня будет ошибка launchctl:

Bug: launchctl.c:2325 (23930):13: (dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1

Я понимаю, что демон по определению не должен работать в сеансе пользователя. Точно так же Apple, похоже, рекомендует LaunchAgents в качестве вспомогательных объектов для LaunchDaemons для выполнения этой пользовательской сессии. Есть ли способ немедленно запустить и запустить такого агента?

У меня есть все .plists в нужных местах (они запускаются после перезагрузки, когда в следующий раз launchctl выполняет свою обычную загрузку), поэтому моей первой мыслью было просто сказать launchctl для перезагрузки. Но весь код для этого закомментирован в launchctl.c :

//  { "reload",         reload_cmd,             "Reload configuration files and/or directories" },

...

 * In later versions of launchd, I hope to load everything in the first pass,
 * then do the Bonjour magic on the jobs that need it, and reload them, but for now,
 * I haven't thought through the various complexities of reloading jobs, and therefore
 * launchd doesn't have reload support right now.

1 Ответ

6 голосов
/ 26 октября 2011

О, как launchd сводит меня с ума ....

Чтобы перейти к поиску, после долгих исследований и экспериментов, вот как я делаю это на 10,5 +:

# If possible, tell launchd to start the LaunchAgent. This will fail on 10.4.
# $F[0] is the pid
# $F[1] is the username
# $F[2] is the first word of the command
ps -ww -A -opid,user,command | \
  perl -nae 'if($F[2] =~ /\bloginwindow\b/) { system(
    qq(launchctl bsexec $F[0] su $F[1] -c "launchctl load -w <your_plist>"))
}'

Я не нашел способа добиться этого непосредственно на 10.4.Я обманываю на 10.4 и просто запускаю то, что запускал бы LaunchAgent, даже если у него есть графический интерфейс, и вы не должны этого делать (вы можете в любом случае в 10.4-10.6; вы не можете в 10.7).На 10.4 LaunchAgent работает корректно после следующей перезагрузки.

Приведенный выше код ищет loginwindow процессы и использует bsexec для запуска команд в этих контекстах.Помните, что при быстром переключении пользователей может быть несколько контекстов.

Некоторые полезные ссылки:

IMO, launchd - одна из худших "великих идей", которые когда-либо использовала Apple.Идея очень полезна, но API ужасен.

...