diff -u -r -N usr.sbin/daemon.orig/daemon.8 usr.sbin/daemon/daemon.8 --- usr.sbin/daemon.orig/daemon.8 2016-02-16 15:01:42.820821797 +0100 +++ usr.sbin/daemon/daemon.8 2016-02-16 15:00:24.410798668 +0100 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 13, 2013 +.Dd February 14, 2016 .Dt DAEMON 8 .Os .Sh NAME @@ -34,7 +34,8 @@ .Nd run detached from the controlling terminal .Sh SYNOPSIS .Nm -.Op Fl cfr +.Op Fl cr +.Op Fl f | Fl e Ar stderr_path Fl o Ar stdout_path Op Fl a .Op Fl p Ar child_pidfile .Op Fl P Ar supervisor_pidfile .Op Fl u Ar user @@ -54,6 +55,28 @@ .It Fl f Redirect standard input, standard output and standard error to .Pa /dev/null . +.It Fl e +Redirect standard error to +.Pa stderr_path. +.br +Use only with +.Fl o, +optionally +.Fl a +and not with +.Fl f. +.It Fl o +Redirect standard output to +.Pa stdout_path. +.br +Use only with +.Fl e, +optionally +.Fl a +and not with +.Fl f. +.It Fl a +Append to stdout / stderr redirection destination instead of overwriting it. .It Fl p Ar child_pidfile Write the ID of the created process into the .Ar child_pidfile @@ -131,6 +154,14 @@ stop the service, causing .Nm to restart the child. +.Pp +Redirecting stdout and stderr may be useful if the application +does not provide alternative means to log output to a file. +.br +/dev/null is a valid redirection target. +.br +Note that the log file is owned by the user starting +.Xr daemon(8). .Sh EXIT STATUS The .Nm diff -u -r -N usr.sbin/daemon.orig/daemon.c usr.sbin/daemon/daemon.c --- usr.sbin/daemon.orig/daemon.c 2016-02-16 12:37:37.797878419 +0100 +++ usr.sbin/daemon/daemon.c 2016-02-16 14:57:10.365439029 +0100 @@ -44,6 +44,7 @@ #include #include #include +#include static void dummy_sighandler(int); static void restrict_process(const char *); @@ -55,14 +56,14 @@ { struct pidfh *ppfh, *pfh; sigset_t mask, oldmask; - int ch, nochdir, noclose, restart, serrno; - const char *pidfile, *ppidfile, *user; + int ch, nochdir, noclose, restart, serrno, append_on_redirection; + const char *pidfile, *ppidfile, *user, *stdout_path, *stderr_path; pid_t otherpid, pid; nochdir = noclose = 1; - restart = 0; - ppidfile = pidfile = user = NULL; - while ((ch = getopt(argc, argv, "cfp:P:ru:")) != -1) { + restart = append_on_redirection = 0; + ppidfile = pidfile = user = stdout_path = stderr_path = NULL; + while ((ch = getopt(argc, argv, "cfp:P:ru:o:e:a")) != -1) { switch (ch) { case 'c': nochdir = 0; @@ -82,6 +83,15 @@ case 'u': user = optarg; break; + case 'o': + stdout_path = optarg; + break; + case 'e': + stderr_path = optarg; + break; + case 'a': + append_on_redirection = 1; + break; default: usage(); } @@ -122,6 +132,57 @@ } } + /* Handle alternative stdout if requested.*/ + if (stdout_path != NULL || stderr_path != NULL) { + + if (!(stdout_path != NULL && stderr_path != NULL)) { + warnx("specify either both or no alternative " + "stdout and stderr"); + goto exit; + } + + if (noclose == 0) { + warnx("redirecting stdout & stderr to /dev/null " + "and specifying alternative redirection paths " + "is mutually exclusive"); + goto exit; + } + + /* daemon() will not close stdin,stdout,stderr now. + Redirect output to appropriate descriptors instead */ + int output_flags = O_WRONLY | O_CREAT; + output_flags |= append_on_redirection ? O_APPEND : O_TRUNC; + + const int output_mode = 0600; + + int null_fd = open("/dev/null", O_WRONLY); + int stdout_fd = open(stdout_path, output_flags, output_mode); + int stderr_fd = open(stderr_path, output_flags, output_mode); + + if (null_fd == -1 || stdout_fd == -1 || stderr_fd == -1) { + warn("could not open one or more stdin / stdout / " + "stderr redirection destinations."); + goto exit; + } + + if (close(STDOUT_FILENO) == -1 || + close(STDERR_FILENO) == -1 || + close(STDIN_FILENO) == -1) { + warn("could not close original stdin / stdout / " + "stderr."); + goto exit; + } + + if (dup2(null_fd, STDIN_FILENO) == -1 || + dup2(stdout_fd, STDOUT_FILENO) == -1 || + dup2(stderr_fd, STDERR_FILENO) == -1) { + warn("could not redirect stdin / stdout / stderr " + "to sepcified destinations."); + goto exit; + } + + } + if (daemon(nochdir, noclose) == -1) { warn("daemon"); goto exit; @@ -270,7 +331,8 @@ usage(void) { (void)fprintf(stderr, - "usage: daemon [-cfr] [-p child_pidfile] [-P supervisor_pidfile] " + "usage: daemon [-cr] [-f | -e stderr_path -o stdout_path [-a]] " + "[-p child_pidfile] [-P supervisor_pidfile] " "[-u user]\n command arguments ...\n"); exit(1); }