/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * SYSLOG -- print message on log file * * This routine looks a lot like printf, except that it * outputs to the log file instead of the standard output. * Also: * adds a timestamp, * prints the module name in front of the message, * has some other formatting types (or will sometime), * adds a newline on the end of the message. * * The output of this routine is intended to be read by /etc/syslogd. * * Author: Eric Allman * Modified to use UNIX domain IPC by Ralph Campbell */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXLINE 1024 /* max message size */ #define PRIMASK(p) (1 << ((p) & LOG_PRIMASK)) #define PRIFAC(p) (((p) & LOG_FACMASK) >> 3) #define IMPORTANT LOG_ERR static char *logname = "/dev/log"; static char *ctty = "/dev/console"; static char *sysmsg = "/dev/sysmsg"; static struct _syslog { int _LogFile; int _LogStat; char *_LogTag; int _LogMask; struct sockaddr _SyslogAddr; char *_SyslogHost; int _LogFacility; } *_syslog; #define LogFile (_syslog->_LogFile) #define LogStat (_syslog->_LogStat) #define LogTag (_syslog->_LogTag) #define LogMask (_syslog->_LogMask) #define SyslogAddr (_syslog->_SyslogAddr) #define SyslogHost (_syslog->_SyslogHost) #define LogFacility (_syslog->_LogFacility) extern char *strerror(int); extern time_t time(); void vsyslog(int, char *, va_list); void openlog(char *, int, int); static int snprintf(char *, size_t, char *, ...); static int vsnprintf(char *, size_t, char *, va_list ap); static int allocstatic(void) { _syslog = (struct _syslog *)calloc(1, sizeof (struct _syslog)); if (_syslog == 0) return (0); /* can't do it */ LogFile = -1; /* fd for log */ LogStat = 0; /* status bits, set by openlog() */ LogTag = "syslog"; /* string to tag the entry with */ LogMask = 0xff; /* mask of priorities to be logged */ LogFacility = LOG_USER; /* default facility code */ return (1); } void syslog(int pri, char *fmt, ...) { va_list ap; va_start(ap, fmt); vsyslog(pri, fmt, ap); va_end(ap); } void vsyslog(int pri, char *fmt, va_list ap) { char buf[MAXLINE + 1], outline[MAXLINE + 1]; char *b, *f, *o; int c; long now; int pid, olderrno = errno; int retsiz, outsiz = MAXLINE + 1; int taglen; /* * Maximum tag length is 256 (the pad in outline) minus the size of the * other things that can go in the pad. */ #define MAX_TAG 230 if (_syslog == 0 && !allocstatic()) return; /* see if we should just throw out this message */ if (pri <= 0 || PRIFAC(pri) >= LOG_NFACILITIES || (PRIMASK(pri) & LogMask) == 0) return; if (LogFile < 0) openlog(LogTag, LogStat | LOG_NDELAY, 0); /* set default facility if none specified */ if ((pri & LOG_FACMASK) == 0) pri |= LogFacility; /* build the message */ o = outline; (void) time(&now); (void) sprintf(o, "<%d>%.15s ", pri, ctime(&now) + 4); o += strlen(o); if (LogTag) { taglen = strlen(LogTag) < MAX_TAG ? strlen(LogTag) : MAX_TAG; strncpy(o, LogTag, taglen); o[taglen] = '\0'; o += strlen(o); } if (LogStat & LOG_PID) { (void) sprintf(o, "[%d]", getpid()); o += strlen(o); } if (LogTag) { (void) strcpy(o, ": "); o += 2; } b = buf; f = fmt; while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) { char *errstr; if (c != '%') { *b++ = c; continue; } if ((c = *f++) != 'm') { *b++ = '%'; *b++ = c; continue; } if ((errstr = strerror(olderrno)) == NULL) (void) snprintf(b, &buf[MAXLINE] - b, "error %d", olderrno); else { while (*errstr != '\0' && b < &buf[MAXLINE]) { if (*errstr == '%') { strcpy(b, "%%"); b += 2; } else *b++ = *errstr; errstr++; } *b = '\0'; } b += strlen(b); } if (b > buf && *(b-1) != '\n') /* ensure at least one newline */ *b++ = '\n'; *b = '\0'; (void) vsnprintf(o, &outline[sizeof (outline)] - o, buf, ap); c = strlen(outline) + 1; /* add one for NULL byte */ if (c > MAXLINE) { c = MAXLINE; outline[MAXLINE-1] = '\0'; } /* output the message to the local logger */ if (sendto(LogFile, outline, c, 0, &SyslogAddr, sizeof (SyslogAddr)) >= 0) return; if (!(LogStat & LOG_CONS)) return; /* output the message to the console */ pid = vfork(); if (pid == -1) return; if (pid == 0) { int fd; (void) signal(SIGALRM, SIG_DFL); (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); (void) alarm(5); if (((fd = open(sysmsg, O_WRONLY)) >= 0) || (fd = open(ctty, O_WRONLY)) >= 0) { (void) alarm(0); if (outsiz > 2) { /* Just in case */ (void) strcat(o, "\r\n"); c += 2; } o = index(outline, '>') + 1; (void) write(fd, o, c - (o - outline)); (void) close(fd); } else (void) alarm(0); _exit(0); } if (!(LogStat & LOG_NOWAIT)) while ((c = wait((int *)0)) > 0 && c != pid) ; } /* * OPENLOG -- open system log */ void openlog(char *ident, int logstat, int logfac) { if (_syslog == 0 && !allocstatic()) return; if (ident != NULL) LogTag = ident; LogStat = logstat; if (logfac != 0) LogFacility = logfac & LOG_FACMASK; if (LogFile >= 0) return; SyslogAddr.sa_family = AF_UNIX; (void) strncpy(SyslogAddr.sa_data, logname, sizeof (SyslogAddr.sa_data)); if (LogStat & LOG_NDELAY) { LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); (void) fcntl(LogFile, F_SETFD, 1); } } /* * CLOSELOG -- close the system log */ void closelog(void) { if (_syslog == 0) return; (void) close(LogFile); LogFile = -1; } /* * SETLOGMASK -- set the log mask level */ int setlogmask(int pmask) { int omask; if (_syslog == 0 && !allocstatic()) return (-1); omask = LogMask; if (pmask != 0) LogMask = pmask; return (omask); } /* * snprintf/vsnprintf -- These routines are here * temporarily to solve bugid 1220257. Perhaps * they could become a public interface at some * point but not for now. */ extern int _doprnt(); static int snprintf(char *string, size_t n, char *format, ...) { int count; FILE siop; va_list ap; if (n == 0) return (0); siop._cnt = n - 1; siop._base = siop._ptr = (unsigned char *)string; siop._flag = _IOWRT+_IOSTRG; va_start(ap, format); count = _doprnt(format, ap, &siop); va_end(ap); *siop._ptr = '\0'; /* plant terminating null character */ return (count); } static int vsnprintf(char *string, size_t n, char *format, va_list ap) { int count; FILE siop; if (n == 0) return (0); siop._cnt = n - 1; siop._base = siop._ptr = (unsigned char *)string; siop._flag = _IOWRT+_IOSTRG; count = _doprnt(format, ap, &siop); *siop._ptr = '\0'; /* plant terminating null character */ return (count); }