Make syslog(3) thread safe.

PR:		bin/72394
Submitted by:	Dan Nelson
Reviewed by:	deischen
MFC after:	2 weeks
This commit is contained in:
Gleb Smirnoff 2004-12-30 16:05:11 +00:00
parent a0ede505d3
commit 9657520621

View File

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <paths.h> #include <paths.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -66,9 +67,20 @@ static int LogStat = 0; /* status bits, set by openlog() */
static const char *LogTag = NULL; /* string to tag the entry with */ static const char *LogTag = NULL; /* string to tag the entry with */
static int LogFacility = LOG_USER; /* default facility code */ static int LogFacility = LOG_USER; /* default facility code */
static int LogMask = 0xff; /* mask of priorities to be logged */ static int LogMask = 0xff; /* mask of priorities to be logged */
static pthread_mutex_t syslog_mutex = PTHREAD_MUTEX_INITIALIZER;
#define THREAD_LOCK() \
do { \
if (__isthreaded) _pthread_mutex_lock(&syslog_mutex); \
} while(0)
#define THREAD_UNLOCK() \
do { \
if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex); \
} while(0)
static void disconnectlog(void); /* disconnect from syslogd */ static void disconnectlog(void); /* disconnect from syslogd */
static void connectlog(void); /* (re)connect to syslogd */ static void connectlog(void); /* (re)connect to syslogd */
static void openlog_unlocked(const char *, int, int);
enum { enum {
NOCONN = 0, NOCONN = 0,
@ -134,7 +146,7 @@ vsyslog(pri, fmt, ap)
char ch, *p; char ch, *p;
time_t now; time_t now;
int fd, saved_errno; int fd, saved_errno;
char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26]; char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26], errstr[64];
FILE *fp, *fmt_fp; FILE *fp, *fmt_fp;
struct bufcookie tbuf_cookie; struct bufcookie tbuf_cookie;
struct bufcookie fmt_cookie; struct bufcookie fmt_cookie;
@ -147,9 +159,13 @@ vsyslog(pri, fmt, ap)
pri &= LOG_PRIMASK|LOG_FACMASK; pri &= LOG_PRIMASK|LOG_FACMASK;
} }
THREAD_LOCK();
/* Check priority against setlogmask values. */ /* Check priority against setlogmask values. */
if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) {
THREAD_UNLOCK();
return; return;
}
saved_errno = errno; saved_errno = errno;
@ -161,8 +177,10 @@ vsyslog(pri, fmt, ap)
tbuf_cookie.base = tbuf; tbuf_cookie.base = tbuf;
tbuf_cookie.left = sizeof(tbuf); tbuf_cookie.left = sizeof(tbuf);
fp = fwopen(&tbuf_cookie, writehook); fp = fwopen(&tbuf_cookie, writehook);
if (fp == NULL) if (fp == NULL) {
THREAD_UNLOCK();
return; return;
}
/* Build the message. */ /* Build the message. */
(void)time(&now); (void)time(&now);
@ -192,6 +210,7 @@ vsyslog(pri, fmt, ap)
fmt_fp = fwopen(&fmt_cookie, writehook); fmt_fp = fwopen(&fmt_cookie, writehook);
if (fmt_fp == NULL) { if (fmt_fp == NULL) {
fclose(fp); fclose(fp);
THREAD_UNLOCK();
return; return;
} }
@ -203,7 +222,8 @@ vsyslog(pri, fmt, ap)
for ( ; (ch = *fmt); ++fmt) { for ( ; (ch = *fmt); ++fmt) {
if (ch == '%' && fmt[1] == 'm') { if (ch == '%' && fmt[1] == 'm') {
++fmt; ++fmt;
fputs(strerror(saved_errno), fmt_fp); strerror_r(saved_errno, errstr, sizeof(errstr));
fputs(errstr, fmt_fp);
} else if (ch == '%' && fmt[1] == '%') { } else if (ch == '%' && fmt[1] == '%') {
++fmt; ++fmt;
fputc(ch, fmt_fp); fputc(ch, fmt_fp);
@ -247,7 +267,7 @@ vsyslog(pri, fmt, ap)
/* Get connected, output the message to the local logger. */ /* Get connected, output the message to the local logger. */
if (!opened) if (!opened)
openlog(LogTag, LogStat | LOG_NDELAY, 0); openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0);
connectlog(); connectlog();
/* /*
@ -272,13 +292,17 @@ vsyslog(pri, fmt, ap)
} }
do { do {
usleep(1); usleep(1);
if (send(LogFile, tbuf, cnt, 0) >= 0) if (send(LogFile, tbuf, cnt, 0) >= 0) {
THREAD_UNLOCK();
return; return;
}
if (status == CONNPRIV) if (status == CONNPRIV)
break; break;
} while (errno == ENOBUFS); } while (errno == ENOBUFS);
} else } else {
THREAD_UNLOCK();
return; return;
}
/* /*
* Output the message to the console; try not to block * Output the message to the console; try not to block
@ -299,7 +323,11 @@ vsyslog(pri, fmt, ap)
(void)_writev(fd, iov, 2); (void)_writev(fd, iov, 2);
(void)_close(fd); (void)_close(fd);
} }
THREAD_UNLOCK();
} }
/* Should be called with mutex acquired */
static void static void
disconnectlog() disconnectlog()
{ {
@ -315,6 +343,7 @@ disconnectlog()
status = NOCONN; /* retry connect */ status = NOCONN; /* retry connect */
} }
/* Should be called with mutex acquired */
static void static void
connectlog() connectlog()
{ {
@ -366,8 +395,8 @@ connectlog()
} }
} }
void static void
openlog(ident, logstat, logfac) openlog_unlocked(ident, logstat, logfac)
const char *ident; const char *ident;
int logstat, logfac; int logstat, logfac;
{ {
@ -383,13 +412,26 @@ openlog(ident, logstat, logfac)
opened = 1; /* ident and facility has been set */ opened = 1; /* ident and facility has been set */
} }
void
openlog(ident, logstat, logfac)
const char *ident;
int logstat, logfac;
{
THREAD_LOCK();
openlog_unlocked(ident, logstat, logfac);
THREAD_UNLOCK();
}
void void
closelog() closelog()
{ {
THREAD_LOCK();
(void)_close(LogFile); (void)_close(LogFile);
LogFile = -1; LogFile = -1;
LogTag = NULL; LogTag = NULL;
status = NOCONN; status = NOCONN;
THREAD_UNLOCK();
} }
/* setlogmask -- set the log mask level */ /* setlogmask -- set the log mask level */
@ -399,8 +441,10 @@ setlogmask(pmask)
{ {
int omask; int omask;
THREAD_LOCK();
omask = LogMask; omask = LogMask;
if (pmask != 0) if (pmask != 0)
LogMask = pmask; LogMask = pmask;
THREAD_UNLOCK();
return (omask); return (omask);
} }