systemdを使用したMTPデバイスのマウント

systemdを使用したMTPデバイスのマウント
  • Linux:確立されたシンステーション6.2プロジェクト(systemdから)
  • 仕事:シンクライアントに接続すると、MTPデバイス(Android携帯電話など)を自動的にマウントします。
  • 質問:デバイスの接続中にディストリビューションの読み込み中にエラーが発生したか、デバイスが正しくインストールされていません。
  • インストール中に使用されるソフトウェア: シンプルなmtpfsAndroidファイル転送 - LinuxAndroid-udev-ルール

最初の試み

ルールに51-android.rules、携帯電話をシンクライアントに接続する場合に備えてプログラム実行を追加しました。

...
# Skip other vendor tests
LABEL="android_usb_rule_match"
RUN+="/etc/udev/scripts/mtp.sh"
...

私のスクリプトは、接続する/etc/udev/scripts/mtp.shとデバイスのインストールを実行します。

#!/bin/sh

. /etc/thinstation.env
. $TS_GLOBAL

if [[ $ACTION == "add" ]]; then
    echo "********************* START MOUNT *******************" | systemd-cat -p info -t "mtp"
    /bin/aft-mtp-mount /phone
    grep -oe "/phone" /proc/mounts | systemd-cat -p err -t "mtp"
    ls "/phone/Внутренний общий накопитель" | systemd-cat -p err -t "mtp"
    echo "********************** END MOUNT ********************" | systemd-cat -p info -t "mtp"
elif [[ $ACTION == "remove" ]]; then
    echo "******************** START UNMOUNT ******************" | systemd-cat -p info -t "mtp"
    umount /phone
    echo "********************* END UNMOUNT *******************" | systemd-cat -p info -t "mtp"
fi

PS BusyBoxはTSにログを書き込まないecho ...ため、ロギング構造を使用しています。logger

私のデバイスがマウントされていない理由を確認するために、ロギングスクリプトを使用しました。あるいは、むしろインストールしてから時間が経つにつれて落ちたが、システムにはインストールされたデバイスとは見えなかった。インターネットでグーグルして見つけた情報systemdはデフォルトで別々の「マウントネームスペース」を使用してsystemd-udevd.serviceを実行します。

2回目の試み

ルールを書き直しました51-android.rules次のように:

...
# Skip other vendor tests
LABEL="android_usb_rule_match"
ACTION=="add", PROGRAM="/bin/aft-mtp-mount -p [email protected] $env{ID_MODEL}_$env{ID_VENDOR}", ENV{SYSTEMD_WANTS}+="%c"
...

そして以下を入力してください:/etc/systemd/system/[email protected]

[Service]
Type=oneshot
ExecStart=/etc/udev/scripts/mtp.sh

/etc/udev/scripts/mtp.shそのため、イベントにのみ応答するようにスクリプトを書き直しましたadd

#!/bin/sh

. /etc/thinstation.env
. $TS_GLOBAL

/bin/aft-mtp-mount /phone

テスト中にスクリプトを使用せずに直接ディレクトリをアンマウントしたと仮定するのは妥当です。その結果、電話は常に最初の接続に失敗します。数分の接続制限に何らかのタイムアウトがあるように感じます。結局、私は問題が何であるかを知りませんでした。

3回目の試み

この問題を解決するための全体的なプロセスは次のようになりました。stackoverflowですでに利用可能。この投稿でソリューションを再現しようとしています。

修正済み51-android.rulesスクリプトは次のとおりです。

...
# Skip other vendor tests
LABEL="android_usb_rule_match"
ACTION=="add", RUN+="/bin/systemctl start mtp@$env{ID_VENDOR}_$env{ID_MODEL}_$env{ID_REVISION}.service"
ACTION=="remove", RUN+="/bin/systemctl stop mtp@$env{ID_VENDOR}_$env{ID_MODEL}_$env{ID_REVISION}.service"
...

そして以下を入力してください:/etc/systemd/system/[email protected]

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/etc/udev/scripts/mtp.sh add %I
ExecStop=/etc/udev/scripts/mtp.sh remove %I

そして実行スクリプトをマウントします/etc/udev/scripts/mtp.sh

#! /bin/sh

. /etc/thinstation.env
. $TS_GLOBAL

ACTION=$1
DEVICE_NAME=$2
MOUNT=/bin/aft-mtp-mount

CURRENT_DEVICE_MOUNT_PATH=$BASE_MOUNT_PATH/$USB_MOUNT_DIR/$DEVICE_NAME

_logger() {
    echo "$2" | systemd-cat -p $1 -t "mtp"
}

_mounted() {
    if [ -n "$(grep -oe "$1" /proc/mounts)" ]; then
        return 0
    else
        return 1
    fi
}

_mount() {
    _logger info "mount $DEVICE_NAME"
    if [ -d $CURRENT_DEVICE_MOUNT_PATH ] && _mounted $CURRENT_DEVICE_MOUNT_PATH; then
        _logger warning "$DEVICE_NAME already mounted"
        exit 1
    fi
    if [ ! -d $CURRENT_DEVICE_MOUNT_PATH ]; then
        mkdir $CURRENT_DEVICE_MOUNT_PATH
        if is_enabled "$USB_STORAGE_SYNC" && [ ! -n "$(echo $USB_MOUNT_OPTIONS | grep -e sync)" ]; then
            USB_MOUNT_OPTIONS=$USB_MOUNT_OPTIONS,sync
        fi
        $MOUNT -o $USB_MOUNT_OPTIONS $CURRENT_DEVICE_MOUNT_PATH
        if _mounted $CURRENT_DEVICE_MOUNT_PATH && [ "$(ls -A $CURRENT_DEVICE_MOUNT_PATH)" ]; then
            _logger info "mounted $DEVICE_NAME in $CURRENT_DEVICE_MOUNT_PATH"
        else
            _logger warning "$DEVICE_NAME failed to mount"
            _umount
            exit 2
        fi
    else
        _logger warning "$CURRENT_DEVICE_MOUNT_PATH already exists"
        exit 3
    fi
}

_umount() {
    _logger info "unmount $DEVICE_NAME"
    if [[ -d $CURRENT_DEVICE_MOUNT_PATH ]]; then
        while _mounted $CURRENT_DEVICE_MOUNT_PATH; do
            umount $CURRENT_DEVICE_MOUNT_PATH
        done
        _logger info "unmounted $DEVICE_NAME in $CURRENT_DEVICE_MOUNT_PATH"
        rm -r $CURRENT_DEVICE_MOUNT_PATH
    else
        _logger warning "$DEVICE_NAME was not mounted"
    fi
}

if [ $ACTION == "add" ]; then
    _mount
elif [ $ACTION == "remove" ]; then
    _umount
fi

exit 0

今、すべてが期待どおりに動作します!しかし、ニュアンスがあります。

起動中に電話機が最初にシンクライアントに接続された場合、システムは開かれません。起動中にダイヤルアップが切断されると、シンクライアントのロードに問題はなく、接続するとインストールが正常に機能します。

シンクライアントのダウンロード中にsystemd-udevd読み込もうとしたようです。51-android.rulesルールを適用し、モバイルインストールスクリプトを呼び出すため、追加のロードの問題が発生します。

ダウンロードデータを抽出してみたところ、次のようになります。

システム化されたサービスロードスケジュール

カーネルログ

わかりません。実装がすべて間違っているか、問題がある可能性があります。さまざまなオプションを試しているようです。デバイスのマウントを試みることができますが、systemd-mountMTPプロトコルを介したマウントはサポートされていません。それとも別の方法で達成できますか?このトピックに関するその他の情報が見つかりませんでした。行き詰まった路地に至ったので、ご存知の方にお願いします。アーチ法廷。テーマを作ってみましたGitHubしかし、現在まで何の進展もありません。

答え1

ついにインストールの問題を修正しました!私はより適切な解決策を見つけるために3週間を過ごしました。

まず、Androidデバイスのルールスクリプトにこれらの変更を適用します。51-android.rules /etc/udev/rules.d/51-android.rules:

diff --git a/51-android.rules b/51-android.rules
index d75ddb3..65f235c 100644
--- a/51-android.rules
+++ b/51-android.rules
@@ -9,7 +9,7 @@
 # https://github.com/M0Rf30/android-udev-rules
 
 # Skip testing for android devices if device is not add, or usb
-ACTION!="add", ACTION!="bind", GOTO="android_usb_rules_end"
+ENV{DEVTYPE}!="usb_device", GOTO="android_usb_rules_end"
 SUBSYSTEM!="usb", GOTO="android_usb_rules_end"
 
 # Skip testing for unexpected devices like hubs, controllers or printers
@@ -820,13 +820,16 @@ GOTO="android_usb_rule_match"
 LABEL="not_ZTE"
 
 # ZUK
-ATTR{idVendor}=="2b4c", ENV{adb_user}="yes"
+ATTR{idVendor}=="2b4c", ENV{adb_user}="yes", GOTO="android_usb_rule_match"
 
 # Verifone
-ATTR{idVendor}=="11ca", ENV{adb_user}="yes"
+ATTR{idVendor}=="11ca", ENV{adb_user}="yes", GOTO="android_usb_rule_match"
+
+GOTO="android_usb_rules_end"
 
 # Skip other vendor tests
 LABEL="android_usb_rule_match"
+TAG+="systemd", SYMLINK+="$env{ID_VENDOR}_$env{ID_MODEL}_$env{ID_REVISION}", ENV{SYSTEMD_WANTS}+="mtp@$env{ID_VENDOR}_$env{ID_MODEL}_$env{ID_REVISION}.service"
 
 # Symlink shortcuts to reduce code in tests above
 ENV{adb_adbfast}=="yes", ENV{adb_adb}="yes", ENV{adb_fast}="yes"

このパッチでは、接続されたデバイスへのシンボリックリンクを形成しました(わかりやすくするため、端末のプロパティに基づいて名前をつけています。):

TAG+="systemd", SYMLINK+="$env{ID_VENDOR}_$env{ID_MODEL}_$env{ID_REVISION}", ENV{SYSTEMD_WANTS}+="mtp@$env{ID_VENDOR}_$env{ID_MODEL}_$env{ID_REVISION}.service"

私もsystemdラベル(それがなければ、システムサービスコールは機能しません。)私のテンプレート(下)に基づいてサービスを呼び出します。/etc/systemd/system/[email protected]

[Unit]
Description=Mounting MTP devices
BindsTo=dev-%i.device
After=dev-%i.device

[Service]
Type=oneshot
RemainAfterExit=true
TimeoutStartSec=30
ExecStart=/etc/udev/scripts/mtp.sh add %I
ExecStop=/etc/udev/scripts/mtp.sh remove %I

[Install]
WantedBy=dev-%i.device

システムでは、私のデバイスは次のようになりますdev-NAME.device

~ # systemctl --all --full -t device | grep Swift
dev-android.device                                               loaded active plugged Swift_2_Plus                                                                         
dev-android4.device                                              loaded active plugged Swift_2_Plus                                                                         
dev-bus-usb-001-007.device                                       loaded active plugged Swift_2_Plus                                                                         
dev-Wileyfox_Swift_2_Plus_0318.device                            loaded active plugged Swift_2_Plus                                                                         
sys-devices-pci0000:00-0000:00:15.0-usb1-1\x2d4.device           loaded active plugged Swift_2_Plus

呼び出されたハンドラスクリプトからsystemdディレクトリ(私の場合)を作成しWileyfox_Swift_2_Plus_0318、そこにデバイスをマウントしようとしています。成功した場合はマウントし、失敗した場合はマウント解除をトリガーします。

#! /bin/sh

. /etc/thinstation.env
. $TS_GLOBAL

ACTION=$1
DEVICE_NAME=$2
MOUNT=/bin/aft-mtp-mount

CURRENT_DEVICE_MOUNT_PATH=$BASE_MOUNT_PATH/$USB_MOUNT_DIR/$DEVICE_NAME

_logger() {
    echo "$2" | systemd-cat -p $1 -t "mtp"
}

_mounted() {
    if [ -n "$(grep -oe "$1" /proc/mounts)" ]; then
        return 0
    else
        return 1
    fi
}

_mount() {
    _logger info "mount $DEVICE_NAME"
    if [ -d $CURRENT_DEVICE_MOUNT_PATH ] && _mounted $CURRENT_DEVICE_MOUNT_PATH; then
        _logger warning "$DEVICE_NAME already mounted"
        exit 1
    fi
    if [ ! -d $CURRENT_DEVICE_MOUNT_PATH ]; then
        mkdir $CURRENT_DEVICE_MOUNT_PATH
        if is_enabled "$USB_STORAGE_SYNC" && [ ! -n "$(echo $USB_MOUNT_OPTIONS | grep -e sync)" ]; then
            USB_MOUNT_OPTIONS=$USB_MOUNT_OPTIONS,sync
        fi
        $MOUNT -o $USB_MOUNT_OPTIONS $CURRENT_DEVICE_MOUNT_PATH
        if _mounted $CURRENT_DEVICE_MOUNT_PATH && [ "$(ls -A $CURRENT_DEVICE_MOUNT_PATH)" ]; then
            _logger info "mounted $DEVICE_NAME in $CURRENT_DEVICE_MOUNT_PATH"
        else
            _logger warning "$DEVICE_NAME failed to mount"
            _umount
            exit 2
        fi
    else
        _logger warning "$CURRENT_DEVICE_MOUNT_PATH already exists"
        exit 3
    fi
}

_umount() {
    _logger info "unmount $DEVICE_NAME"
    if [[ -d $CURRENT_DEVICE_MOUNT_PATH ]]; then
        while _mounted $CURRENT_DEVICE_MOUNT_PATH; do
            umount $CURRENT_DEVICE_MOUNT_PATH
        done
        _logger info "unmounted $DEVICE_NAME in $CURRENT_DEVICE_MOUNT_PATH"
        rm -r $CURRENT_DEVICE_MOUNT_PATH
    else
        _logger warning "$DEVICE_NAME was not mounted"
    fi
}

if [ $ACTION == "add" ]; then
    _mount
elif [ $ACTION == "remove" ]; then
    _umount
fi

exit 0

そのため、デバイスを正常にインストールし、問題なくデバイスに接続されているOSを起動しました。

MTP機器の自動設置デモンストレーション

改善が必要な場合はリポジトリを作成しました。

関連情報