使用 GUI 会话为所有用户启动/停止 launchd 代理

发布于 2024-07-26 08:57:52 字数 2098 浏览 11 评论 0原文

我需要能够从根级别守护程序启动/停止每个会话 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

但这只会启动/停止一个实例,并且它在当前 GUI 会话中以 root 身份运行。 如果我将 sudo 保留在那里,

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

我会尝试使用 bsexec 的各种其他排列(包括使用加载/卸载命令从 bsexec 调用辅助脚本),但我永远无法让实例启动除 root 之外的任何内容,并且绝不会在另一个 GUI 会话中。

我还尝试过使用 su -; ...sudo -u; ...,但也没有运气(正如许多人在上面链接的文章和其他地方讨论的那样)。

有人有什么想法吗?

编辑: 我尝试按照 Graham Lee 的建议使用包装器工具执行此操作,但出现以下错误:

launch_msg(): Socket is not connected

这是我正在使用的命令行命令、包装器和脚本(501 是用户 ID,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;
}

脚本:

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

I need to be able to start/stop a per-session GUI agent from a root level daemon.

Similar issues are discussed here, here and here.

What I want to be able to do is basically

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

but this only starts/stops one instance and it runs as root in the current GUI session. If I leave the sudo off there start I get

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

I've tried messing around with a variety of other permutations of bsexec (including calling a secondary script from bsexec with the load/unload command), but I can never get the instance to start as anything other than root and never in another GUI session.

I also tried messing around with su - <user> ... and sudo -u <user> ..., but had no luck there either (as many people have discussed in the above linked articles and elsewhere).

Does anybody have any thoughts?

EDIT:
I tried doing this with a wrapper tool as suggested below by Graham Lee, but I get the following error:

launch_msg(): Socket is not connected

This is the command line command, wrapper, and script I'm using (501 is the userid and 63093 the pid of launchd for another user logged in to the system):

Command line:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

勿忘初心 2024-08-02 08:57:52

使用 launchctl bsexec 是正确的,但您需要启动一个包装工具,在运行“真正的”代理可执行文件之前将 UID 删除给目标用户。 哦,最好寻找 loginwindow 进程,因为它们是登录会话的领导者(尽管 launchd 也很可能起作用)。

Using launchctl bsexec is correct, but you need to launch a wrapper tool which drops UID to the target user before running the 'real' agent executable. Oh, and it's probably better to look for loginwindow processes, as those are the leaders of the login sessions (though launchd is very likely to work too).

素手挽清风 2024-08-02 08:57:52

看起来每个用户的 launchd 实例与从终端启动的 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 上不起作用。是的,将启动代理,但正如我从测试中看到的,不在正确的上下文中。

It looks like per-user launchd instances are running not in the same bootstrap namespace as launchctl launched from Terminal.

By using Dock.app as pid donor and some sudo magic:

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")}'

it is possible to launch agent in all running sessions.

Not neat, but works.

Update: will not work on 10.7. Yes, agent will be launched, but as I can see from tests not in the correct context.

情深缘浅 2024-08-02 08:57:52

根据此处的讨论和此脚本,我认为不需要包装工具。 这两个 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 中引用的启动代理。

请注意,由于 OS X El Capitan (10.11) 中的“无根”,使用 bsexec 可能不再有效,但到 10.10 为止,这应该没问题。

Based on the discussions here and this script, I didn't think a wrapper tool should be necessary. These two bash scripts may help others too.

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

Replace 'MyAgent' with the name of your Launch Agent.

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

Called from a root daemon, this will load and unload the Launch Agent referenced in myAgent.plist for all logged-in users.

Note that due to 'rootless' in OS X El Capitan (10.11), the use of bsexec may no longer work, but up to 10.10, this should be fine.

心安伴我暖 2024-08-02 08:57:52

我有同样的问题。
要解决此问题,请使用 launchd“下”的 pid,即 launchd 已启动的进程的 pid。

您提交给“launchctl bsexec”的 pid 用于查找正确的引导程序。 如果您使用 launchd 的 pid(来自用户上下文),那么您将在根 launchd 引导程序中工作。 如果你使用pe。 用户的 Finder 或 Dock pid,您可以在此“每用户”引导程序中工作

I had the same problem.
To solve this, use a pid "under" launchd, the pid of a process that launchd has started.

The pid you commit to 'launchctl bsexec' is used to find the right bootstrap. If you use the pid of launchd (from the user context) than you work in the root launchd bootstrap. If you use pe. the Finder or the Dock pid of the user, you can work in this "per-user" bootstrap

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文