bash脚本在终端中运行,但不会使用systemd自动启动

问题描述 投票:1回答:1

[我试图在启动时作为系统服务运行bash脚本,我正在使用Raspbian Buster Lite在Raspberry Pi 4上执行此操作。

如果我手动运行bash脚本./hls.sh,我将能够执行bash脚本;如果我执行sudo service tv start,我也能够运行该服务,但是tv.service似乎无法执行bash脚本。 hls.sh启动时。我确实为服务和bash文件都授予了权限chmod 777

这里的任何帮助将不胜感激,我已经尝试解决这个问题一个月了。

Bash脚本

#!/bin/bash
/usr/bin/ffmpeg -reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2 -y -nostdin \
-hide_banner -loglevel fatal \
-i http://10.0.0.11:9981/stream/channelnumber/2 \
-vcodec copy -acodec copy -scodec copy -g 60 \
-fflags +genpts -user_agent HLS_delayer \
-metadata service_provider="TimeShift" \
-metadata service_name="TV 1" \
-f hls -hls_flags delete_segments \
-hls_time 60 \
-hls_list_size 480 \
-hls_wrap 481 \
-hls_segment_filename /home/pi/hls/1_%03d.ts /home/pi/hls/1_hls.m3u8

服务

[Unit]
Description=Timeshift TV
After=tvheadend.service
PartOf=tvheadend.service
Restart=always

[Service]
ExecStartPre=/bin/mkdir -p /home/pi/hls/
ExecStart=/home/pi/hls.sh 103 &
ExecStop=/bin/rm -rf /home/pi/hls

[Install]
WantedBy=default.target

重新启动后,通过systemctl status检查状态

● tv.service - Timeshift TV
   Loaded: loaded (/etc/systemd/system/tv.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Mon 2020-05-18 05:36:40 BST; 45s ago
  Process: 465 ExecStartPre=/bin/mkdir -p -m777 /home/pi/hls/ (code=exited, status=0/SUCCESS)
  Process: 472 ExecStart=/home/pi/hls.sh 103 & (code=exited, status=1/FAILURE)
 Main PID: 472 (code=exited, status=1/FAILURE)

May 18 05:36:39 tv3 systemd[1]: Starting Timeshift TV...
May 18 05:36:39 tv3 systemd[1]: Started Timeshift TV.
May 18 05:36:40 tv3 systemd[1]: tv.service: Main process exited, code=exited, status=1/FAILURE
May 18 05:36:40 tv3 systemd[1]: tv.service: Failed with result 'exit-code'.
linux bash raspberry-pi raspbian systemd
1个回答
1
投票

此服务文件存在一些问题。我将在下面解决这些问题,然后显示最终解决方案。

  1. [避免将系统级服务放在/home目录下。虽然可能有效,但不建议这样做。这样做可能会导致许多范围外的问题。而是考虑将脚本放置在/opt/srv/usr/local下。
    • 当以这种大方式移动文件时,请确保在移动目录后在该目录上运行restorecon -r。这样可确保SELinux上下文被重置为其正确的值,而不是将新上下文与旧上下文混合。当SELinux处于强制模式时,这可以帮助解决权限被拒绝的错误。
  2. Restart=指令位于Restart=之下,而不是[Service]之下,因此应将其移至该位置或完全删除。因为systemd有时是可以原谅的,所以它可能是无害的,但是[Unit]是定义该指令的指令,而不是systemd.service
  3. systemd.unit更改为末尾没有ExecStart=。只需保留它,然后将其作为普通脚本运行即可。如果配置正确,Systemd将处理其余部分。
  4. ExecStart=更改为&。这将使systemd能够执行其正常的停止行为,即在被要求停止服务时向脚本发送ExecStop=。停止完成后(优雅地或强制性地),ExecStop=将运行。由于似乎在脚本运行后您正在使用它进行清理,因此应该进行更改。如果按原样保留,systemd将删除目录,然后等待脚本退出,由于未告知脚本,脚本将永远不会执行此操作,因此systemd将等待超时时间,然后再要求内核ExecStopPost=脚本。绝对不理想。
  5. ExecStopPost=下的一些额外指令将解决有关此服务应如何行为的一些假设。
    • SIGTERM —以便定义而不是假定。如果保留为默认值,它将成为ExecStopPost=的主目录,如果保留为默认值,则为SIGKILL。而是将其设置为脚本的位置,如果为[Service],则设置为WorkingDirectory=
    • WorkingDirectory=-这样脚本不会以默认用户User身份运行。我建议/root或您希望管理/tmp执行的任何用户。这样可以防止在脚本运行时为其授予root特权,而PrivateTmp=true则不需要。
    • User= —可以说这是最重要的,因为脚本是一次性运行的,成功后将退出;它不会守护到后台并继续以默认的User=服务运行。应该将其设置为root,以便systemd知道。它将退出的脚本视为服务成功运行,然后继续运行。
    • nobody-在大多数情况下,应启用此功能。仅在极少数情况下应禁用它。默认行为是禁用的。启用后,脚本尝试存储在ffmpeg中的所有内容实际上将透明地存储在名为ffmpeg的命名空间目录中,以防止与Type=中的其他文件发生任何冲突。如果使用此选项,我将更改Type=写入simple,而不是管理脚本旁边的目录,从而使您可以完全删除oneshotPrivateTmp=
  6. 请确保PrivateTmp=/tmp带有/tmp/systemd-private-xxxx-servicename.service-xxxxx/前缀,这样,它们将以/tmp的身份运行,而不是所定义的ffmpeg可能不是root;根据您对目录的期望,此操作可能必要也可能不必要。有关更多信息,请参见/tmp
  7. ExecStartPre=更改为ExecStopPost=;更有可能应该为该目标运行该服务,而不是默认启动任何目标。
  8. 您可能不应该编写脚本ExecStartPre=,我会改用适度的ExecStopPost=。它只需要执行位(+)。
  9. 因此,没有其他理由,这是最终解决方案:

目录结构:

root
User=

Shell脚本:

systemd.service Table 1. Special executable prefixes
WantedBy=default.target

服务文件:

multi-user.target
chmod 777

系统状态输出:

chmod 755
© www.soinside.com 2019 - 2024. All rights reserved.