首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用systemd安装MTP设备

使用systemd安装MTP设备
EN

Unix & Linux用户
提问于 2023-01-29 15:51:50
回答 1查看 345关注 0票数 1

第一次尝试

在规则51-android.rules中,我添加了程序的执行,以防我的手机连接到瘦客户端:

代码语言:javascript
复制
...
# Skip other vendor tests
LABEL="android_usb_rule_match"
RUN+="/etc/udev/scripts/mtp.sh"
...

我的脚本/etc/udev/scripts/mtp.sh,在连接时执行设备安装:

代码语言:javascript
复制
#!/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

P.S.我使用记录日志的构造为echo ...__,因为BusyBox的logger不写入TS上的日志。

我使用了一个日志脚本来查看为什么我的设备没有挂载。或者更确切地说,它被挂载了,过了一段时间就掉了下来,而它在系统中作为一个安装的设备是看不见的。在互联网上搜索时,我发现信息默认运行具有单独的“挂载名称空间”的systemd-udevd.service。

第二次尝试

我在51-android.rules中重写了规则如下:

代码语言:javascript
复制
...
# Skip other vendor tests
LABEL="android_usb_rule_match"
ACTION=="add", PROGRAM="/bin/aft-mtp-mount -p --template=mtp@.service $env{ID_MODEL}_$env{ID_VENDOR}", ENV{SYSTEMD_WANTS}+="%c"
...

/etc/systemd/system/mtp@.service中放置了以下内容:

代码语言:javascript
复制
[Service]
Type=oneshot
ExecStart=/etc/udev/scripts/mtp.sh

因此,我重写了只响应add事件的脚本D30

代码语言:javascript
复制
#!/bin/sh

. /etc/thinstation.env
. $TS_GLOBAL

/bin/aft-mtp-mount /phone

假设在测试期间我自己卸载了目录,而没有脚本,这是合乎逻辑的。因此,电话并不总是在第一次连接上。感觉好像他在几分钟的连接限制上有了某种暂停。最后,我根本不知道问题出在哪里。

第三次尝试

我解决这个问题的整个过程类似于类似的东西,即已在堆栈溢出上可用。我试着从这篇文章中复制出解决方案。

以这种方式更正了51-android.rules脚本:

代码语言:javascript
复制
...
# 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/mtp@.service中放置了以下内容:

代码语言:javascript
复制
[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

代码语言:javascript
复制
#! /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规则并调用phone挂载脚本,这给加载带来了进一步的问题。

我试图提取下载数据,这就是我所看到的:

Systemd服务加载计划

内核日志

我不明白,也许我没有正确地实现所有的东西,或者有一些缺陷。我似乎尝试了不同的选择。可以尝试通过systemd-mount挂载设备,但它不支持MTP协议来挂载它。或者我可以用其他方法来实现它?我没有发现关于这个问题的任何补充资料。我向那些知道的人寻求帮助,因为我已经在论坛上到达了一个死胡同。我已经在GitHub上创建了主题,但到目前为止也没有进展。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2023-01-30 08:53:18

我终于解决了安装问题!我花了三周时间寻找一个更合适的解决方案。

首先,我将这些更改应用于安卓设备51-android.rules /etc/udev/rules.d/51-android.rules的规则脚本:

代码语言:javascript
复制
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"

在这个补丁中,我形成了一个指向附加设备的符号链接(为了更好地理解,我正在从设备的属性中形成一个名称):

代码语言:javascript
复制
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标记(没有它,systemd服务调用对我不起作用),并根据我的模板(下面)/etc/systemd/system/mtp@.service调用服务:

代码语言:javascript
复制
[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

代码语言:javascript
复制
~ # 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),并尝试在那里挂载我的设备。如果成功,它将被安装,如果没有,则触发卸载:

代码语言:javascript
复制
#! /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

因此,我成功地挂载了设备,并在连接到它的设备上启动了操作系统,这也是没有问题的。

MTP装置自动安装演示

如果需要改进,我创建了一个存储库。

票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/733591

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档