From dab7fa54300ebdfe67399b7ae0db895888157c2a Mon Sep 17 00:00:00 2001 From: Jean-Jacques Bernard-Gundol Date: Wed, 24 Oct 2001 08:16:43 +0000 Subject: syslog_r() implementation. deraadt@ ok. --- lib/libc/gen/syslog.3 | 113 ++++++++++++++++++++-- lib/libc/gen/syslog.c | 263 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 275 insertions(+), 101 deletions(-) (limited to 'lib/libc/gen') diff --git a/lib/libc/gen/syslog.3 b/lib/libc/gen/syslog.3 index 36f998b8ee2..3f09655a030 100644 --- a/lib/libc/gen/syslog.3 +++ b/lib/libc/gen/syslog.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: syslog.3,v 1.12 2001/07/27 16:41:20 marc Exp $ +.\" $OpenBSD: syslog.3,v 1.13 2001/10/24 08:16:42 jjbg Exp $ .\" .\" Copyright (c) 1985, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -36,10 +36,15 @@ .Os .Sh NAME .Nm syslog , +.Nm syslog_r, .Nm vsyslog , +.Nm vsyslog_r, .Nm openlog , +.Nm openlog_r, .Nm closelog , -.Nm setlogmask +.Nm closelog_r, +.Nm setlogmask, +.Nm setlogmask_r .Nd control system log .Sh SYNOPSIS .Fd #include @@ -47,13 +52,36 @@ .Ft void .Fn syslog "int priority" "const char *message" "..." .Ft void +.Fn syslog_r "int priority" "struct syslog_data *data" "const char *message" "..." +.Ft void .Fn vsyslog "int priority" "const char *message" "va_list args" .Ft void +.Fn vsyslog_r "int priority" "struct syslog_data *data" "const char *message" "va_list args" +.Ft void .Fn openlog "const char *ident" "int logopt" "int facility" .Ft void +.Fn openlog_r "const char *ident" "int logopt" "int facility" "struct syslog_data *data" +.Ft void .Fn closelog void +.Ft void +.Fn closelog_r "struct syslog_data *data" .Ft int .Fn setlogmask "int maskpri" +.Ft int +.Fn setlogmask_r "int maskpri" "struct syslog_data *data" +.Bd -literal + +struct syslog_data { + int log_file; + int connected; + int opened; + int log_stat; + const char *log_tag; + int log_fac; + int log_mask; +}; + +#define SYSLOG_DATA_INIT {-1, 0, 0, 0, NULL, LOG_USER, 0xff} .Sh DESCRIPTION The .Fn syslog @@ -76,6 +104,39 @@ see A trailing newline is added if none is present. .Pp The +.Fn syslog_r +function is a reentrant version of the +.Xr syslog 3 +function. It takes a pointer to a +.Fa syslog_data +structure which is used to store +information. This parameter must be initialized before +.Fn syslog_r +is called. The SYSLOG_DATA_INIT constant is used for this purpose. +The +.Fa syslog_data +structure is composed of the following elements: +.Bl -tag -width connected +.It Dv log_file +contains the file descriptor of the file where the message is logged. +.It Dv connected +indicates if connect has been done +.It Dv opened +indicates if +.Xr openlog_r 3 +has been called. +.It Dv log_stat +status bits, set by +.Xr openlog_r 3 +.It Dv log_tag +string to tag the entry with +.It Dv log_fac +facility code +.It Dv log_mask +mask of priorities to be logged +.El +.Pp +The .Fn vsyslog function is an alternate form in which the arguments have already been captured using the variable-length argument facilities of @@ -116,6 +177,16 @@ normally of use only when debugging a program. .El .Pp The +.Fn vsyslog_r +is used the same way than +.Fn vsyslog +except than it takes an additional pointer on a +.Fa syslog_data +structure. It is a reentrant version of the +.Fn vsyslog +function described above. +.Pp +The .Fn openlog function provides for more specialized processing of the messages sent by .Fn syslog @@ -210,8 +281,22 @@ through .El .Pp The +.Fn openlog_r +function is the reentrant version of the +.Fn openlog +function. It takes an additional pointer on a +.Fa syslog_data +structure. This function must be used in conjunction with the other +reentrant functions. +.Pp +The .Fn closelog -function can be used to close the log file. +function can be used to close the log file. +.Fn closelog_r +do the same thing but in a reentrant way and takes an additional +pointer on a +.Fa syslog_data +structure. .Pp The .Fn setlogmask @@ -232,18 +317,32 @@ the mask for all priorities up to and including is given by the macro .Fn LOG_UPTO toppri ; . The default allows all priorities to be logged. +.Pp +The +.Fn setlogmask_r +function is the reentrant version of +.Fn setlogmask . +It takes an additional pointer on a +.Fa syslog_data +structure. .Sh RETURN VALUES The .Fn closelog , +.Fn closelog_r , .Fn openlog , +.Fn openlog_r , .Fn syslog , -and +.Fn syslog_r , .Fn vsyslog +and +.Fn vsyslog_r functions return no value. .Pp -The routine +The routines .Fn setlogmask -always returns the previous log mask level. +and +.Fn setlogmask_r +always return the previous log mask level. .Sh EXAMPLES .Bd -literal -offset indent -compact syslog(LOG_ALERT, "who: internal error 23"); @@ -263,6 +362,8 @@ syslog(LOG_INFO|LOG_LOCAL2, "foobar error: %m"); These functions appeared in .Bx 4.2 . +The reentrant functions appeared in +.Ox 3.1 . .Sh CAVEATS It is important never to pass a string with user-supplied data as a format without using diff --git a/lib/libc/gen/syslog.c b/lib/libc/gen/syslog.c index fa6b9511921..beabbcce9ba 100644 --- a/lib/libc/gen/syslog.c +++ b/lib/libc/gen/syslog.c @@ -32,7 +32,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$OpenBSD: syslog.c,v 1.11 2001/08/18 22:56:22 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: syslog.c,v 1.12 2001/10/24 08:16:42 jjbg Exp $"; #endif /* LIBC_SCCS and not lint */ #include @@ -56,17 +56,15 @@ static char rcsid[] = "$OpenBSD: syslog.c,v 1.11 2001/08/18 22:56:22 deraadt Exp #include #endif -static int LogFile = -1; /* fd for log */ -static int connected; /* have done connect */ -static int opened; /* have done openlog() */ -static int LogStat = 0; /* status bits, set by openlog() */ -static const char *LogTag = NULL; /* string to tag the entry with */ -static int LogFacility = LOG_USER; /* default facility code */ -static int LogMask = 0xff; /* mask of priorities to be logged */ +static struct syslog_data sdata = SYSLOG_DATA_INIT; + extern char *__progname; /* Program name, from crt0. */ static void disconnectlog __P((void)); /* disconnect from syslogd */ static void connectlog __P((void)); /* (re)connect to syslogd */ +static void disconnectlog_r __P((struct syslog_data *)); +static void connectlog_r __P((struct syslog_data *)); + /* * syslog, vsyslog -- * print message on log file; output is intended for syslogd(8). @@ -98,8 +96,76 @@ vsyslog(pri, fmt, ap) register const char *fmt; va_list ap; { - register int cnt; - register char ch, *p, *t; + vsyslog_r(pri, &sdata, fmt, ap); +} + +static void +disconnectlog() +{ + disconnectlog_r(&sdata); +} + +static void +connectlog() +{ + connectlog_r(&sdata); +} + +void +openlog(ident, logstat, logfac) + const char *ident; + int logstat, logfac; +{ + openlog_r(ident, logstat, logfac, &sdata); +} + +void +closelog() +{ + closelog_r(&sdata); +} + +/* setlogmask -- set the log mask level */ +int +setlogmask(pmask) + int pmask; +{ + return setlogmask_r(pmask, &sdata); +} + +/* Reentrant version of syslog, i.e. syslog_r() */ + +void +#ifdef __STDC__ +syslog_r(int pri, struct syslog_data *data, const char *fmt, ...) +#else +syslog_r(pri, data, fmt, va_alist) + int pri; + struct syslog_data *data; + char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vsyslog_r(pri, data, fmt, ap); + va_end(ap); +} + +void +vsyslog_r(pri, data, fmt, ap) + int pri; + struct syslog_data *data; + const char *fmt; + va_list ap; +{ + int cnt; + char ch, *p, *t; time_t now; int fd, saved_errno; #define TBUF_LEN 2048 @@ -110,65 +176,64 @@ vsyslog(pri, fmt, ap) #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { - syslog(INTERNALLOG, - "syslog: unknown facility/priority: %x", pri); + if (data == &sdata) { + syslog(INTERNALLOG, + "syslog: unknown facility/priority: %x", pri); + } else { + syslog_r(INTERNALLOG, data, + "syslog_r: unknown facility/priority: %x", pri); + } pri &= LOG_PRIMASK|LOG_FACMASK; } /* Check priority against setlogmask values. */ - if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) + if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask)) return; saved_errno = errno; - /* Set default facility if none specified. */ - if ((pri & LOG_FACMASK) == 0) - pri |= LogFacility; + /* If we have been called through syslog(), no need for reentrancy. */ + if (data == &sdata) + (void)time(&now); + + p = tbuf; + tbuf_left = TBUF_LEN; + +#define DEC() \ + do { \ + if (prlen < 0) \ + prlen = 0; \ + if (prlen >= tbuf_left) \ + prlen = tbuf_left - 1; \ + p += prlen; \ + tbuf_left -= prlen; \ + } while (0) + + prlen = snprintf(p, tbuf_left, "<%d>", pri); + DEC(); - /* Build the message. */ - - /* - * Although it's tempting, we can't ignore the possibility of - * overflowing the buffer when assembling the "fixed" portion - * of the message. Strftime's "%h" directive expands to the - * locale's abbreviated month name, but if the user has the - * ability to construct to his own locale files, it may be - * arbitrarily long. + /* + * syslogd will expand time automagically for reentrant case, and + * for normal case, just do like before */ - (void)time(&now); - - p = tbuf; - tbuf_left = TBUF_LEN; - -#define DEC() \ - do { \ - if (prlen < 0) \ - prlen = 0; \ - else if (prlen >= tbuf_left) \ - prlen = tbuf_left - 1; \ - p += prlen; \ - tbuf_left -= prlen; \ - } while (0) - - prlen = snprintf(p, tbuf_left, "<%d>", pri); - DEC(); - - prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now)); - DEC(); + if (data == &sdata) { + prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now)); + DEC(); + } - if (LogStat & LOG_PERROR) + if (data->log_stat & LOG_PERROR) stdp = p; - if (LogTag == NULL) - LogTag = __progname; - if (LogTag != NULL) { - prlen = snprintf(p, tbuf_left, "%s", LogTag); + if (data->log_tag == NULL) + data->log_tag = __progname; + if (data->log_tag != NULL) { + prlen = snprintf(p, tbuf_left, "%s", data->log_tag); DEC(); } - if (LogStat & LOG_PID) { + if (data->log_stat & LOG_PID) { prlen = snprintf(p, tbuf_left, "[%d]", getpid()); DEC(); } - if (LogTag != NULL) { + if (data->log_tag != NULL) { if (tbuf_left > 1) { *p++ = ':'; tbuf_left--; @@ -179,15 +244,18 @@ vsyslog(pri, fmt, ap) } } - /* - * We wouldn't need this mess if printf handled %m, or if - * strerror() had been invented before syslog(). - */ + /* strerror() is not reentrant */ + for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) { if (ch == '%' && fmt[1] == 'm') { ++fmt; - prlen = snprintf(t, fmt_left, "%s", - strerror(saved_errno)); + if (data == &sdata) { + prlen = snprintf(t, fmt_left, "%s", + strerror(saved_errno)); + } else { + prlen = snprintf(t, fmt_left, "Error %d", + saved_errno); + } if (prlen >= fmt_left) prlen = fmt_left - 1; t += prlen; @@ -206,7 +274,7 @@ vsyslog(pri, fmt, ap) cnt = p - tbuf; /* Output to stderr if requested. */ - if (LogStat & LOG_PERROR) { + if (data->log_stat & LOG_PERROR) { struct iovec iov[2]; iov[0].iov_base = stdp; @@ -217,19 +285,19 @@ vsyslog(pri, fmt, ap) } /* Get connected, output the message to the local logger. */ - if (!opened) - openlog(LogTag, LogStat, 0); - connectlog(); - if (send(LogFile, tbuf, cnt, 0) >= 0) + if (!data->opened) + openlog_r(data->log_tag, data->log_stat, 0, data); + connectlog_r(data); + if (send(data->log_file, tbuf, cnt, 0) >= 0) return; /* * If the send() failed, the odds are syslogd was restarted. * Make one (only) attempt to reconnect to /dev/log. */ - disconnectlog(); - connectlog(); - if (send(LogFile, tbuf, cnt, 0) >= 0) + disconnectlog_r(data); + connectlog_r(data); + if (send(data->log_file, tbuf, cnt, 0) >= 0) return; /* @@ -237,7 +305,7 @@ vsyslog(pri, fmt, ap) * if console blocks everything will. Make sure the error reported * is the one from the syslogd failure. */ - if (LogStat & LOG_CONS && + if (data->log_stat & LOG_CONS && (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) { struct iovec iov[2]; @@ -252,79 +320,84 @@ vsyslog(pri, fmt, ap) } static void -disconnectlog() +disconnectlog_r(data) + struct syslog_data *data; { /* * If the user closed the FD and opened another in the same slot, * that's their problem. They should close it before calling on * system services. */ - if (LogFile != -1) { - close(LogFile); - LogFile = -1; + if (data->log_file != -1) { + close(data->log_file); + data->log_file = -1; } - connected = 0; /* retry connect */ + data->connected = 0; /* retry connect */ } static void -connectlog() +connectlog_r(data) + struct syslog_data *data; { struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ - if (LogFile == -1) { - if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) + if (data->log_file == -1) { + if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) return; - (void)fcntl(LogFile, F_SETFD, 1); + (void)fcntl(data->log_file, F_SETFD, 1); } - if (LogFile != -1 && !connected) { + if (data->log_file != -1 && !data->connected) { memset(&SyslogAddr, '\0', sizeof(SyslogAddr)); SyslogAddr.sun_len = sizeof(SyslogAddr); SyslogAddr.sun_family = AF_UNIX; strlcpy(SyslogAddr.sun_path, _PATH_LOG, sizeof(SyslogAddr.sun_path)); - if (connect(LogFile, (struct sockaddr *)&SyslogAddr, + if (connect(data->log_file, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr)) == -1) { - (void)close(LogFile); - LogFile = -1; + (void)close(data->log_file); + data->log_file = -1; } else - connected = 1; + data->connected = 1; } } void -openlog(ident, logstat, logfac) +openlog_r(ident, logstat, logfac, data) const char *ident; int logstat, logfac; + struct syslog_data *data; { if (ident != NULL) - LogTag = ident; - LogStat = logstat; + data->log_tag = ident; + data->log_stat = logstat; if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) - LogFacility = logfac; + data->log_fac = logfac; - if (LogStat & LOG_NDELAY) /* open immediately */ - connectlog(); + if (data->log_stat & LOG_NDELAY) /* open immediately */ + connectlog_r(data); - opened = 1; /* ident and facility has been set */ + data->opened = 1; /* ident and facility has been set */ } void -closelog() +closelog_r(data) + struct syslog_data *data; { - (void)close(LogFile); - LogFile = -1; - connected = 0; + (void)close(data->log_file); + data->log_file = -1; + data->connected = 0; } /* setlogmask -- set the log mask level */ int -setlogmask(pmask) +setlogmask_r(pmask, data) int pmask; + struct syslog_data *data; { int omask; - omask = LogMask; + omask = data->log_mask; if (pmask != 0) - LogMask = pmask; + data->log_mask = pmask; return (omask); } -- cgit v1.2.3