This patch adds daemonizing support using libdaemon. * console-client/console.c (daemonize): New variable. (options): Add --daemonize argument. (parse_opt): Handle --daemonize argument. (daemon_error): New error(3) like macro. (main): Daemonize. --- console-client/Makefile | 2 +- console-client/console.c | 104 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 6 deletions(-)
diff --git a/console-client/Makefile b/console-client/Makefile index 69a7e37..0ad7a53 100644 --- a/console-client/Makefile +++ b/console-client/Makefile @@ -37,7 +37,7 @@ SRCS = $(CONSOLE_SRCS) \ VPATH += $(srcdir)/xkb OBJS = $(addsuffix .o,$(basename $(notdir $(SRCS)))) kdioctlServer.o HURDLIBS = cons ports netfs fshelp iohelp ihash shouldbeinlibc -LDLIBS = -ldl -lpthread +LDLIBS = -ldl -lpthread -ldaemon module-dir = $(libdir)/hurd/console console-LDFLAGS = -Wl,-E diff --git a/console-client/console.c b/console-client/console.c index 7c9a880..7dd7a00 100644 --- a/console-client/console.c +++ b/console-client/console.c @@ -26,6 +26,7 @@ #include <assert.h> #include <pthread.h> +#include <libdaemon/daemon.h> #include <hurd/console.h> #include <hurd/cons.h> @@ -61,6 +62,8 @@ static cons_t saved_cons; set. */ static char *console_node; +/* If set, the client will daemonize. */ +static int daemonize; /* Callbacks for input source drivers. */ @@ -516,6 +519,8 @@ cons_vcons_set_mousecursor_status (vcons_t vcons, int status) } +#define DAEMONIZE_KEY 0x80 /* !isascii (DAEMONIZE_KEY), so no short option. */ + /* Console-specific options. */ static const struct argp_option options[] = @@ -524,6 +529,7 @@ options[] = {"driver", 'd', "NAME", 0, "Add driver NAME to the console" }, {"console-node", 'c', "FILE", OPTION_ARG_OPTIONAL, "Set a translator on the node FILE (default: " DEFAULT_CONSOLE_NODE ")" }, + {"daemonize", DAEMONIZE_KEY, NULL, 0, "daemonize the console client"}, {0} }; @@ -577,7 +583,11 @@ parse_opt (int key, char *arg, struct argp_state *state) if (!console_node) return ENOMEM; break; - + + case DAEMONIZE_KEY: + daemonize = 1; + break; + case ARGP_KEY_SUCCESS: if (!devcount) { @@ -598,6 +608,28 @@ static const struct argp_child startup_children[] = static struct argp startup_argp = {options, parse_opt, 0, 0, startup_children}; +#define daemon_error(status, errnum, format, args...) \ + do \ + { \ + if (daemonize) \ + { \ + if (errnum) \ + daemon_log (LOG_ERR, format ": %s", ##args, \ + strerror(errnum)); \ + else \ + daemon_log (LOG_ERR, format, ##args); \ + if (status) \ + { \ + /* Signal parent. */ \ + daemon_retval_send (status); \ + return 0; \ + } \ + } \ + else \ + error (status, errnum, format, ##args); \ + } \ + while (0); + int main (int argc, char *argv[]) { @@ -609,9 +641,67 @@ main (int argc, char *argv[]) /* Parse our command line. This shouldn't ever return an error. */ argp_parse (&startup_argp, argc, argv, ARGP_IN_ORDER, 0, 0); + if (daemonize) + { + /* Reset signal handlers. */ + if (daemon_reset_sigs (-1) < 0) + error (1, errno, "Failed to reset all signal handlers"); + + /* Unblock signals. */ + if (daemon_unblock_sigs (-1) < 0) + error (1, errno, "Failed to unblock all signals"); + + /* Set indetification string for the daemon for both syslog and + PID file. */ + daemon_pid_file_ident = daemon_log_ident = \ + daemon_ident_from_argv0 (argv[0]); + + /* Check that the daemon is not run twice at the same time. */ + pid_t pid; + if ((pid = daemon_pid_file_is_running ()) >= 0) + error (1, errno, "Daemon already running on PID file %u", pid); + + /* Prepare for return value passing from the initialization + procedure of the daemon process. */ + if (daemon_retval_init () < 0) + error (1, errno, "Failed to create pipe."); + + /* Do the fork. */ + if ((pid = daemon_fork ()) < 0) + { + /* Exit on error. */ + daemon_retval_done (); + error (1, errno, "Failed to fork"); + } + else if (pid) + { + /* The parent. */ + int ret; + + /* Wait for 20 seconds for the return value passed from the + daemon process. . */ + if ((ret = daemon_retval_wait (20)) < 0) + error (1, errno, + "Could not receive return value from daemon process"); + + return ret; + } + else + { + /* The daemon. */ + /* Close FDs. */ + if (daemon_close_all (-1) < 0) + daemon_error (1, errno, "Failed to close all file descriptors"); + + /* Create the PID file. */ + if (daemon_pid_file_create () < 0) + daemon_error (2, errno, "Could not create PID file"); + } + } + err = driver_start (&errname); if (err) - error (1, err, "Starting driver %s failed", errname); + daemon_error (1, err, "Starting driver %s failed", errname); pthread_mutex_init (&global_lock, NULL); @@ -619,19 +709,23 @@ main (int argc, char *argv[]) if (err) { driver_fini (); - error (1, err, "Console library initialization failed"); + daemon_error (1, err, "Console library initialization failed"); } err = timer_init (); if (err) { driver_fini (); - error (1, err, "Timer thread initialization failed"); + daemon_error (1, err, "Timer thread initialization failed"); } if (console_node) console_setup_node (console_node); - + + if (daemonize) + /* Signal parent that all went well. */ + daemon_retval_send(0); + cons_server_loop (); /* Never reached. */ -- 1.7.10.4