web-dev-qa-db-ja.com

Pythonスクリプトを実行するudevルール

Bluetoothヘッドセットに接続するたびに、自動的に this スクリプトを実行しようとしています。

ファイル/etc/udev/rules.d/80-bt-headset.rulesを次の行で作成しました

ACTION=="add", SUBSYSTEM=="input" ATTR{name}=="00:22:37:3D:DA:50" RUN+="/home/USER/.local/bin/a2dp.py 00:22:37:3D:DA:50"

しかし、それは何もしません。条件は問題ありません。代わりに入力すると、簡単なテストコマンドがトリガーされます。スクリプト自体は、手動で実行しても正常に機能します。

ここで何が問題になっていますか?

UpdateSudo -u USERでスクリプトを実行するとエラーが発生します(詳細については以下を参照)。これが問題になりますか?そして、同じユーザーへのSudo-ingはどのように物事を壊しますか?

更新2a2dp.pypacmdのすべてのインスタンスをpactlに置き換えた後(およびlist-sinkslist sinksに置き換えて有効にするpactlコマンド)、Sudo -u USERは動作しますが、udevルールはまだ動作しません。 /var/log/syslogに次の行が表示されます

systemd-udevd[32629]: Process '/home/USER/.local/bin/a2dp_2.py 00:22:37:3D:DA:50' failed with exit code 1.

Update 3(Solution):環境変数DISPLAY=:0およびXAUTHORITY=/home/USER/.Xauthorityを使用して修正されたskript(pacmd-> pactl、Update 2を参照)がトリックを行いました。 udevルール:

ACTION=="add", SUBSYSTEM=="input" ATTR{name}=="00:22:37:3D:DA:50" ENV{DISPLAY}=":0" ENV{XAUTHORITY}="/home/USER/.Xauthority" RUN+="/home/USER/.local/bin/a2dp_2.py 00:22:37:3D:DA:50"

意図したとおりに機能しています。

(現在残っている唯一の問題は、ヘッドセットを再接続するときにスクリプト自体がルールをトリガーし、無限ループが発生することです。しかし、それは別の質問であり、回避策を見つけるのはそれほど難しくないはずです。実際、私はこのスレッドを開始したときにその動作を期待していました。)

動作するもの:

  1. 条件は問題ありません:行:

    ACTION=="add", SUBSYSTEM=="input" ATTR{name}=="00:22:37:3D:DA:50" RUN+="/bin/mkdir /tmp/testme"
    

    ヘッドセットに接続すると、新しいディレクトリが作成されます。

  2. スクリプトa2dp.py自体は、ターミナルから

    /home/USER/.local/bin/a2dp.py 00:22:37:3D:DA:50
    
  3. Udevを介して単にPythonスクリプトを実行する:

    ACTION=="add", SUBSYSTEM=="input" ATTR{name}=="00:22:37:3D:DA:50" RUN+="/home/USER/.local/bin/atestscript.py"
    

    atestscript.pyの内容は次のとおりです。

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import subprocess
    
    def main():
        subprocess.Popen(['mkdir', '/tmp/atestdir'])
    
    if __== '__main__':
        main()
    

    デバイスが接続されると、フォルダーが再び作成されます。

Pacmdをpactlに置き換えた後の動作:

  1. Sudo -u USERまたはSudo -u rootを使用して端末からスクリプトを実行すると、意図したとおりに動作するようになりました(元のスクリプトの場合:

    USER@MACHINE:~$ Sudo -u USER /usr/local/bin/a2dp.py 00:22:37:3D:DA:50
    Connection MADE
    Device MAC: 00:22:37:3D:DA:50
    Command: pacmd list-sinks failed with status: 1
    stderr: No PulseAudio daemon running, or not running as session daemon.
    
    Exiting bluetoothctl
    

動作しないもの:

  1. 上記のように、またはRUN+=部分として以下の行のいずれかを使用してスクリプトを実行します。

    /usr/bin/Sudo -u USER /usr/bin/python3 /home/USER/.local/bin/a2dp.py 00:22:37:3D:DA:50
    /usr/bin/Sudo -u USER /home/USER/.local/bin/a2dp.py 00:22:37:3D:DA:50
    /usr/bin/python3.5 /usr/local/bin/a2dp.py 00:22:37:3D:DA:50
    ENV{DISPLAY}=":0" RUN+="/usr/local/bin/a2dp.py 00:22:37:3D:DA:50"
    

    変更されたスクリプトでも機能しません。

    ENV{DISPLAY}=":0" ENV{Pulse_RUNTIME_PATH}="/run/user/1000/Pulse/" RUN+="Sudo -u USER /home/USER/.local/bin/a2dp_2.py 00:22:37:3D:DA:50"
    

詳細情報:udevadmは、ヘッドセットへの接続時の出力を監視します:

KERNEL[104388.664737] add      /devices/pci0000:00/0000:00:14.0/usb3/3-7/3-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
UDEV  [104388.667185] add      /devices/pci0000:00/0000:00:14.0/usb3/3-7/3-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
KERNEL[104390.848157] add      /devices/virtual/input/input46 (input)
UDEV  [104390.849150] add      /devices/virtual/input/input46 (input)
KERNEL[104390.849471] add      /devices/virtual/input/input46/event17 (input)
UDEV  [104390.864692] add      /devices/virtual/input/input46/event17 (input)
5
hife

私の作業ソリューション

  1. pacmdのすべてのインスタンスをpactlに置き換えてa2dp.pyを変更し、pacmd list-sinkspactl list sinksに調整します(この場合、/usr/local/bin/a2dp_2.shとして保存します)。

  2. ラッパースクリプトを作成する/usr/local/bin/a2dp-wrapper.sh

    #!/bin/bash
    
    MAC=$1
    MACMOD=$(echo $MAC | sed 's/:/_/g')
    
    PID=$(pgrep pulseaudio)
    USER=$(grep -z USER= /proc/$PID/environ | sed 's/.*=//')
    
    export DISPLAY=:0
    export XAUTHORITY=/home/$USER/.Xauthority
    
    if pactl list sinks short | grep "bluez_sink\.$MACMOD.*SUSPENDED" 
        then
        Sudo -u $USER /usr/local/bin/a2dp_2.py $MAC
    fi
    
  3. 次の行を/etc/udev/rules.d/80-bt-headset.rulesに追加します。

    ACTION=="add", SUBSYSTEM=="input" ATTR{name}=="00:22:37:3D:DA:50" RUN+="/usr/local/bin/a2dp-wrapper.sh $attr{name}"
    

このラッパースクリプトは、次のことを実現します。

  1. Pulseaudioの実行中のインスタンスを所有している$USERを見つけ、pactlが機能するために必要な環境変数DISPLAY=:0およびXAUTHORITY=/home/$USER/.Xauthorityを設定します。これにより、マシン上のすべてのユーザーに対して機能するはずです。 (複数のユーザーが同時にログインした場合の効果はテストしていません。)

  2. 対応するシンクが中断されているかどうかを確認してから、a2dp_2.pyを実行します。これは、デバイスを再接続してルールをトリガーするa2dp_2.pyによって引き起こされる無限ループを防ぐために必要です。

  3. それは、a2dp_2.pyを$ USERとして実行します。ルートとして実行した場合、a2dp_2.pyは、ルート権限なしではアクセスできないパルスオーディオ、したがってオーディオ設定を残します。

代替手段:dbus loop/fixed package

  1. Dbusループを使用する代替ソリューションは、 sript開発者のページ にあります。

  2. 元のバグの修正が利用可能になりました hereppa:ubuntu-audio-dev/Pulse-testingを追加して利用可能なパッケージを更新することで簡単にインストールできます。

ヒント:デバイスのMACアドレスを見つける

厳密には元の問題の一部ではありませんが、これは将来の参照に役立つ場合があります。デバイスのMACアドレスを見つける方法は多数あります。以下は、udevルールに最も役立つと思うものです。

  1. udevadm monitorを実行してデバイスを接続し、デバイスのパスを見つけます。出力は次のようになります。

    USER@MACHINE:~$ udevadm monitor
    monitor will print the received events for:
    UDEV - the event which udev sends out after rule processing
    KERNEL - the kernel uevent
    
    KERNEL[123043.617276] add      /devices/pci0000:00/0000:00:14.0/usb3/3-7/3-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
    UDEV  [123043.647291] add      /devices/pci0000:00/0000:00:14.0/usb3/3-7/3-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
    KERNEL[123044.153776] add      /devices/virtual/input/input68 (input)
    KERNEL[123044.153911] add      /devices/virtual/input/input68/event17 (input)
    UDEV  [123044.193415] add      /devices/virtual/input/input68 (input)
    UDEV  [123044.213213] add      /devices/virtual/input/input68/event17 (input)
    

    Ctrl+Cでモニターを停止します。 3つのデバイスパスが見つかりました。関連するのは/devices/virtual/input/input68です。

  2. 取得したパスをudevadm infoに差し込みます:

    USER@MACHINE:~$ udevadm info -a -p /devices/virtual/input/input68
    
    Udevadm info starts with the device specified by the devpath and then
    walks up the chain of parent devices. It prints for every device
    found, all possible attributes in the udev rules key format.
    A rule to match, can be composed by the attributes of the device
    and the attributes from one single parent device.
    
      looking at device '/devices/virtual/input/input68':
        KERNEL=="input68"
        SUBSYSTEM=="input"
        DRIVER==""
        ATTR{name}=="00:22:37:3D:DA:50"
        ATTR{phys}==""
        ATTR{properties}=="0"
        ATTR{uniq}==""
    

    MACアドレスは00:22:37:3D:DA:50であり、ATTR{name}として保存されていることもわかります。

出力が完全に異なって見える場合でも、これらの2つのコマンドは、udevルールに関連する条件を探すための良い出発点になります。

実験:任意のBluetoothオーディオデバイスをキャッチする

ルール:

ACTION=="add", SUBSYSTEM=="input" ATTR{name}=="??:??:??:??:??:??" RUN+="/usr/local/bin/a2dp-wrapper.sh $attr{name}"

mACアドレスのように見える名前属性を持つ入力デバイスに対してトリガーされます。ラッパースクリプトの条件は、意図しないアクションが行われないことを確認する必要があります。

これをテストするためのBluetoothオーディオデバイスは他にありませんが、いくつかの潜在的な問題があります。

  1. これは、name属性にMACアドレスを含む入力デバイスとして認識されるbluetoothデバイスでのみ機能します。すべてのデバイスがそのように認識されるとは限りません。

  2. このソリューションは、入力デバイスに対してルールがトリガーされるため、あまりエレガントではありません。ただし、Bluetoothオーディオデバイスを識別するための明確なインジケーターを見つけることができませんでした。 (上記のように、入力デバイスにはそれ以上の属性はなく、bluetoothデバイスにはオーディオデバイスであることの表示はなく、MACアドレスも含まれていません。おそらくACPIの方が良いでしょう。)

  3. すべてのBluetoothオーディオデバイスを同じように扱いたくない場合があります:ヘッドセットにHSPプロトコルを使用したい場合や、ハウスメイトのスピーカーに自動的に切り替えたくない場合があります。利用できます。そのような場合、おそらく各デバイスに個別のルールを設定することが望ましいでしょう。

詳細については、この投稿を更新し続けます。

3
hife