1*722Smuffin /*
2*722Smuffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3*722Smuffin * Use is subject to license terms.
4*722Smuffin */
5*722Smuffin
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
80Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
90Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
100Sstevel@tonic-gate */
110Sstevel@tonic-gate
120Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
130Sstevel@tonic-gate
140Sstevel@tonic-gate /*
150Sstevel@tonic-gate * SYSLOG -- print message on log file
160Sstevel@tonic-gate *
170Sstevel@tonic-gate * This routine looks a lot like printf, except that it
180Sstevel@tonic-gate * outputs to the log file instead of the standard output.
190Sstevel@tonic-gate * Also:
200Sstevel@tonic-gate * adds a timestamp,
210Sstevel@tonic-gate * prints the module name in front of the message,
220Sstevel@tonic-gate * has some other formatting types (or will sometime),
230Sstevel@tonic-gate * adds a newline on the end of the message.
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * The output of this routine is intended to be read by /etc/syslogd.
260Sstevel@tonic-gate *
270Sstevel@tonic-gate * Author: Eric Allman
280Sstevel@tonic-gate * Modified to use UNIX domain IPC by Ralph Campbell
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/socket.h>
330Sstevel@tonic-gate #include <sys/file.h>
340Sstevel@tonic-gate #include <sys/signal.h>
350Sstevel@tonic-gate #include <sys/syslog.h>
360Sstevel@tonic-gate #include <sys/time.h>
37*722Smuffin #include <sys/unistd.h>
380Sstevel@tonic-gate #include <netdb.h>
390Sstevel@tonic-gate #include <strings.h>
40*722Smuffin #include <stdarg.h>
410Sstevel@tonic-gate #include <vfork.h>
420Sstevel@tonic-gate #include <stdio.h>
43*722Smuffin #include <errno.h>
44*722Smuffin #include <malloc.h>
45*722Smuffin
460Sstevel@tonic-gate
470Sstevel@tonic-gate #define MAXLINE 1024 /* max message size */
480Sstevel@tonic-gate
490Sstevel@tonic-gate #define PRIMASK(p) (1 << ((p) & LOG_PRIMASK))
500Sstevel@tonic-gate #define PRIFAC(p) (((p) & LOG_FACMASK) >> 3)
510Sstevel@tonic-gate #define IMPORTANT LOG_ERR
520Sstevel@tonic-gate
530Sstevel@tonic-gate static char *logname = "/dev/log";
540Sstevel@tonic-gate static char *ctty = "/dev/console";
550Sstevel@tonic-gate static char *sysmsg = "/dev/sysmsg";
560Sstevel@tonic-gate
570Sstevel@tonic-gate static struct _syslog {
580Sstevel@tonic-gate int _LogFile;
590Sstevel@tonic-gate int _LogStat;
600Sstevel@tonic-gate char *_LogTag;
610Sstevel@tonic-gate int _LogMask;
620Sstevel@tonic-gate struct sockaddr _SyslogAddr;
630Sstevel@tonic-gate char *_SyslogHost;
640Sstevel@tonic-gate int _LogFacility;
650Sstevel@tonic-gate } *_syslog;
660Sstevel@tonic-gate #define LogFile (_syslog->_LogFile)
670Sstevel@tonic-gate #define LogStat (_syslog->_LogStat)
680Sstevel@tonic-gate #define LogTag (_syslog->_LogTag)
690Sstevel@tonic-gate #define LogMask (_syslog->_LogMask)
700Sstevel@tonic-gate #define SyslogAddr (_syslog->_SyslogAddr)
710Sstevel@tonic-gate #define SyslogHost (_syslog->_SyslogHost)
720Sstevel@tonic-gate #define LogFacility (_syslog->_LogFacility)
730Sstevel@tonic-gate
740Sstevel@tonic-gate
750Sstevel@tonic-gate extern char *strerror(int);
760Sstevel@tonic-gate extern time_t time();
77*722Smuffin
78*722Smuffin void vsyslog(int, char *, va_list);
79*722Smuffin void openlog(char *, int, int);
80*722Smuffin static int snprintf(char *, size_t, char *, ...);
81*722Smuffin static int vsnprintf(char *, size_t, char *, va_list ap);
820Sstevel@tonic-gate
830Sstevel@tonic-gate static int
allocstatic(void)84*722Smuffin allocstatic(void)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate _syslog = (struct _syslog *)calloc(1, sizeof (struct _syslog));
870Sstevel@tonic-gate if (_syslog == 0)
880Sstevel@tonic-gate return (0); /* can't do it */
890Sstevel@tonic-gate LogFile = -1; /* fd for log */
900Sstevel@tonic-gate LogStat = 0; /* status bits, set by openlog() */
910Sstevel@tonic-gate LogTag = "syslog"; /* string to tag the entry with */
920Sstevel@tonic-gate LogMask = 0xff; /* mask of priorities to be logged */
930Sstevel@tonic-gate LogFacility = LOG_USER; /* default facility code */
940Sstevel@tonic-gate return (1);
950Sstevel@tonic-gate }
960Sstevel@tonic-gate
97*722Smuffin void
syslog(int pri,char * fmt,...)98*722Smuffin syslog(int pri, char *fmt, ...)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate va_list ap;
1010Sstevel@tonic-gate
102*722Smuffin va_start(ap, fmt);
1030Sstevel@tonic-gate vsyslog(pri, fmt, ap);
1040Sstevel@tonic-gate va_end(ap);
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate
107*722Smuffin void
vsyslog(int pri,char * fmt,va_list ap)108*722Smuffin vsyslog(int pri, char *fmt, va_list ap)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate char buf[MAXLINE + 1], outline[MAXLINE + 1];
111*722Smuffin char *b, *f, *o;
112*722Smuffin int c;
1130Sstevel@tonic-gate long now;
1140Sstevel@tonic-gate int pid, olderrno = errno;
1150Sstevel@tonic-gate int retsiz, outsiz = MAXLINE + 1;
1160Sstevel@tonic-gate int taglen;
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate * Maximum tag length is 256 (the pad in outline) minus the size of the
1190Sstevel@tonic-gate * other things that can go in the pad.
1200Sstevel@tonic-gate */
1210Sstevel@tonic-gate #define MAX_TAG 230
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate if (_syslog == 0 && !allocstatic())
1250Sstevel@tonic-gate return;
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate /* see if we should just throw out this message */
1280Sstevel@tonic-gate if (pri <= 0 || PRIFAC(pri) >= LOG_NFACILITIES ||
1290Sstevel@tonic-gate (PRIMASK(pri) & LogMask) == 0)
1300Sstevel@tonic-gate return;
1310Sstevel@tonic-gate if (LogFile < 0)
1320Sstevel@tonic-gate openlog(LogTag, LogStat | LOG_NDELAY, 0);
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /* set default facility if none specified */
1350Sstevel@tonic-gate if ((pri & LOG_FACMASK) == 0)
1360Sstevel@tonic-gate pri |= LogFacility;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /* build the message */
1390Sstevel@tonic-gate o = outline;
1400Sstevel@tonic-gate (void) time(&now);
1410Sstevel@tonic-gate (void) sprintf(o, "<%d>%.15s ", pri, ctime(&now) + 4);
1420Sstevel@tonic-gate o += strlen(o);
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate if (LogTag) {
1450Sstevel@tonic-gate taglen = strlen(LogTag) < MAX_TAG ? strlen(LogTag) : MAX_TAG;
1460Sstevel@tonic-gate strncpy(o, LogTag, taglen);
1470Sstevel@tonic-gate o[taglen] = '\0';
1480Sstevel@tonic-gate o += strlen(o);
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate if (LogStat & LOG_PID) {
1510Sstevel@tonic-gate (void) sprintf(o, "[%d]", getpid());
1520Sstevel@tonic-gate o += strlen(o);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate if (LogTag) {
1550Sstevel@tonic-gate (void) strcpy(o, ": ");
1560Sstevel@tonic-gate o += 2;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate b = buf;
1600Sstevel@tonic-gate f = fmt;
1610Sstevel@tonic-gate while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) {
1620Sstevel@tonic-gate char *errstr;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (c != '%') {
1650Sstevel@tonic-gate *b++ = c;
1660Sstevel@tonic-gate continue;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate if ((c = *f++) != 'm') {
1690Sstevel@tonic-gate *b++ = '%';
1700Sstevel@tonic-gate *b++ = c;
1710Sstevel@tonic-gate continue;
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate if ((errstr = strerror(olderrno)) == NULL)
1740Sstevel@tonic-gate (void) snprintf(b, &buf[MAXLINE] - b, "error %d",
1750Sstevel@tonic-gate olderrno);
1760Sstevel@tonic-gate else {
1770Sstevel@tonic-gate while (*errstr != '\0' && b < &buf[MAXLINE]) {
1780Sstevel@tonic-gate if (*errstr == '%') {
1790Sstevel@tonic-gate strcpy(b, "%%");
1800Sstevel@tonic-gate b += 2;
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate else
1830Sstevel@tonic-gate *b++ = *errstr;
1840Sstevel@tonic-gate errstr++;
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate *b = '\0';
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate b += strlen(b);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate if (b > buf && *(b-1) != '\n') /* ensure at least one newline */
1910Sstevel@tonic-gate *b++ = '\n';
1920Sstevel@tonic-gate *b = '\0';
1930Sstevel@tonic-gate (void) vsnprintf(o, &outline[sizeof (outline)] - o, buf, ap);
1940Sstevel@tonic-gate c = strlen(outline) + 1; /* add one for NULL byte */
1950Sstevel@tonic-gate if (c > MAXLINE) {
1960Sstevel@tonic-gate c = MAXLINE;
1970Sstevel@tonic-gate outline[MAXLINE-1] = '\0';
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate /* output the message to the local logger */
2010Sstevel@tonic-gate if (sendto(LogFile, outline, c, 0, &SyslogAddr,
2020Sstevel@tonic-gate sizeof (SyslogAddr)) >= 0)
2030Sstevel@tonic-gate return;
2040Sstevel@tonic-gate if (!(LogStat & LOG_CONS))
2050Sstevel@tonic-gate return;
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /* output the message to the console */
2080Sstevel@tonic-gate pid = vfork();
2090Sstevel@tonic-gate if (pid == -1)
2100Sstevel@tonic-gate return;
2110Sstevel@tonic-gate if (pid == 0) {
2120Sstevel@tonic-gate int fd;
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate (void) signal(SIGALRM, SIG_DFL);
2150Sstevel@tonic-gate (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM));
2160Sstevel@tonic-gate (void) alarm(5);
2170Sstevel@tonic-gate if (((fd = open(sysmsg, O_WRONLY)) >= 0) ||
2180Sstevel@tonic-gate (fd = open(ctty, O_WRONLY)) >= 0) {
2190Sstevel@tonic-gate (void) alarm(0);
2200Sstevel@tonic-gate if (outsiz > 2) { /* Just in case */
2210Sstevel@tonic-gate (void) strcat(o, "\r\n");
2220Sstevel@tonic-gate c += 2;
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate o = index(outline, '>') + 1;
2250Sstevel@tonic-gate (void) write(fd, o, c - (o - outline));
2260Sstevel@tonic-gate (void) close(fd);
2270Sstevel@tonic-gate } else
2280Sstevel@tonic-gate (void) alarm(0);
2290Sstevel@tonic-gate _exit(0);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate if (!(LogStat & LOG_NOWAIT))
2320Sstevel@tonic-gate while ((c = wait((int *)0)) > 0 && c != pid)
2330Sstevel@tonic-gate ;
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate * OPENLOG -- open system log
2380Sstevel@tonic-gate */
239*722Smuffin void
openlog(char * ident,int logstat,int logfac)240*722Smuffin openlog(char *ident, int logstat, int logfac)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate if (_syslog == 0 && !allocstatic())
2430Sstevel@tonic-gate return;
2440Sstevel@tonic-gate if (ident != NULL)
2450Sstevel@tonic-gate LogTag = ident;
2460Sstevel@tonic-gate LogStat = logstat;
2470Sstevel@tonic-gate if (logfac != 0)
2480Sstevel@tonic-gate LogFacility = logfac & LOG_FACMASK;
2490Sstevel@tonic-gate if (LogFile >= 0)
2500Sstevel@tonic-gate return;
2510Sstevel@tonic-gate SyslogAddr.sa_family = AF_UNIX;
2520Sstevel@tonic-gate (void) strncpy(SyslogAddr.sa_data, logname,
2530Sstevel@tonic-gate sizeof (SyslogAddr.sa_data));
2540Sstevel@tonic-gate if (LogStat & LOG_NDELAY) {
2550Sstevel@tonic-gate LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
2560Sstevel@tonic-gate (void) fcntl(LogFile, F_SETFD, 1);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate /*
2610Sstevel@tonic-gate * CLOSELOG -- close the system log
2620Sstevel@tonic-gate */
263*722Smuffin void
closelog(void)264*722Smuffin closelog(void)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate if (_syslog == 0)
2680Sstevel@tonic-gate return;
2690Sstevel@tonic-gate (void) close(LogFile);
2700Sstevel@tonic-gate LogFile = -1;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate * SETLOGMASK -- set the log mask level
2750Sstevel@tonic-gate */
276*722Smuffin int
setlogmask(int pmask)277*722Smuffin setlogmask(int pmask)
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate int omask;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate if (_syslog == 0 && !allocstatic())
2820Sstevel@tonic-gate return (-1);
2830Sstevel@tonic-gate omask = LogMask;
2840Sstevel@tonic-gate if (pmask != 0)
2850Sstevel@tonic-gate LogMask = pmask;
2860Sstevel@tonic-gate return (omask);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * snprintf/vsnprintf -- These routines are here
2910Sstevel@tonic-gate * temporarily to solve bugid 1220257. Perhaps
2920Sstevel@tonic-gate * they could become a public interface at some
2930Sstevel@tonic-gate * point but not for now.
2940Sstevel@tonic-gate */
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate extern int _doprnt();
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate static int
snprintf(char * string,size_t n,char * format,...)299*722Smuffin snprintf(char *string, size_t n, char *format, ...)
3000Sstevel@tonic-gate {
301*722Smuffin int count;
3020Sstevel@tonic-gate FILE siop;
3030Sstevel@tonic-gate va_list ap;
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate if (n == 0)
3060Sstevel@tonic-gate return (0);
3070Sstevel@tonic-gate siop._cnt = n - 1;
3080Sstevel@tonic-gate siop._base = siop._ptr = (unsigned char *)string;
3090Sstevel@tonic-gate siop._flag = _IOWRT+_IOSTRG;
310*722Smuffin va_start(ap, format);
3110Sstevel@tonic-gate count = _doprnt(format, ap, &siop);
3120Sstevel@tonic-gate va_end(ap);
3130Sstevel@tonic-gate *siop._ptr = '\0'; /* plant terminating null character */
3140Sstevel@tonic-gate return (count);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate static int
vsnprintf(char * string,size_t n,char * format,va_list ap)318*722Smuffin vsnprintf(char *string, size_t n, char *format, va_list ap)
3190Sstevel@tonic-gate {
320*722Smuffin int count;
3210Sstevel@tonic-gate FILE siop;
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate if (n == 0)
3240Sstevel@tonic-gate return (0);
3250Sstevel@tonic-gate siop._cnt = n - 1;
3260Sstevel@tonic-gate siop._base = siop._ptr = (unsigned char *)string;
3270Sstevel@tonic-gate siop._flag = _IOWRT+_IOSTRG;
3280Sstevel@tonic-gate count = _doprnt(format, ap, &siop);
3290Sstevel@tonic-gate *siop._ptr = '\0'; /* plant terminating null character */
3300Sstevel@tonic-gate return (count);
3310Sstevel@tonic-gate }
332