launchd.plist每10秒运行一次,而不是一次

Chr*_*fer 5 macos usb launchd

我一直在设置一个launchd.plistXML,该XML在每次安装特定的USB设备时都会运行。我按照xpc_events(3)手册页上的说明进行操作,无论何时装入设备,它都在运行应用程序。

我遇到的问题是,只要仍然安装设备,该应用程序就会每10秒钟运行一次。如何设置它,使其仅在将设备插入USB端口时才运行一次?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.myapp.agent</string>
    <key>Program</key>
    <string>/Applications/MyApp.app/Contents/MacOS/MyAgent</string>
    <key>LaunchEvents</key>
    <dict>
        <key>com.apple.iokit.matching</key>
        <dict>
            <key>com.apple.device-attach</key>
            <dict>
                <key>idVendor</key>
                <integer>2316</integer>
                <key>idProduct</key>
                <integer>4096</integer>
                <key>IOProviderClass</key>
                <string>IOUSBDevice</string>
                <key>IOMatchLaunchStream</key>
                <true/>
            </dict>
        </dict>
        <key>com.apple.notifyd.matching</key>
        <dict>
            <key>com.apple.interesting-notification</key>
            <dict>
                <key>Notification</key>
                <string>com.apple.interesting-notification</string>
            </dict>
        </dict>
    </dict>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)

lsr*_*ggr 5

我为此编写了一个教程,其中包含详细的说明和示例文件,这些示例文件用于通过将外部设备(usb / thunderbolt)连接到Mac计算机来触发任意可执行文件或shell脚本,而不会产生重生问题。

像作者的方法一样,它依靠Apple的IOKit库来进行设备检测,并依靠守护程序来运行所需的可执行文件。为了使守护程序在连接设备后不再被重复触发,使用了一个特殊的流处理程序(xpc_set_event_stream_handler)来“消费”该com.apple.iokit.matching事件,如@ford的帖子及其github repo中所述

特别是,本教程描述了如何编译xpc流处理程序以及如何将其与可执行文件一起在守护程序plist文件中进行引用,以及在何处以正确的权限放置所有相关文件。

有关文件,请转到此处。为了完整起见,我还在下面粘贴了它们的内容。

在Mac上运行由设备检测触发的Shell脚本或可执行文件

在这里,我以以太网适配器连接到Mac时欺骗其MAC地址为例。这可以推广到任意可执行文件和设备。

将您的Shell脚本或可执行文件放到位

修改shell脚本 spoof-mac.sh

#!/bin/bash
ifconfig en12 ether 12:34:56:78:9A:BC
Run Code Online (Sandbox Code Playgroud)

满足您的需求并使其可执行:

sudo chmod 755 spoof-mac.sh
Run Code Online (Sandbox Code Playgroud)

然后将其移动到/usr/local/bin或其他目录中:

cp spoof-mac.sh / usr / local / bin /

构建流处理程序

流处理程序 xpc_set_event_stream_handler.m

//  Created by Ford Parsons on 10/23/17.
//  Copyright © 2017 Ford Parsons. All rights reserved.
//

#import <Foundation/Foundation.h>
#include <xpc/xpc.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        xpc_set_event_stream_handler("com.apple.iokit.matching", NULL, ^(xpc_object_t _Nonnull object) {
            const char *event = xpc_dictionary_get_string(object, XPC_EVENT_KEY_NAME);
            NSLog(@"%s", event);
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        if(argc >= 2) {
            execv(argv[1], (char **)argv+1);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

是通用的(无需调整),可以在mac命令行(安装了xcode)上构建:

gcc -framework Foundation -o xpc_set_event_stream_handler xpc_set_event_stream_handler.m
Run Code Online (Sandbox Code Playgroud)

让我们将其放入/usr/local/bin,就像守护程序的主要可执行文件一样。

cp xpc_set_event_stream_handler /usr/local/bin/
Run Code Online (Sandbox Code Playgroud)

设置守护程序

plist文件com.spoofmac.plist包含将在设备连接触发器上运行可执行文件的守护程序的属性。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>UserName</key>
    <string>root</string>
    <key>StandardErrorPath</key>
    <string>/tmp/spoofmac.stderr</string>
    <key>StandardOutPath</key>
    <string>/tmp/spoofmac.stdout</string>
    <key>Label</key>
    <string>com.spoofmac.program</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/xpc_set_event_stream_handler</string>
        <string>/usr/local/bin/spoofmac.sh</string>
    </array>
    <key>LaunchEvents</key>
    <dict>
        <key>com.apple.iokit.matching</key>
        <dict>
            <key>com.apple.device-attach</key>
            <dict>
                <key>idVendor</key>
                <integer>32902</integer>
                <key>idProduct</key>
                <integer>5427</integer>
                <key>IOProviderClass</key>
                <string>IOPCIDevice</string>
                <key>IOMatchLaunchStream</key>
                <true/>
                <key>IOMatchStream</key>
                <true/>
            </dict>
        </dict>
    </dict>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)

它包含了信息识别要立足,就像你的触发装置idVendoridProductIOProviderClass。这些可以在System InformationMac上的App中找到。

屏幕截图系统信息

在插入plist文件之前(例如int(0x8086)在python中使用),将十六进制标识符转换为整数。

IOProviderClass应该是IOPCIDevice(Thunderbolt)或IOUSBDevice(USB)。

plist文件中的另一个相关条目是xpc_set_event_stream_handler可执行文件的位置。

其他条目包括标准输出(日志)文件和执行用户的位置。

由于MAC欺骗,需要root权限,我们把com.spoofmac.plist/Library/LaunchDaemons

cp com.spoofmac.plist /Library/LaunchDaemons/
Run Code Online (Sandbox Code Playgroud)

不放入LaunchAgents文件夹。启动代理忽略该UserName参数。

确保文件的所有者是root

sudo chown root:wheel /Library/LaunchDaemons/com.spoofmac.plist
Run Code Online (Sandbox Code Playgroud)

启动守护程序

激活守护程序:

launchctl load /Library/LaunchDaemons/com.spoofmac.plist
Run Code Online (Sandbox Code Playgroud)

而且你很好。

卸载是使用完成的launchctl unload

  • 我更改了帖子以包含所有外部链接内容。 (2认同)

Gor*_*son 4

AIUI您的应用程序必须调用xpc_set_event_stream_handler来从队列中删除事件。您可能还需要添加<key>KeepAlive</key><false/>到 .plist,但我不确定这一点。