8

launchd.plist特定のUSBデバイスがマウントされるたびに実行されるXMLを設定しています。xpc_events(3)のマニュアルページの指示に従い、デバイスがマウントされるたびにアプリケーションが実行されます。

私が抱えている問題は、デバイスがまだマウントされている限り、アプリケーションが10秒ごとに何度も実行されることです。デバイスがUSBポートに挿入されたときに1回だけ実行されるように設定するにはどうすればよいですか?

<?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>
4

4 に答える 4

9

外部デバイス(usb / thunderbolt)をMacコンピューターに接続することで、再生成の問題なしに任意の実行可能ファイルまたはシェルスクリプトをトリガーするための詳細な手順とサンプルファイルを使用して、これに関するチュートリアルを作成しました。

著者のアプローチと同様に、デバイスの検出にはAppleのライブラリに依存しIOKit、目的の実行可能ファイルを実行するにはデーモンに依存しています。デバイスの接続後にデーモンが繰り返しトリガーされないようにするには、@ fordによる投稿と彼のgithubリポジトリで説明されているように、特別なストリームハンドラー(xpc_set_event_stream_handler)を使用してイベントを「消費」します。com.apple.iokit.matching

特に、チュートリアルでは、xpcストリームハンドラーをコンパイルする方法と、デーモンplistファイル内の実行可能ファイルと一緒にそれを参照する方法、および関連するすべてのファイルを正しいアクセス許可で配置する場所について説明します。

ファイルについては、こちらをご覧ください。完全を期すために、以下にそれらのコンテンツも貼り付けました。

Macでデバイス検出によってトリガーされたシェルスクリプトまたは実行可能ファイルを実行する

ここでは、イーサネットアダプタがMacに接続されているときにそのMACアドレスをスプーフィングする例を使用します。これは、任意の実行可能ファイルとデバイスに一般化できます。

シェルスクリプトまたは実行可能ファイルを配置します

シェルスクリプトを適応させるspoof-mac.sh

#!/bin/bash
ifconfig en12 ether 12:34:56:78:9A:BC

必要に応じて実行可能にします。

sudo chmod 755 spoof-mac.sh

次に、それを/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);
        }
    }
}

ユニバーサル(適応する必要はありません)であり、macコマンドライン(xcodeがインストールされている)で構築できます:

gcc -framework Foundation -o xpc_set_event_stream_handler xpc_set_event_stream_handler.m

/usr/local/binデーモンのメインの実行可能ファイルのように、に配置しましょう。

cp xpc_set_event_stream_handler /usr/local/bin/

デーモンをセットアップします

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>

、、などidVendor、トリガーのベースにするデバイスを識別するための情報が含まれています。これらは、Macのアプリで把握できます。idProductIOProviderClassSystem Information

スクリーンショットシステム情報

plistファイルに挿入する前に16進識別子を整数に変換します(たとえばint(0x8086)、Pythonで使用します)。

IOProviderClassIOPCIDevice(Thunderbolt)またはIOUSBDevice(USB)のいずれかである必要があります。

plistファイルの他の関連するエントリは、実行可能ファイルの場所xpc_set_event_stream_handlerと実行可能ファイルです。

その他のエントリには、標準出力(ログ)ファイルの場所と実行中のユーザーが含まれます。

MACスプーフィングにはroot権限が必要なため、次のように記述com.spoofmac.plist/Library/LaunchDaemonsます。

cp com.spoofmac.plist /Library/LaunchDaemons/

LaunchAgentsフォルダには入れません。起動エージェントはUserName引数を無視します。

ファイルの所有者が次のrootとおりであることを確認してください。

sudo chown root:wheel /Library/LaunchDaemons/com.spoofmac.plist

デーモンを起動します

デーモンをアクティブ化します。

launchctl load /Library/LaunchDaemons/com.spoofmac.plist

そして、あなたは行ってもいいです。

アンロードはを使用して行われlaunchctl unloadます。

于 2018-04-18T14:47:24.887 に答える
4

AIUIアプリケーションは、xpc_set_event_stream_handlerを呼び出して、キューからイベントを削除する必要があります。<key>KeepAlive</key><false/>.plistに追加する必要があるかもしれませんが、それについてはよくわかりません。

于 2012-12-21T12:23:09.793 に答える
1

私はこのようなものを使おうとしています:

#include <xpc/xpc.h>
#include <unistd.h>
#include <asl.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        return 1;
    }

    asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "event_stream_handler: starting");

    xpc_set_event_stream_handler("com.apple.iokit.matching", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(xpc_object_t event) {
        const char *name = xpc_dictionary_get_string(event, XPC_EVENT_KEY_NAME);
        uint64_t id = xpc_dictionary_get_uint64(event, "IOMatchLaunchServiceID");
        asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "event_stream_handler: received event: %s: %llu", name, id);

        execv(argv[1], argv + 1);
    });

    dispatch_main();

    return 0;
}

したがって、イベントを消費し、引数として渡されたスクリプトを実行するスクリプト。

于 2016-02-01T11:21:08.260 に答える
0

これは私のために働きます:

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);
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        if(argc >= 2) {
            execv(argv[1], (char **)argv+1);
        }
    }
}

完全なソースコードはこちら

于 2018-02-20T23:34:07.623 に答える