调用start-stop-daemon的脚本直接运行正常,C++调用时失效求助
问题描述
我有一个使用start-stop-daemon的启动脚本,代码如下:
trap "" 1 ( echo "INFO Starting $BinName application" cd ${APPLICATION_ROOT} if [ -e ${DEVOUT} ]; then mv ${DEVOUT} ${DEVOUTOLD} fi if [ -e ${DEVERR} ]; then mv ${DEVERR} ${DEVERROLD} fi if [ -e ${VALGRIND_LOG} ]; then mv ${VALGRIND_LOG} ${VALGRIND_LOG_OLD} fi # rm ${VALGRIND_LOG} HASHCODE=$(sha1sum ${APPLICATION_BIN}/${BinName}|cut -b0-40) if [ ! -z "$VALGRIND_ENABLE" ]; then VALGRIND_CMD="$VALGRIND --log-file=$VALGRIND_LOG" fi start-stop-daemon -S -b -m -p ${PidFileName} -c service:c10 --startas /bin/bash -- -c "/usr/bin/nohup $VALGRIND_CMD ${APPLICATION_BIN}/${BinName} -j 8019 -O -H $HASHCODE 2>${DEVERR} > ${DEVOUT} &" ) sleep 1 pid=$(mypidof $BinName) echo $pid > $PidFileName if [ X$pid != "X" ]; then RETVAL=0; echo "INFO $BinName running with pid=${pid}" else RETVAL=11; echo "ERROR Start $BinName failed !!!" fi
直接运行该脚本时,start-stop-daemon能正常启动目标进程,但通过C++的system()/popen()/execv()调用脚本时,目标进程并未启动,不清楚哪里出了问题。
排查与解决方案
1. 环境变量缺失
终端运行脚本会继承当前shell的环境变量,但C++程序调用时(尤其是execv这类函数),环境变量可能被清空或不完整:
- 脚本中依赖的
BinName、APPLICATION_ROOT等变量,要么在脚本开头显式定义,要么在C++调用时通过execve()传递完整环境变量数组,或用system()前先设置好环境变量; - 给
start-stop-daemon、mypidof等命令加上绝对路径(比如/sbin/start-stop-daemon),避免因PATH环境变量缺失找不到命令。
2. 权限不足
脚本中start-stop-daemon用了-c service:c10切换用户,若C++程序运行用户权限不够,会导致切换失败:
- 检查C++程序的运行用户是否和手动执行脚本时一致;
- 若需要切换用户,确保C++程序以root运行,或给程序设置SUID位获取对应权限。
3. 上下文与输出重定向问题
C++调用时可能因stdout/stderr被重定向或关闭,导致子进程无法正常启动:
- 调用脚本时显式重定向输出到日志文件,比如
system("./your_script.sh > /tmp/script_run.log 2>&1"),查看日志里start-stop-daemon的错误信息; - 去掉
start-stop-daemon命令末尾的&,因为-b参数已经指定后台运行,重复加&会导致进程管理混乱。
4. execv()参数错误
使用execv()时参数构造必须规范:
- 第一个参数必须是脚本的绝对路径;
- 参数数组最后必须以
NULL结尾,示例:
char* args[] = {"/full/path/to/your_script.sh", NULL}; execv(args[0], args);
5. 脚本逻辑冲突
脚本中start-stop-daemon已经通过-m -p ${PidFileName}生成PID文件,后续用mypidof查找并覆盖PID文件的逻辑可能导致混乱:
- 注释掉
echo $pid > $PidFileName这一行,测试启动是否正常; - 查看
DEVOUT、DEVERR日志文件,里面可能有nohup或目标进程的启动错误信息。
内容的提问来源于stack exchange,提问作者pinxpoong
相关产品推荐
相关产品推荐

