You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FreeBSD rc.d脚本daemon参数丢失问题排查求助

问题

我正在为Java应用PeerBanHelper编写FreeBSD rc.d脚本,脚本内容如下:

#!/bin/sh
#
# PROVIDE: peerbanhelper
# REQUIRE: LOGIN
# KEYWORD: shutdown

. /etc/rc.subr

name="peerbanhelper"
rcvar=peerbanhelper_enable

load_rc_config $name

: ${peerbanhelper_enable:=NO}
: ${peerbanhelper_user:="root"}
: ${peerbanhelper_dir:="/usr/local/etc/peerbanhelper"}
: ${peerbanhelper_command:="/usr/local/bin/java"}
: ${peerbanhelper_classpath:="/usr/local/lib/peerbanhelper/PeerBanHelper.jar"}
: ${peerbanhelper_jvm_flags:="-Dpbh.datadir=${peerbanhelper_dir} -Xmx386M -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+ShrinkHeapInSteps -jar ${peerbanhelper_classpath}"}

command="/usr/sbin/daemon"
command_args="-f -p /var/run/${name}.pid -u ${peerbanhelper_user} ${peerbanhelper_command} ${peerbanhelper_jvm_flags}"
# this is for debug only
echo "run command: ${command} ${command_args}"
run_rc_command "$1" 

运行该脚本时得到以下报错:

root@freebsd:~/PeerBanHelper # service peerbanhelper onestart
run command: /usr/sbin/daemon -f -p /var/run/peerbanhelper.pid -u root /usr/local/bin/java 
/usr/local/etc/rc.d/peerbanhelper: DEBUG: checkyesno: peerbanhelper_enable is set to YES.
Starting peerbanhelper.
/usr/local/etc/rc.d/peerbanhelper: DEBUG: run_rc_command: doit:  limits -C daemon   /usr/sbin/daemon -Dpbh.datadir=/usr/local/etc/peerbanhelper -Xmx386M -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+ShrinkHeapInSteps -jar /usr/local/lib/peerbanhelper/PeerBanHelper.jar -f -p /var/run/peerbanhelper.pid -u root /usr/local/bin/java 
daemon: invalid option -- D
usage: daemon [-cfHrS] [-p child_pidfile] [-P supervisor_pidfile]
              [-u user] [-o output_file] [-t title]
              [-l syslog_facility] [-s syslog_priority]
              [-T syslog_tag] [-m output_mask] [-R restart_delay_secs]
command arguments ...
  --change-dir         -c         Change the current working directory to root
  --close-fds          -f         Set stdin, stdout, stderr to /dev/null
  --sighup             -H         Close and re-open output file on SIGHUP
  --syslog             -S         Send output to syslog
  --output-file        -o <file>  Append output of the child process to file
  --output-mask        -m <mask>  What to send to syslog/file
                                  1=stdout, 2=stderr, 3=both
  --child-pidfile      -p <file>  Write PID of the child process to file
  --supervisor-pidfile -P <file>  Write PID of the supervisor process to file
  --restart            -r         Restart child if it terminates (1 sec delay)
  --restart-delay      -R <N>     Restart child if it terminates after N sec
  --title              -t <title> Set the title of the supervisor process
  --user               -u <user>  Drop privileges, run as given user
  --syslog-priority    -s <prio>  Set syslog priority
  --syslog-facility    -l <flty>  Set syslog facility
  --syslog-tag         -T <tag>   Set syslog tag
  --help               -h         Show this help

从调试输出可见,/usr/sbin/daemon与${peerbanhelper_jvm_flags}之间的参数丢失,命令顺序错乱导致报错。若将command改为/usr/local/bin/java则可正常运行,但我需要实现进程守护,必须使用daemon命令,请问我的脚本存在什么问题?


问题原因与解决方法

原因分析

FreeBSD的rc.subr框架对command和command_args有特定处理逻辑:当你把daemon直接设为command时,框架会错误拆分参数,将原本属于Java的JVM标记识别为daemon的选项,最终导致参数顺序完全混乱,触发daemon: invalid option -- D的错误。

rc.d脚本的规范是:将实际要运行的业务程序(这里是Java)设为command,通过daemon_flags单独配置daemon工具自身的参数,框架会自动调用daemon来守护业务进程。

修正后的脚本

#!/bin/sh
#
# PROVIDE: peerbanhelper
# REQUIRE: LOGIN
# KEYWORD: shutdown

. /etc/rc.subr

name="peerbanhelper"
rcvar=peerbanhelper_enable

load_rc_config $name

: ${peerbanhelper_enable:=NO}
: ${peerbanhelper_user:="root"}
: ${peerbanhelper_dir:="/usr/local/etc/peerbanhelper"}
: ${peerbanhelper_command:="/usr/local/bin/java"}
: ${peerbanhelper_classpath:="/usr/local/lib/peerbanhelper/PeerBanHelper.jar"}
: ${peerbanhelper_jvm_flags:="-Dpbh.datadir=${peerbanhelper_dir} -Xmx386M -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+ShrinkHeapInSteps -jar ${peerbanhelper_classpath}"}
# 单独配置daemon的参数
: ${peerbanhelper_daemon_flags:="-f -p /var/run/${name}.pid -u ${peerbanhelper_user}"}

# 核心修正:将Java设为command,daemon参数通过daemon_flags传递
command="${peerbanhelper_command}"
command_args="${peerbanhelper_jvm_flags}"
daemon_flags="${peerbanhelper_daemon_flags}"

# debug输出
echo "run command: /usr/sbin/daemon ${daemon_flags} ${command} ${command_args}"
run_rc_command "$1" 

关键说明

  • 把Java程序设为command后,rc.subr会自动调用daemon工具来守护它,无需手动将daemon作为command。
  • daemon_flags专门存放daemon自身的配置(如PID文件、运行用户),command_args存放Java的JVM参数和程序参数,框架会正确将参数传递给对应进程。
  • 这种写法既保留了daemon的进程守护能力,又能确保所有参数被正确解析传递。

内容的提问来源于stack exchange,提问作者Gaojiali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:22:13