Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Jul 2021 12:40:49 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 7fa95d69f108 - stable/12 - dd a new option (-H) to daemon(8) to catch SIGHUP and re-open output_file file when received.
Message-ID:  <202107281240.16SCenMW069297@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=7fa95d69f10827d0b02607682a2c4a1513d658e5

commit 7fa95d69f10827d0b02607682a2c4a1513d658e5
Author:     Maxim Sobolev <sobomax@FreeBSD.org>
AuthorDate: 2020-09-24 02:44:58 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-07-28 12:38:38 +0000

    dd a new option (-H) to daemon(8) to catch SIGHUP and re-open output_file file when
    received.
    
    The default system log rotation mechanism (newsyslog(8)) requires ability to send
    signal to a daemon in order to properly complete rotation of the logs in an "atomic"
    manner without having to making a copy and truncating original file. Unfortunately
    our built-in mechanism to convert "dumb" programs into daemons has no way to handle
    this rotation properly. This change adds this ability, to be enabled by supplying -H
    option in addition to the -o option.
    
    PR:             255198
    Reviewed by:    markj, rpokala (manpages)
    
    (cherry picked from commit 4cd407ec933b81d9d0f733532d29426416cccc06)
---
 usr.sbin/daemon/daemon.8 | 18 ++++++++++++--
 usr.sbin/daemon/daemon.c | 63 ++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/usr.sbin/daemon/daemon.8 b/usr.sbin/daemon/daemon.8
index bd853652c03f..665108df6afc 100644
--- a/usr.sbin/daemon/daemon.8
+++ b/usr.sbin/daemon/daemon.8
@@ -26,7 +26,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 2, 2019
+.Dd September 22, 2020
 .Dt DAEMON 8
 .Os
 .Sh NAME
@@ -34,7 +34,7 @@
 .Nd run detached from the controlling terminal
 .Sh SYNOPSIS
 .Nm
-.Op Fl cfrS
+.Op Fl cfHrS
 .Op Fl p Ar child_pidfile
 .Op Fl P Ar supervisor_pidfile
 .Op Fl t Ar title
@@ -68,6 +68,14 @@ or syslog output, the standard file descriptors are first redirected to
 .Pa /dev/null ,
 then stdout and/or stderr is redirected to a file or to syslog as
 specified by the other options.
+.It Fl H
+Close
+.Pa output_file
+and re-open it when signal SIGHUP is received, for interoperability with
+.Xr newsyslog 1
+and similar log rotation / archival mechanisms.  If
+.Fa o
+is not specified, this flag is ignored.
 .It Fl S
 Enable syslog output.
 This is implicitly applied if other syslog parameters are provided.
@@ -77,6 +85,12 @@ tag, respectively.
 Append output from the daemonized process to
 .Pa output_file .
 If the file does not exist, it is created with permissions 0600.
+When this option is used together with options
+.Fl c and
+.Fl H
+the absolute path needs to be provided to ensure
+.Nm
+can re-open the file after a SIGHUP.
 .It Fl m Ar output_mask
 Redirect output from the child process stdout (1), stderr (2), or both (3).
 This value specifies what is sent to syslog and the log file.
diff --git a/usr.sbin/daemon/daemon.c b/usr.sbin/daemon/daemon.c
index 7a245421e4df..d8a26132223b 100644
--- a/usr.sbin/daemon/daemon.c
+++ b/usr.sbin/daemon/daemon.c
@@ -61,11 +61,15 @@ struct log_params {
 	int logpri;
 	int noclose;
 	int outfd;
+	const char *outfn;
 };
 
 static void restrict_process(const char *);
 static void handle_term(int);
 static void handle_chld(int);
+static void handle_hup(int);
+static int open_log(const char *);
+static void reopen_log(struct log_params *);
 static int  listen_child(int, struct log_params *);
 static int  get_log_mapping(const char *, const CODE *);
 static void open_pid_files(const char *, const char *, struct pidfh **,
@@ -74,7 +78,8 @@ static void do_output(const unsigned char *, size_t, struct log_params *);
 static void daemon_sleep(time_t, long);
 static void usage(void);
 
-static volatile sig_atomic_t terminate = 0, child_gone = 0, pid = 0;
+static volatile sig_atomic_t terminate = 0, child_gone = 0, pid = 0,
+  do_log_reopen = 0;
 
 int
 main(int argc, char *argv[])
@@ -84,7 +89,7 @@ main(int argc, char *argv[])
 	sigset_t mask_susp, mask_orig, mask_read, mask_term;
 	struct log_params logpar;
 	int pfd[2] = { -1, -1 }, outfd = -1;
-	int stdmask, logpri, logfac;
+	int stdmask, logpri, logfac, log_reopen;
 	struct pidfh *ppfh, *pfh;
 	char *p;
 
@@ -97,9 +102,10 @@ main(int argc, char *argv[])
 	logtag = "daemon";
 	restart = 0;
 	dosyslog = 0;
+	log_reopen = 0;
 	outfn = NULL;
 	title = NULL;
-	while ((ch = getopt(argc, argv, "cfSp:P:ru:o:s:l:t:l:m:R:T:")) != -1) {
+	while ((ch = getopt(argc, argv, "cfHSp:P:ru:o:s:l:t:l:m:R:T:")) != -1) {
 		switch (ch) {
 		case 'c':
 			nochdir = 0;
@@ -107,6 +113,9 @@ main(int argc, char *argv[])
 		case 'f':
 			noclose = 0;
 			break;
+		case 'H':
+			log_reopen = 1;
+			break;
 		case 'l':
 			logfac = get_log_mapping(optarg, facilitynames);
 			if (logfac == -1)
@@ -168,7 +177,7 @@ main(int argc, char *argv[])
 		title = argv[0];
 
 	if (outfn) {
-		outfd = open(outfn, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0600);
+		outfd = open_log(outfn);
 		if (outfd == -1)
 			err(7, "open");
 	}
@@ -201,7 +210,7 @@ main(int argc, char *argv[])
 	 */
 	pid = -1;
 	if (pidfile || ppidfile || restart || outfd != -1 || dosyslog) {
-		struct sigaction act_term, act_chld;
+		struct sigaction act_term, act_chld, act_hup;
 
 		/* Avoid PID racing with SIGCHLD and SIGTERM. */
 		memset(&act_term, 0, sizeof(act_term));
@@ -214,6 +223,10 @@ main(int argc, char *argv[])
 		sigemptyset(&act_chld.sa_mask);
 		sigaddset(&act_chld.sa_mask, SIGTERM);
 
+		memset(&act_hup, 0, sizeof(act_hup));
+		act_hup.sa_handler = handle_hup;
+		sigemptyset(&act_hup.sa_mask);
+
 		/* Block these when avoiding racing before sigsuspend(). */
 		sigemptyset(&mask_susp);
 		sigaddset(&mask_susp, SIGTERM);
@@ -251,6 +264,12 @@ main(int argc, char *argv[])
 		logpar.dosyslog = dosyslog;
 		logpar.logpri = logpri;
 		logpar.noclose = noclose;
+		logpar.outfn = outfn;
+		if (log_reopen && outfd >= 0 &&
+		    sigaction(SIGHUP, &act_hup, NULL) == -1) {
+			warn("sigaction");
+			goto exit;
+		}
 restart:
 		if (pipe(pfd))
 			err(1, "pipe");
@@ -465,6 +484,8 @@ listen_child(int fd, struct log_params *logpar)
 	assert(logpar);
 	assert(bytes_read < LBUF_SIZE - 1);
 
+	if (do_log_reopen)
+		reopen_log(logpar);
 	rv = read(fd, buf + bytes_read, LBUF_SIZE - bytes_read - 1);
 	if (rv > 0) {
 		unsigned char *cp;
@@ -543,9 +564,9 @@ handle_term(int signo)
 }
 
 static void
-handle_chld(int signo)
+handle_chld(int signo __unused)
 {
-	(void)signo;
+
 	for (;;) {
 		int rv = waitpid(-1, NULL, WNOHANG);
 		if (pid == rv) {
@@ -558,11 +579,37 @@ handle_chld(int signo)
 	}
 }
 
+static void
+handle_hup(int signo __unused)
+{
+
+	do_log_reopen = 1;
+}
+
+static int
+open_log(const char *outfn)
+{
+
+	return open(outfn, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0600);
+}
+
+static void
+reopen_log(struct log_params *lpp)
+{
+	int outfd;
+
+	do_log_reopen = 0;
+	outfd = open_log(lpp->outfn);
+	if (lpp->outfd >= 0)
+		close(lpp->outfd);
+	lpp->outfd = outfd;
+}
+
 static void
 usage(void)
 {
 	(void)fprintf(stderr,
-	    "usage: daemon [-cfrS] [-p child_pidfile] [-P supervisor_pidfile]\n"
+	    "usage: daemon [-cfHrS] [-p child_pidfile] [-P supervisor_pidfile]\n"
 	    "              [-u user] [-o output_file] [-t title]\n"
 	    "              [-l syslog_facility] [-s syslog_priority]\n"
 	    "              [-T syslog_tag] [-m output_mask] [-R restart_delay_secs]\n"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107281240.16SCenMW069297>