我编写了一个脚本,用于侦听来自 FIFO 的命令并收集几个文件以便在我的树莓派上进行调试,所有这些工作正常直到我决定为其编写一个 systemd 单元文件。 runningsystemctl start crashcollector
将启动脚本,但它永远不会从正在运行的管道中读取任何内容,但不会执行任何操作,systemctl stop crashcollector
需要永远停止服务,所以我猜测我的单元文件出了问题,即使我编写了许多工作正常的文件。
bash脚本:
#!/bin/bash
collectCrashReport() {
# teleport to cache dir
cd /mnt/cache
# remove any previous report
rm -rf crash/crashreport_*
# create report directory
directory=crashreport_`cat /etc/hostname`_$(date +%Y%m%d%H%M%S)
mkdir $directory
cd $directory
# snatch all the logs
cp -r /var/log/ .
ps --no-headers -ax > processes.dump
# dump dmesg to file
dmesg > dmesg.dump
# create crash dir
mkdir crash
# zip the whole thing
zip -qr /mnt/cache/crash/"$directory.zip" .
# remove collection dir
rm -rf /mnt/cache/crashreport_*
# done and done
}
# check if already running and kill
PIDFILE=/var/run/crashcollector.pid
# check if already running
if [ -f $PIDFILE ]; then
kill `cat $PIDFILE`
fi
echo $$ > $PIDFILE
cleanup() {
rm -f $PIDFILE
exit 0
}
# trap them signals
trap "cleanup" INT TERM EXIT
that_awesome_pipe="CCPipe"
[ -p $that_awesome_pipe ] || mkfifo $that_awesome_pipe
chmod 766 $that_awesome_pipe
while :; do
if read line; then
case $line in
"collect")
collectCrashReport
;;
*)
log "Received bad command $line, ignoring..."
;;
esac
fi
done <"$that_awesome_pipe"
Systemd单元文件:
[Unit]
Description=Crash report collector
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/crashCollector
ExecStop=/usr/bin/kill -9 `cat /var/run/crashcollector.pid`
KillMode=process
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
不确定我在这里到底缺少什么,删除该if read line
块使一切正常工作。
答案1
那里有很多事情不对劲。
- 不要将
ExecStart
和ExecStop
视为 shell 命令行。他们不是。 systemd 手册确实警告了这一点。命令替换等 Shell 扩展是不是在这些服务单元文件设置中可用。这是不是shell语言。 - 当您开始的地方有实际的服务管理器时,不要创建 PID 文件机制。 PID 文件是一种自 20 世纪 80 年代以来就被破坏的机制,正确的服务管理完全消除了这种需要。你有一个服务经理。 它将确保任何时候最多只有一个服务实例运行。 它将跟踪进程 ID。 它当服务关闭时,将处理向服务进程发送终止信号。
- 不要将基本的服务器端内容放入服务器进程中,例如创建 FIFO 并打开其服务器端。
这样做:
- 创建一个套接字单元与服务单元并排。
- 将 FIFO 的所有显式处理从
crashCollector
. - 用于
ListenFIFO
插座单元。这当然需要绝对路径名。 StandardInput=socket
在服务单位使用。- 让您的
crashcollector
脚本仅从其标准输入读取。 - 将所有 PID 文件从
crashCollector
. - 把所有的信号捕获和
cleanup()
东西从crashCollector
. - 将所有使用 的显式杀戮
ExecStop
以及您尝试使用 执行的后续操作KillMode
从服务单元中取出。 StandardError=journal
在服务单位使用。- 替换
log
为简单echo 1>&2
到标准错误。
进一步阅读
- 乔纳森·德博因·波拉德 (2001)。 设计 Unix 守护程序时要避免的错误。常见答案。
- 伦纳特·珀特林等人系统套接字。 systemd 手册页。 Freedesktop.org。
- 如何让服务从 FIFO 套接字读取
答案2
我将 fifo 移动到 后,一切都修复了/tmp
;不确定会发生什么变化,但现在一切进展顺利。