1. 功能概述 start-stop-daemon 是一个用于管理系统守护进程的工具,主要功能包括:
启动守护进程 :创建并运行后台服务程序。
停止守护进程 :终止正在运行的服务程序。
检查进程状态 :验证服务是否在运行。
发送信号 :向守护进程发送特定的控制信号。 它主要用于 Unix/Linux 系统的 init 脚本和服务管理,确保同一程序只运行一个实例。
2. 工作原理 2.1. 核心工作机制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 启动流程: 1. 检查是否已有实例运行 - 通过 PID 文件检查 -通过进程名称匹配 -通过/proc文件系统检查 2. 决定操作: -如果实例存在且 --oknodo 未设置 → 退出 -如果没有实例 → 启动新进程 3. 进程启动: -fork() 新进程 -可选 chroot/chdir -设置用户/组权限 -重定向标准 I/O -exec() 目标程序
2.2. 进程检测机制 1 2 3 4 5 6 检测优先级: 1. --pidfile:最精确,读取文件中的 PID2. --exec:匹配可执行文件路径3. --name:匹配进程名称4. --user:结合以上条件过滤
3. 详细用法 3.1. 基本语法 1 2 3 start-stop-daemon [选项] --start -- 执行命令 [参数] start-stop-daemon [选项] --stop start-stop-daemon [选项] --status
3.2. 启动选项
选项
描述
示例
--start
启动进程
--start
--stop
停止进程
--stop
--status
检查状态
--status
--pidfile
指定 PID 文件
--pidfile /var/run/nginx.pid
--exec
指定可执行文件
--exec /usr/bin/nginx
--name
指定进程名
--name nginx
--user
指定运行用户
--user www - data
--chdir
指定工作目录
--chdir /var/www
--chroot
改变根目录
--chroot /jail
--make-pidfile
创建 PID 文件
--make-pidfile
--background
后台运行
--background
--nicelevel
设置优先级
--nicelevel - 5
3.3. 停止选项
选项
描述
示例
--signal
指定停止信号
--signal TERM
--retry
重试策略
--retry TERM/5/KILL
--oknodo
无操作也返回成功
--oknodo
--quiet
安静模式
--quiet
4. 实战示例 4.1. 启动服务示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 start-stop-daemon --start \ --pidfile /var/run/nginx.pid \ --exec /usr/sbin/nginx \ -- - c /etc/nginx/nginx.conf start-stop-daemon --start \ --pidfile /var/run/myservice.pid \ --user nobody \ --group nogroup \ --chdir /var/lib/service \ --background \ --make-pidfile \ --exec /usr/bin/myservice start-stop-daemon --start \ --pidfile /var/run/myapp.pid \ --user appuser \ --chdir /opt/app \ --background \ --make-pidfile \ --exec /usr/bin/java -- \ - jar myapp.jar
4.2. 停止服务示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 start-stop-daemon --stop \ --pidfile /var/run/nginx.pid start-stop-daemon --stop \ --pidfile /var/run/mysql.pid \ --retry TERM/30/KILL/5 \ --oknodo start-stop-daemon --stop \ --name sshd \ --signal HUP
4.3. 完整 init 脚本示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #!/bin/sh NAME = myservice DAEMON = /usr/bin/$NAME PIDFILE = /var/run/$NAME .pid USER = nobody start () { echo "Starting $NAME ..." start-stop-daemon --start \ --pidfile $PIDFILE \ --user $USER \ --chdir /var/lib/$NAME \ --background \ --make-pidfile \ --exec $DAEMON echo "OK" } stop () { echo "Stopping $NAME ..." start-stop-daemon --stop \ --pidfile $PIDFILE \ --retry TERM/20/KILL/5 \ --oknodo rm - f $PIDFILE echo "OK" } status () { start-stop-daemon --status --pidfile $PIDFILE case "$?" in 0) echo "$NAME is running" ;; 3) echo "$NAME is not running" ;; 4) echo "Unable to determine status" ;; esac } case "$1 " in start) start ;; stop) stop ;; restart) stop; sleep 2; start ;; status) status ;; *) echo "Usage: $0 {start|stop|restart|status}" ;; esac
5. 高级用法 5.1. 信号处理策略 1 2 3 4 5 6 7 8 9 --retry TERM/30/KILL/5 --retry 10 --retry TERM/10
5.2. 复杂的进程匹配 1 2 3 4 5 6 7 8 9 10 11 12 start-stop-daemon --stop \ --user www - data \ --exec /usr/bin/php \ --name "php - fpm*" \ --pidfile /var/run/php - fpm.pid start-stop-daemon --stop \ --user mysql \ --exec /usr/sbin/mysqld \ --test
5.3. 监控和日志 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 start-stop-daemon --start \ --background \ --make-pidfile \ --pidfile /var/run/app.pid \ --exec /usr/bin/app \ -- \ --log - file /var/log/app.log 2>&1 if start-stop-daemon --status --pidfile /var/run/service.pid; then echo "Service is running" else echo "Service is not running" start-stop-daemon --start ... fi
6. 退出码详解 start-stop-daemon 的退出码设计用于脚本编程,不会在终端输出信息 ,而是通过返回值传递状态。不同命令的退出码含义有所不同,下面详细说明。
6.1. 通用退出码(所有命令都可能返回)
退出码
含义
说明
0
成功
操作成功完成
1
一般性错误
无法确定具体错误类型
2
无效选项
命令行参数语法错误或不支持
3
权限不足
没有足够权限执行操作(如无法读取pidfile)
4
资源问题
如内存不足、进程表满等
5
配置错误
配置文件或环境问题
6
程序未安装
指定的可执行文件不存在
6.2. --start 命令的退出码
退出码
含义
详细说明
0
启动成功
进程已启动(或已在运行且未指定 --oknodo 时的默认行为)
1
启动失败
一般性启动失败(如fork失败、exec失败)
2
已在运行
仅在指定了 --oknodo 时 :进程已在运行且没有采取任何操作
3
权限不足
无法以指定用户身份运行
4
资源不足
系统资源不足无法启动新进程
5
pidfile错误
无法创建pidfile或pidfile已存在且属于其他进程(且未指定 --oknodo)
关键细节:
如果不加 --oknodo,当进程已在运行时,--start 默认仍然返回0 (表示”操作成功”——因为进程已在运行,符合期望)
如果加了 --oknodo,当进程已在运行时,返回2 (表示”无事可做”)
示例:
1 2 3 4 5 6 7 start-stop-daemon --start --pidfile /run/app.pid --exec /usr/bin/app start-stop-daemon --start --oknodo --pidfile /run/app.pid --exec /usr/bin/app
6.3. --stop 命令的退出码
退出码
含义
详细说明
0
停止成功
进程已停止
1
停止失败
一般性停止失败(如发送信号失败)
2
未在运行
仅在指定了 --oknodo 时 :进程未在运行且没有采取任何操作
3
pidfile错误
pidfile存在但无法读取或内容无效
4
进程匹配失败
根据指定条件未找到匹配的进程
5
超时
使用 --retry 时,在指定时间内进程未终止
关键细节:
如果不加 --oknodo,当进程未运行时,--stop 默认返回1 (表示”操作失败”——因为本应停止的进程不存在)
如果加了 --oknodo,当进程未运行时,返回2 (表示”无事可做”)
示例:
1 2 3 4 5 6 7 start-stop-daemon --stop --pidfile /run/app.pid start-stop-daemon --stop --oknodo --pidfile /run/app.pid
--retry 的退出码影响:
如果指定了 --retry TIMEOUT 或 --retry SCHEDULE,且进程在超时后仍未终止,返回5
例如:--retry 5 表示先发SIGTERM,等5秒,若未终止则发SIGKILL,若仍失败则返回5
6.4. --restart 的退出码 注意:--restart 在标准 start-stop-daemon 中不是直接支持的参数 ,通常是init脚本组合使用 --stop 和 --start 实现。但有些发行版(如Debian/Ubuntu)的版本支持 --restart:
退出码
含义
详细说明
0
重启成功
成功停止并重新启动
1
一般性失败
整体重启流程失败
2
停止失败
无法停止现有进程
3
启动失败
成功停止但无法启动新进程
4
未在运行
进程未运行且启动了新进程(类似--start)
5
未在运行且未启动
进程未运行且因某些原因未启动(如条件不满足)
如果没有内置的 --restart,手动实现的伪代码:
1 2 3 start-stop-daemon --stop --oknodo --pidfile $PIDFILE start-stop-daemon --start --pidfile $PIDFILE --exec $EXEC
6.5. --status 命令的退出码详解 这是你遇到的情况,--status 的退出码设计最为详细:
退出码
含义
详细说明
0
进程正在运行
根据pidfile或进程名匹配到活动进程
1
进程未运行
pidfile不存在 或 pidfile中的PID已不存在
2
进程未运行,且pidfile已失效
(较少使用)
3
进程未运行,但pidfile存在
pidfile存在但对应的进程已死亡(stale pidfile )
4
无法确定状态
权限不足无法读取/proc,或指定的匹配条件不明确
示例判断逻辑:
1 2 3 4 5 6 7 8 start-stop-daemon --status --pidfile /run/app.pid --exec /usr/bin/app case $? in 0) echo "✅ Running" ;; 1) echo "❌ Not running (no pidfile or dead)" ;; 3) echo "⚠️ Stale pidfile exists" ;; 4) echo "❓ Cannot determine (permission?)" ;; *) echo "💥 Error: $?" ;; esac
6.6. 退出码速查表
操作
--oknodo 影响
成功
已运行(stop时未运行)
失败/错误
--status
无关
0
1或3
4
--start
无
0
0(视为成功)
1,3,4,5
--start
有
0
2
1,3,4,5
--stop
无
0
1(视为失败)
3,4,5
--stop
有
0
2
3,4,5
--restart*
视子命令
0
4或5
1,2,3
*注:--restart 的退出码因实现而异
6.7. 实际应用示例 6.7.1. 检查状态并给出人类可读输出 1 2 3 4 5 6 7 8 9 10 check_status () { start-stop-daemon --status --pidfile "$1 " --exec "$2 " case $? in 0) echo "RUNNING" ;; 1) echo "STOPPED (no pidfile)" ;; 3) echo "STOPPED (stale pidfile)" ;; 4) echo "UNKNOWN (permission?)" ;; *) echo "ERROR" ;; esac }
6.7.2. 安全的停止脚本 1 2 3 4 5 6 7 8 9 10 11 12 stop_service () { start-stop-daemon --stop --retry 5 \ --oknodo \ --pidfile "$PIDFILE " \ --exec "$EXEC " case $? in 0) echo "Stopped successfully" ;; 2) echo "Already stopped" ;; 5) echo "Failed to stop after timeout" ; exit 1;; *) echo "Stop failed" ; exit 1;; esac }
6.7.3. 启动脚本考虑已运行情况 1 2 3 4 5 6 7 8 9 10 11 start_service () { start-stop-daemon --start --background --make-pidfile \ --pidfile "$PIDFILE " \ --exec "$EXEC " -- "$@ " case $? in 0) echo "Started (or already running)" ;; 2) echo "Already running (--oknodo would return 2)" ;; *) echo "Start failed" ; exit 1;; esac }
7. 注意事项 7.1. 常见问题
PID 文件不一致
权限问题
1 2 3 --user 指定用户必须有执行权限 --chdir 目录必须可访问
进程检测失败
1 2 --pidfile + --exec + --user 组合使用
7.2. 最佳实践 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 start-stop-daemon --start \ --pidfile $PIDFILE \ --make-pidfile \ --exec $DAEMON start-stop-daemon --stop \ --pidfile $PIDFILE \ --retry TERM/30/KILL/10 \ --oknodo test - x $DAEMON || exit 0test - f $CONFIG || exit 0
8. 跨平台差异
系统
命令位置
特性差异
Debian/Ubuntu
/sbin/start-stop-daemon
完整功能
RedHat/CentOS
/usr/sbin/start-stop-daemon
可能需要安装 dpkg
Alpine Linux
/sbin/start-stop-daemon
BusyBox 版本,功能简化
macOS
需要安装
通过 brew 安装 dpkg
9. 调试技巧 由于 start-stop-daemon 不输出任何信息,调试时可以:
详细输出 :
添加 --verbose 选项(如果版本支持),可以查看详细的调试信息。
1 start-stop-daemon --verbose --status --pidfile ...
检查退出码 :
1 start-stop-daemon --status --pidfile ...; echo "Exit code: $?"
查看系统日志 :
1 tail -f /var/log/syslog | grep start-stop-daemon
使用 strace 跟踪 (高级):
1 strace -e trace=process start-stop-daemon --status --pidfile ...
测试模式(不实际执行)
1 2 3 4 5 start-stop-daemon --start \ --pidfile $PIDFILE \ --exec $DAEMON \ --test
通过合理使用 start-stop-daemon,可以编写出健壮、可靠的服务管理脚本,确保系统服务的稳定运行。