From owner-svn-src-head@freebsd.org Thu Sep 24 02:44:59 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id B50E73EA52B; Thu, 24 Sep 2020 02:44:59 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4BxfXW4KsWz3XDK; Thu, 24 Sep 2020 02:44:59 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 787221B099; Thu, 24 Sep 2020 02:44:59 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 08O2ixsA023406; Thu, 24 Sep 2020 02:44:59 GMT (envelope-from sobomax@FreeBSD.org) Received: (from sobomax@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 08O2ixw5023405; Thu, 24 Sep 2020 02:44:59 GMT (envelope-from sobomax@FreeBSD.org) Message-Id: <202009240244.08O2ixw5023405@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: sobomax set sender to sobomax@FreeBSD.org using -f From: Maxim Sobolev Date: Thu, 24 Sep 2020 02:44:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r366098 - head/usr.sbin/daemon X-SVN-Group: head X-SVN-Commit-Author: sobomax X-SVN-Commit-Paths: head/usr.sbin/daemon X-SVN-Commit-Revision: 366098 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Sep 2020 02:44:59 -0000 Author: sobomax Date: Thu Sep 24 02:44:58 2020 New Revision: 366098 URL: https://svnweb.freebsd.org/changeset/base/366098 Log: 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. Reviewed by: markj, rpokala (manpages) MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D26526 Modified: head/usr.sbin/daemon/daemon.8 head/usr.sbin/daemon/daemon.c Modified: head/usr.sbin/daemon/daemon.8 ============================================================================== --- head/usr.sbin/daemon/daemon.8 Wed Sep 23 23:56:49 2020 (r366097) +++ head/usr.sbin/daemon/daemon.8 Thu Sep 24 02:44:58 2020 (r366098) @@ -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 fi .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. Modified: head/usr.sbin/daemon/daemon.c ============================================================================== --- head/usr.sbin/daemon/daemon.c Wed Sep 23 23:56:49 2020 (r366097) +++ head/usr.sbin/daemon/daemon.c Thu Sep 24 02:44:58 2020 (r366098) @@ -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, s 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) { @@ -559,10 +580,36 @@ 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"