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
This commit is contained in:
parent
4d1bad3c62
commit
4cd407ec93
@ -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.
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user