Shell Daemonize a program through rc.d script

I am still struggling to create a working rc.d script for onedrive. covacat has explained that I need to explicitly define environment variables, but now I am facing another issue:

rc.d starts onedrive exactly as it should, but the program starts and stays in the foreground. Meaning: During the boot process the output from onedrive flushes the screen, and then it "hangs" the system before reaching the console login prompt. This makes perfect sense; onedrive is now monitoring my sync folder and the system waits for it to "finish". I can kill onedrive with Ctrl-C and get to the login prompt, but obviously I want it to keep running...

Is rc.d actually meant only for programs that are already daemons? Or can I use rc.d to daemonize any non-daemon program?

I tried to use the daemon command explicitly, and created a shell script:

Code:
#!/bin/sh
daemon -u borysj onedrive --monitor

but I am not sure if it works. "Nothing" happens, and neither
Code:
# ps -ax | grep onedrive
nor
Code:
# ps -ax | grep daemon
gives me any indication that onedrive is running.

Is it a proper approach?
 
Code:
#!/bin/sh
daemon -u borysj onedrive --monitor
So instead of scripting first then wondering; why not master the command line version first then transfer to script.
That way you can see whats going on.

You can also create a file called /etc/rc.local and use it as a startup script with this work.

It will not create a service daemon but it does execute a script on startup..
A service daemon is a rc.d script that allows commands like service onedrive start and service onedrive stop
 
During the boot process the output from onedrive flushes the screen, and then it "hangs" the system before reaching the console login prompt. This makes perfect sense; onedrive is now monitoring my sync folder and the system waits for it to "finish". I can kill onedrive with Ctrl-C and get to the login prompt, but obviously I want it to keep running...
OK so your service takes a long time to start.
Do you want to wait for login or continue. That is a simple rc.d file adjustment. Add a directive to not wait.

You can add stanzas like BEFORE: but I think what would work best is REQUIRES:LOGIN
That would not start file monitoring until the login prompt is on screen.
You need to let startup do its thing. Then start monitoring.
That is my opinion.
For best results study rcorder
 
Thanks for the replies, but:
  • Adding -f to daemon doesn't solve my problem, because it is not daemon that flushes the output; it is onedrive itself. Anyway, flushing with messages is not the issue here. The issue is that onedrive runs in the foreground and blocks the login.
  • Moving the script to rc.local won't change anything, I guess, because it is about how the scripts are organized, not how are they being run, right? Anyway, according to the manual, rc.local is kind of deprecated ("Typically, the rc.d mechanism is used instead of rc.local these days...")
  • You write first that "it will not create a service daemon", but then you confirm that I can use rc.d to daemonize any program. So which is it? Sorry, I do not understand the logic here (not the logic of your reply, but the logic of rc.d).
  • The service doesn't take a long time to start; it is supposed to keep running forever. This is why I would like to daemonize it.
  • REQUIRES: LOGIN does not help. I guess it is because the startup is delayed until right before the login prompt (manual: "Check-point before user login services").
So, to reiterate my original question:
Should I wrap onedrive into daemon through a script, and then run this script from rc.d, to achieve my goal of:
  • running onedrive at system startup, and
  • keep it on silently in the background?
 
Should I wrap onedrive into daemon through a script, and then run this script from rc.d
rc(8) scripts wrap a bunch of facilities like starting and stopping around dæmon class processes using well understood conventions that integrate into the booting and shutdown process.

Creating a dæmon is a separate task. You should design and test your dæmon quite separately from the rc(8) infrastructure. [Be aware of it, but build and test separately.]

No dæmon ever runs in the foreground, unless it's being tested. Dæmons are session and process group leaders. They have no controlling terminal -- which means that they WILL NOT respond to Ctrl-C or any other signal delivered by a controlling tty. Normally, these settings are established when an executable program is invoked using the daemon(8) command (or when a C program calls the daemon(3) library function). Dæmons would usually close stdin, stdout, and stderr, plus change working directory to a safe place which is not likely to get deleted. Most of this is handled by the daemon(8) command, but you need to read the manual page carefully. Also dæmons generally use syslogd(8) to report progress, and problems.

Not every application will necessarily behave in a way compatible with expected behaviour of a dæmon.

You should test your dæmon from the command line. Make sure it behaves as you expect.

Once you have it working, move on to using the rc(8) facilities to get it started at boot time.
 
Daemonizing a program is actually quite an involved task. I forget all the details, but the daemon program needs to detach from the controlling terminal, create a new process group (usually done by forking twice), redirect its output to syslog, change its working directory to something that won't be unmounted (/ is a good choice), close excess file descripters, adjust signal handling (in particular close/reopen any log files on HUP to allow for log rotation), update and check PID files, and probably a few other things I forgot about. If you search the web, there are several long articles that explain what the various steps are, and why each step is needed. The FreeBSD standard rc.d mechanism expects the daemon program to do all of this, and typical daemons all do. For programs that don't daemonize, the daemon(8) utility can be used on FreeBSD.

Once you run a program through daemon (with -f if the program doesn't know to close the standard three file descriptors), the problems like it "running in the foreground" and blocking should go away. You should test that from the command line a few times. And also think through how you are going to control and stop your new daemon when needed.

EDITed: I see the gpw928 said pretty much the same thing a moment ago.
 
I remember daemon taking a while to get the flags right,
I decided instead of using the existing daemon(8) program to code the whole daemonize thing in Python. That's because I wanted code that works on Linux AND FreeBSD, so you have to do it yourself. In retrospect, this was dumb, because (a) on FreeBSD you can use the daemon program, and (b) on Linux, systemd handled daemonizing for you, so you can mostly use a normal Unix-style program (with stdin and stdout) as a daemon.
 
I decided instead of using the existing daemon(8) program to code the whole daemonize thing in Python.
Not familiar with python (it's too lengthy for my taste), but ruby has an invocation Process.daemon that does just daemonize,so it can be done in midflight if the need arises.

Also, when just wanting to run something from rc.d, I am using this - probably still missing one or two matters, but basically seems to work:
Code:
#!/bin/sh

# PROVIDE: myprogram
# REQUIRE: DAEMON
# KEYWORD: shutdown

. /etc/rc.subr

name="myprogram"
rcvar=myprogram_enable

# read configuration and set defaults
load_rc_config $name
: ${myprogram_enable:="NO"}

pidfile="/var/run/${name}.pid"
procname="/ext/sbin/${name}"
command="/usr/sbin/daemon"
command_args="-S -p ${pidfile} ${procname}"

run_rc_command "$1"
 
Back
Top