- Linux: 建立在Thinstation 6.2项目(在 systemd 上)
- 任务:连接瘦客户端时自动挂载MTP设备(即Android手机)
- 问题:连接设备时加载发行版时出错或设备安装不正确。
- 安装时使用的软件: 简单的mtpfs,android-文件传输-linux,android-udev-规则
第一次尝试
规则中51-android.规则,我添加了程序的执行,以防我将手机连接到瘦客户端:
...
# 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 我使用记录日志的结构为echo ...
,因为logger
BusyBox 不会写入 TS 上的日志。
我使用日志脚本来查看为什么我的设备未安装。或者更确切地说,它已安装并在一段时间后脱落,而它在系统中作为已安装设备不可见。在互联网上谷歌搜索,我发现信息systemd 默认情况下使用单独的“挂载命名空间”运行 systemd-udevd.service 。
第二次尝试
我重写了规则51-android.规则如下:
...
# 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
可以合理地假设,在测试期间,我自己卸载了该目录,而没有使用脚本。结果,手机第一次总是连接不上。感觉就像几分钟的连接限制有某种超时。到最后我也没弄清楚问题出在哪里。
第三次尝试
我解决这个问题的整个过程类似于类似的事情已经在 stackoverflow 上可用。我尝试重现这篇文章中的解决方案。
更正了51-android.规则脚本是这样的:
...
# 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.规则规则并调用手机安装脚本,这会产生进一步的加载问题。
我尝试提取下载数据,这就是我看到的:
我不明白,也许我所有的实现都不正确,或者有一些陷阱。看来我试图尝试不同的选择。可以尝试通过 挂载设备systemd-mount
,但不支持 MTP 协议挂载。或者我可以通过其他方式实现它?我没有找到有关此主题的任何其他信息。我向知道的人求助,因为我已经走到了死胡同拱论坛。我已经创建了主题GitHub,但到目前为止也没有任何进展。
答案1
我终于解决了安装问题!我花了三个星期寻找更合适的解决方案。
首先,我将这些更改应用于 Android 设备的规则脚本51-android.规则 /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
标签(没有它,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
因此,我成功地安装了该设备,并通过连接到该设备的操作系统启动操作系统也不会出现任何问题。