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
相关产品推荐
相关产品推荐

