systemd 无法运行某些 bash 脚本

systemd 无法运行某些 bash 脚本

(5 月 16 日更新了更多信息,请参阅帖子末尾的 journalctl 消息)

我创建了一个 systemd 计时器和服务,目的是运行一些 bash 脚本。具体来说,我的目标是在给定时间安装外部硬盘,然后安装 veracrypt 卷,以便运行一些异地备份操作。

每个脚本在我自己的管理员用户运行时都能正常工作,例如

sudo /path/to/script.sh

但是,在 systemd 服务运行时,有些脚本可以运行,有些脚本会失败。即 mount 脚本失败,但 unmount 脚本可以成功运行。

我非常确定这要么是权限问题,要么是用户身份运行问题……但我对 systemd 还不熟悉,似乎无法找到原因。我宁愿避免使用 systemctl --user 机制,因为它依赖于一种我不熟悉的特殊“linger”类型……但如果这是唯一的解决方案,我会接受它。

该功能的高级视图是这样的......

mountup.timer --> mountup.service --> mountup.sh --> mountusb.sh

反向操作也有类似的工作流程

这是代码...

/etc/systemd.system/mountup.timer

[Unit]
Description=run the mountup.service on a given schedule

[Timer]
Unit=mountup.service
OnCalendar=*-*-* *:00,30:00
#this means any day, month, year any hour... each 00 and 30 minute
Persistent=true

[Install]
WantedBy=timers.target

/etc/systemd/system/mountup.service

[Unit]
Description = Runs the mountup.sh script

[Service]
Type = simple
User = adminuseraccount
ExecStartPre = /bin/bash -c 'echo "systemctl says...mountup service triggered at $(date)"  >> /usr/local/bin/mountlog.txt'
ExecStart = /usr/local/bin/mountup.sh

/usr/local/bin/mountup.sh

#! /bin/bash

# the fancy function below pipes the echo messages through a function that preprends the timestamp, then sends the output to the logfile

logit() {
    while read
    do
        printf "%(%Y-%m-%d %T)T %s\n" -1 "$REPLY"  >> /usr/local/bin/mountlog.txt
    done
}


#the line below redirects standard output to logfile, along with standard error to the same, 
#after routing them through the fancy function above
exec 3>&1 1>> >(logit) 2>&1

echo "mountup.sh says ... starting mountusb.sh..." &&
/usr/local/bin/mountusb.sh && 
echo "mountup.sh says ... mountusb.sh has been run" &&

/usr/local/bin/mountusb.sh

#! /bin/bash
usbuuid=9743y934y943

mount --uuid $usbuuid  /mnt/targetlocation

非常感谢,我断断续续地这样做了大约 2 周,现在终于到了放弃并了解我做错什么的时候了。

编辑:来自sudo journalctlmountup.service 尝试的相关输出......

Starting Runs the mountup.sh script...
mountup.service: Control process exited, code=exited, status=1/FAILURE
mountup.service: Failed with result 'exit-code'.
Failed to start Runs the mountup.sh script.

sudo journalctl与 mountdown.service 尝试相关的输出...

Starting Runs the mountdown.sh script...
Started Runs the mountdown.sh script.
root : PWD=/ ; USER=root ; COMMAND=/usr/bin/umount /mnt/targetlocation
pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
pam_unix(sudo:session): session closed for user root
mountdown.service: Main process exited, code=exited, status=32/n/a
mountdown.service: Failed with result 'exit-code'.

据我所知,umount 命令的退出代码 32 仅表示卸载卷失败,仅此而已。

答案1

首先,您应该设置一个一次性服务,因为当它完成后您的脚本就会退出:

[Unit]
Description = Runs the mountup.sh script

[Service]
Type = oneshot
User = adminuseraccount
ExecStart = /usr/local/bin/mountup.sh
RemainAfterExit=true
StandardOutput=journal
StandardError=journal

然后你就可以用journalctl -u mountup.service

有了日志,我还会放弃所有文件句柄的重定向。另外,您/usr/local/bin/mountlog.txt需要 root 权限才能写入。通常,在那里写入是不好的做法。但同样,我根本不会使用重定向。

而且,由于您使用 链接命令&&,因此您可以考虑执行set -e。这样,脚本会在出错时中止。这有一些注意事项(例如,错误构造的 if-greps 可能会中止您的程序),但对于您来说,这看起来是一个不错的选择。

这不是解决方案本身,因为我们没有看到错误,但它应该可以帮助您。

另外,我想我会把所有东西都放在一个脚本中。在其中放入一个“退出陷阱”以便sync; umount /foo/bar之后执行,这样你就可以确保当它完成时,至少已经刷新了文件系统缓冲区并且驱动器已卸载。这样就可以安全地拔下电源。我倾向于在这些情况下调用的原因sync也是以防万一umount失败。

关于卸载失败:如果这是您的问题/一个问题,您可能保持该位置打开,cd例如,如果您进入它。

相关内容