On Mon, Aug 17, 2009 at 04:37:07PM -0700, Garrett D'Amore wrote:
> >It's there in libc in RHEL5.
> 
> If its there in RHEL5, then I'll withdraw my major concerns.  I think 
> the documentation should point users to other, more robust ways of 
> dealing with daemon startup. 

Yes, that's true, but here daemon() does help: the start method of a
service whosea daemon that doesn't do any of what daemon() does and does
not call it... needs to start the daemon like so:

#!/bin/sh

. /lib/svc/share/smf_include.sh

/path/to/daemon &
sleep $some_time

# We don't know if it really did start.  If it didn't we'll get
# restarted until it does start or n-strikes-you're-done
exit $SMF_EXIT_OK

Whereas a daemon program that calls daemon() _after_ initializing can be
started like this:

#!/bin/sh

. /lib/svc/share/smf_include.sh

if ! /path/to/daemon
then
    # handle errors and map to suitable SMF error
    ...
fi

exit $SMF_EXIT_OK

In other words: daemon() is a Good Thing.

The only things to document are: a) the need to do something like
daemon(), b) make sure the parent exits _after_ initialization
completes, c), if you need to drop privs after initialization, then do
that too.

Ideally we'd have something like:

/*
 * Depending on flags daemon2() will fork(), setsid(), fork(),
 * chdir("/"), etcetera.  In the child daemon2() will call
 * templace_callback(); if that returns non-zero, then daemon2() will
 * exit(2) with that error.  In the grandchild daemon2() will call
 * init_callback(init_cb_data), and it that returns zero, then it will
 * call context_setup(context_setup_data), and the grandparent will
 * exit() with the first non-zero return value of those callbacks, else
 * it will exit(0).  (Internally daemon2() uses an IPC mechanism by
 * which the grandchild communicates its status to the grandparent.)
 *
 * Any and all three of templace_callback, init_callback, and
 * context_setup may be NULL.
 *
 * Pre-defined templace and context setup callback functions:
 *
 *  - daemon2_process_contract_template(...)
 *    (put the grandchild in its own process contract as described by
 *    template_cb_data.)
 *  - daemon2_process_context_setup(...)
 *    (initialize the ruid/suid/euid, rgid/sgid/egid, supplementary
 *    groups, privileges.)
 *
 * Flags: DAEMON2_CHDIR, DAEMON2_SETSID, ...
 */
void daemon2(
        int flags,
        int (*templace_callback)(void *arg),
        void *template_cb_data,
        int (*init_callback)(void *arg),
        void *init_cb_data,
        int (*context_setup)(void *arg),
        void *context_setup_data
);

Or something like that.

> Last question: Is "Committed" the way to deal with this?  If we want to 
> steer developers elsewhere, should we instead just list this interface 
> with "Committed Obsolete" or perhaps "Uncommitted".

daemon() won't go away.  Committed is fine, IMO.

Nico
-- 

Reply via email to