Shell troubleshooting rc script

Hi all,

I am trying to daemonize scmserver and it's not going well. Here is my script from /usr/local/etc/rc.d/scmserver:

Code:
#!/bin/sh
# PROVIDE: scmserver
# REQUIRE: LOGIN
# KEYWORD: shutdown

#
# Add the following line to /etc/rc.conf to enable 'scmserver':
#
# scmserver_enable="YES"

. /etc/rc.subr
name=scmserver

rcvar=scmserver_enable
load_rc_config ${name}

: ${scmserver_enable:=NO}
: ${scmserver_user:=scm}
: ${scmserver_group:=scm}
: ${scmserver_chdir=/scm}

pidfile="/var/run/scm/${name}.pid"
procname="/usr/local/openjdk22/bin/java"
command=/usr/sbin/daemon
command_args="-f -p ${pidfile} /usr/local/scm-server/bin/scm-server"

echo $command $command_args

run_rc_command "$1"

Running service scmserver start doesn't do anything other than echoing the correct daemon command and printing Starting scmserver. The command that gets echoed works (if I copy and paste it in the terminal the daemon is started) but it won't start with the service command.

Help!

-Will
 
Also
Code:
/usr/local/etc/rc.d/scmserver start
/usr/local/etc/rc.d/scmserver stop

Seems to work fine... wazzup?
 
Seems to work fine... wazzup?
You are using the daemon service provider to start a daemon. That is not how you do it.

Your manual running of the script works because you are calling it up with daemon.
rc.d handles this for you. Just do the commands let rc.d do the daemon part.
 
I think it helps to look at non-system startup scripts in /usr/local/etc/rc.d/.

smartd script has some nice examples with error handling.
Code:
# DO NOT CHANGE THESE DEFAULT VALUES HERE

. /etc/rc.subr

name=smartd
rcvar=smartd_enable

load_rc_config smartd

: ${smartd_enable:="NO"}

required_files=${smartd_config:="/usr/local/etc/smartd.conf"}
pidfile=${smartd_pidfile:="/var/run/smartd.pid"}

command="/usr/local/sbin/smartd"
command_args="-c ${required_files} -p ${pidfile}"

extra_commands="reload report"
reload_cmd="smartd_reload"
report_cmd="smartd_report"

start_precmd=smartd_prestart

smartd_prestart()
{
    case "${smartd_flags}" in
    -p*|*-p*)
    err 1 'smartd_flags includes the -p option, use smartd_pidfile instead'
        ;;
    esac
}

smartd_reload()
{
    local status

    if ! status=`run_rc_command status 2>&1`; then
        echo $status
        return 1
    fi
    echo 'Reloading smartd.'
    kill -HUP $rc_pid
}
 
OK...

I got this:

Code:
#!/bin/sh

. /etc/rc.subr

name="scmserver"
rcvar=scmserver_enable

#start_cmd="${name}_start"
stop_cmd=":"

: ${scmserver_enable:=no}
: ${scmserver_msg="Nothing started."}
: ${scmserver_user:=scm}
: ${scmserver_group:=scm}
: ${scmserver_chdir=/scm}

pidfile="/var/run/scm/${name}.pid"

command_interpreter="/bin/sh"
command="/usr/local/scm-server/bin/scm-server"

load_rc_config ${name}
run_rc_command "$1"

now it starts the script in the foreground when I do service scmserver start...

Looks like this:

Code:
Starting scmserver.
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for furt
her details.
Set http request header size to 16384
Set http response header size to 16384
Set forward request customizer: true
Set http address binding to 0.0.0.0
Set http port to 8080
Set webapp war file to /usr/local/scm-server-3.4.1/var/webapp/sc
m-webapp.war
Set webapp temp directory to /var/cache/scm/work/scm
Set docroot temp directory to /var/cache/scm/work/docroot

How do I get it to run in the background...
 
Stealing from your example
Code:
command_args="-f -p ${pidfile} /usr/local/scm-server/bin/scm-server"

Something like this but without the command.
Flags only needed.
 
I see here he mentions daemon. Generally you don't use daemon under the rc.d daemon service.
 
found this helpful Alain De Vos post:
https://forums.freebsd.org/threads/practical-rc-scripting-very-short-tutorial.86814/

following that, I did:
Code:
#!/bin/sh
# PROVIDE: scmserver
# REQUIRE: LOGIN
# KEYWORD: shutdown

. /etc/rc.subr

name="scmserver"
rcvar=scmserver_enable

start_cmd="${name}_start"
stop_cmd="${name}_stop"

: ${scmserver_enable:=no}
: ${scmserver_user:=scm}
: ${scmserver_group:=scm}
: ${scmserver_chdir=/scm}

pidfile="/var/run/scm/${name}.pid"

command_interpreter="/bin/sh"
command="/usr/local/scm-server/bin/scm-server"

load_rc_config ${name}

scmserver_start()
{
if [ -f $pidfile ]
then
    echo "ALREADY STARTED"
else
    /usr/sbin/daemon -f -p $pidfile ${command}
    echo "scmserver service started."
fi
}


scmserver_stop()
{
if [ -f $pidfile ]
then
    kill -9 `cat $pidfile`
    echo "scmserver service stopped"
else
    echo "NOT YET STARTED"
fi
}

run_rc_command "$1"

And all seems well with the world. Any issues with this approach?
 
I see here he mentions daemon. Generally you don't use daemon under the rc.d daemon service.
This is interesting. I’ve been under the impression that using the daemon inside rc scripts is the right way to do it.

Is there a clear explanation why this isn’t a good idea?
 
A better question is why you would need to use daemon (the program) under the system daemon process.
A daemon under a daemon doesn't sound like good programming to me.
But as Charlie pointed out 434 out of 6000+ ports use daemon. None in the system rc.d directory use it though.
Is it corner cases or ordinary usage I dunno.
Maybe a program that doesn't use foreground/background it might be needed.
It just sounds redundant to me...
 
If you want to run something "as a daemon" that is not a daemon itself (has no means to fork itself and detach from the controlling tty), daemon(8) is the correct thing to use. Yes, that includes "from within a rc script".

You should never use it if the program you want to run daemonized does have some switch or whatever to "daemonize itself".

It's generally expected that programs offering services suitable for operating as a daemon do include "daemonization" code. On a BSD system, they could e.g. just use the daemon(3) function to achieve that, but many do it fully manually (fork, setsid, chdir, fiddle with the standard fds, ...). Obviously, for base, every daemon is a "real" one with correct behavior, so daemon(8) is not needed and using it would be an error.

I see systemd could more and more break the assumption that a daemon should, well, daemonize itself. In the systemd logic, it shouldn't ... systemd prepares an appropriate environment for its child process itself and then wants to observe it (and be notified by SIGCHLD on events). A classic init system won't do that, the daemon is launched by some shell script and it's the daemon's responsibility to ideally write/lock a pidfile (so the running instance can be identified) and do all the detaching stuff that will cause it to be "adopted" by init(8), which will do nothing else than reap it when it exits.
 
The trouble with java is that it can't do system calls, so can't fork, setsid, chdir, dup, open, close, signal,... and thus needs (a lot of) external help to act a dæmon.
 
Back
Top