17c478bd9Sstevel@tonic-gate /* 2*5d54f3d8Smuffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*5d54f3d8Smuffin * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 7*5d54f3d8Smuffin * Copyright (c) 1983 Regents of the University of California. 8*5d54f3d8Smuffin * All rights reserved. The Berkeley software License Agreement 9*5d54f3d8Smuffin * specifies the terms and conditions for redistribution. 107c478bd9Sstevel@tonic-gate */ 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 137c478bd9Sstevel@tonic-gate 147c478bd9Sstevel@tonic-gate /* 157c478bd9Sstevel@tonic-gate * SYSLOG -- print message on log file 167c478bd9Sstevel@tonic-gate * 177c478bd9Sstevel@tonic-gate * This routine looks a lot like printf, except that it 187c478bd9Sstevel@tonic-gate * outputs to the log file instead of the standard output. 197c478bd9Sstevel@tonic-gate * Also: 207c478bd9Sstevel@tonic-gate * adds a timestamp, 217c478bd9Sstevel@tonic-gate * prints the module name in front of the message, 227c478bd9Sstevel@tonic-gate * has some other formatting types (or will sometime), 237c478bd9Sstevel@tonic-gate * adds a newline on the end of the message. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * The output of this routine is intended to be read by /etc/syslogd. 267c478bd9Sstevel@tonic-gate * 277c478bd9Sstevel@tonic-gate * Author: Eric Allman 287c478bd9Sstevel@tonic-gate * Modified to use UNIX domain IPC by Ralph Campbell 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/socket.h> 337c478bd9Sstevel@tonic-gate #include <sys/file.h> 347c478bd9Sstevel@tonic-gate #include <sys/signal.h> 357c478bd9Sstevel@tonic-gate #include <sys/syslog.h> 367c478bd9Sstevel@tonic-gate #include <sys/time.h> 37*5d54f3d8Smuffin #include <sys/unistd.h> 387c478bd9Sstevel@tonic-gate #include <netdb.h> 397c478bd9Sstevel@tonic-gate #include <strings.h> 40*5d54f3d8Smuffin #include <stdarg.h> 417c478bd9Sstevel@tonic-gate #include <vfork.h> 427c478bd9Sstevel@tonic-gate #include <stdio.h> 43*5d54f3d8Smuffin #include <errno.h> 44*5d54f3d8Smuffin #include <malloc.h> 45*5d54f3d8Smuffin 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #define MAXLINE 1024 /* max message size */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define PRIMASK(p) (1 << ((p) & LOG_PRIMASK)) 507c478bd9Sstevel@tonic-gate #define PRIFAC(p) (((p) & LOG_FACMASK) >> 3) 517c478bd9Sstevel@tonic-gate #define IMPORTANT LOG_ERR 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static char *logname = "/dev/log"; 547c478bd9Sstevel@tonic-gate static char *ctty = "/dev/console"; 557c478bd9Sstevel@tonic-gate static char *sysmsg = "/dev/sysmsg"; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static struct _syslog { 587c478bd9Sstevel@tonic-gate int _LogFile; 597c478bd9Sstevel@tonic-gate int _LogStat; 607c478bd9Sstevel@tonic-gate char *_LogTag; 617c478bd9Sstevel@tonic-gate int _LogMask; 627c478bd9Sstevel@tonic-gate struct sockaddr _SyslogAddr; 637c478bd9Sstevel@tonic-gate char *_SyslogHost; 647c478bd9Sstevel@tonic-gate int _LogFacility; 657c478bd9Sstevel@tonic-gate } *_syslog; 667c478bd9Sstevel@tonic-gate #define LogFile (_syslog->_LogFile) 677c478bd9Sstevel@tonic-gate #define LogStat (_syslog->_LogStat) 687c478bd9Sstevel@tonic-gate #define LogTag (_syslog->_LogTag) 697c478bd9Sstevel@tonic-gate #define LogMask (_syslog->_LogMask) 707c478bd9Sstevel@tonic-gate #define SyslogAddr (_syslog->_SyslogAddr) 717c478bd9Sstevel@tonic-gate #define SyslogHost (_syslog->_SyslogHost) 727c478bd9Sstevel@tonic-gate #define LogFacility (_syslog->_LogFacility) 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate extern char *strerror(int); 767c478bd9Sstevel@tonic-gate extern time_t time(); 77*5d54f3d8Smuffin 78*5d54f3d8Smuffin void vsyslog(int, char *, va_list); 79*5d54f3d8Smuffin void openlog(char *, int, int); 80*5d54f3d8Smuffin static int snprintf(char *, size_t, char *, ...); 81*5d54f3d8Smuffin static int vsnprintf(char *, size_t, char *, va_list ap); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static int 84*5d54f3d8Smuffin allocstatic(void) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate _syslog = (struct _syslog *)calloc(1, sizeof (struct _syslog)); 877c478bd9Sstevel@tonic-gate if (_syslog == 0) 887c478bd9Sstevel@tonic-gate return (0); /* can't do it */ 897c478bd9Sstevel@tonic-gate LogFile = -1; /* fd for log */ 907c478bd9Sstevel@tonic-gate LogStat = 0; /* status bits, set by openlog() */ 917c478bd9Sstevel@tonic-gate LogTag = "syslog"; /* string to tag the entry with */ 927c478bd9Sstevel@tonic-gate LogMask = 0xff; /* mask of priorities to be logged */ 937c478bd9Sstevel@tonic-gate LogFacility = LOG_USER; /* default facility code */ 947c478bd9Sstevel@tonic-gate return (1); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 97*5d54f3d8Smuffin void 98*5d54f3d8Smuffin syslog(int pri, char *fmt, ...) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate va_list ap; 1017c478bd9Sstevel@tonic-gate 102*5d54f3d8Smuffin va_start(ap, fmt); 1037c478bd9Sstevel@tonic-gate vsyslog(pri, fmt, ap); 1047c478bd9Sstevel@tonic-gate va_end(ap); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 107*5d54f3d8Smuffin void 108*5d54f3d8Smuffin vsyslog(int pri, char *fmt, va_list ap) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate char buf[MAXLINE + 1], outline[MAXLINE + 1]; 111*5d54f3d8Smuffin char *b, *f, *o; 112*5d54f3d8Smuffin int c; 1137c478bd9Sstevel@tonic-gate long now; 1147c478bd9Sstevel@tonic-gate int pid, olderrno = errno; 1157c478bd9Sstevel@tonic-gate int retsiz, outsiz = MAXLINE + 1; 1167c478bd9Sstevel@tonic-gate int taglen; 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * Maximum tag length is 256 (the pad in outline) minus the size of the 1197c478bd9Sstevel@tonic-gate * other things that can go in the pad. 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate #define MAX_TAG 230 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate if (_syslog == 0 && !allocstatic()) 1257c478bd9Sstevel@tonic-gate return; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* see if we should just throw out this message */ 1287c478bd9Sstevel@tonic-gate if (pri <= 0 || PRIFAC(pri) >= LOG_NFACILITIES || 1297c478bd9Sstevel@tonic-gate (PRIMASK(pri) & LogMask) == 0) 1307c478bd9Sstevel@tonic-gate return; 1317c478bd9Sstevel@tonic-gate if (LogFile < 0) 1327c478bd9Sstevel@tonic-gate openlog(LogTag, LogStat | LOG_NDELAY, 0); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* set default facility if none specified */ 1357c478bd9Sstevel@tonic-gate if ((pri & LOG_FACMASK) == 0) 1367c478bd9Sstevel@tonic-gate pri |= LogFacility; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* build the message */ 1397c478bd9Sstevel@tonic-gate o = outline; 1407c478bd9Sstevel@tonic-gate (void) time(&now); 1417c478bd9Sstevel@tonic-gate (void) sprintf(o, "<%d>%.15s ", pri, ctime(&now) + 4); 1427c478bd9Sstevel@tonic-gate o += strlen(o); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (LogTag) { 1457c478bd9Sstevel@tonic-gate taglen = strlen(LogTag) < MAX_TAG ? strlen(LogTag) : MAX_TAG; 1467c478bd9Sstevel@tonic-gate strncpy(o, LogTag, taglen); 1477c478bd9Sstevel@tonic-gate o[taglen] = '\0'; 1487c478bd9Sstevel@tonic-gate o += strlen(o); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate if (LogStat & LOG_PID) { 1517c478bd9Sstevel@tonic-gate (void) sprintf(o, "[%d]", getpid()); 1527c478bd9Sstevel@tonic-gate o += strlen(o); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate if (LogTag) { 1557c478bd9Sstevel@tonic-gate (void) strcpy(o, ": "); 1567c478bd9Sstevel@tonic-gate o += 2; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate b = buf; 1607c478bd9Sstevel@tonic-gate f = fmt; 1617c478bd9Sstevel@tonic-gate while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) { 1627c478bd9Sstevel@tonic-gate char *errstr; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if (c != '%') { 1657c478bd9Sstevel@tonic-gate *b++ = c; 1667c478bd9Sstevel@tonic-gate continue; 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate if ((c = *f++) != 'm') { 1697c478bd9Sstevel@tonic-gate *b++ = '%'; 1707c478bd9Sstevel@tonic-gate *b++ = c; 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate if ((errstr = strerror(olderrno)) == NULL) 1747c478bd9Sstevel@tonic-gate (void) snprintf(b, &buf[MAXLINE] - b, "error %d", 1757c478bd9Sstevel@tonic-gate olderrno); 1767c478bd9Sstevel@tonic-gate else { 1777c478bd9Sstevel@tonic-gate while (*errstr != '\0' && b < &buf[MAXLINE]) { 1787c478bd9Sstevel@tonic-gate if (*errstr == '%') { 1797c478bd9Sstevel@tonic-gate strcpy(b, "%%"); 1807c478bd9Sstevel@tonic-gate b += 2; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate else 1837c478bd9Sstevel@tonic-gate *b++ = *errstr; 1847c478bd9Sstevel@tonic-gate errstr++; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate *b = '\0'; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate b += strlen(b); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate if (b > buf && *(b-1) != '\n') /* ensure at least one newline */ 1917c478bd9Sstevel@tonic-gate *b++ = '\n'; 1927c478bd9Sstevel@tonic-gate *b = '\0'; 1937c478bd9Sstevel@tonic-gate (void) vsnprintf(o, &outline[sizeof (outline)] - o, buf, ap); 1947c478bd9Sstevel@tonic-gate c = strlen(outline) + 1; /* add one for NULL byte */ 1957c478bd9Sstevel@tonic-gate if (c > MAXLINE) { 1967c478bd9Sstevel@tonic-gate c = MAXLINE; 1977c478bd9Sstevel@tonic-gate outline[MAXLINE-1] = '\0'; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* output the message to the local logger */ 2017c478bd9Sstevel@tonic-gate if (sendto(LogFile, outline, c, 0, &SyslogAddr, 2027c478bd9Sstevel@tonic-gate sizeof (SyslogAddr)) >= 0) 2037c478bd9Sstevel@tonic-gate return; 2047c478bd9Sstevel@tonic-gate if (!(LogStat & LOG_CONS)) 2057c478bd9Sstevel@tonic-gate return; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* output the message to the console */ 2087c478bd9Sstevel@tonic-gate pid = vfork(); 2097c478bd9Sstevel@tonic-gate if (pid == -1) 2107c478bd9Sstevel@tonic-gate return; 2117c478bd9Sstevel@tonic-gate if (pid == 0) { 2127c478bd9Sstevel@tonic-gate int fd; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate (void) signal(SIGALRM, SIG_DFL); 2157c478bd9Sstevel@tonic-gate (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 2167c478bd9Sstevel@tonic-gate (void) alarm(5); 2177c478bd9Sstevel@tonic-gate if (((fd = open(sysmsg, O_WRONLY)) >= 0) || 2187c478bd9Sstevel@tonic-gate (fd = open(ctty, O_WRONLY)) >= 0) { 2197c478bd9Sstevel@tonic-gate (void) alarm(0); 2207c478bd9Sstevel@tonic-gate if (outsiz > 2) { /* Just in case */ 2217c478bd9Sstevel@tonic-gate (void) strcat(o, "\r\n"); 2227c478bd9Sstevel@tonic-gate c += 2; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate o = index(outline, '>') + 1; 2257c478bd9Sstevel@tonic-gate (void) write(fd, o, c - (o - outline)); 2267c478bd9Sstevel@tonic-gate (void) close(fd); 2277c478bd9Sstevel@tonic-gate } else 2287c478bd9Sstevel@tonic-gate (void) alarm(0); 2297c478bd9Sstevel@tonic-gate _exit(0); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate if (!(LogStat & LOG_NOWAIT)) 2327c478bd9Sstevel@tonic-gate while ((c = wait((int *)0)) > 0 && c != pid) 2337c478bd9Sstevel@tonic-gate ; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * OPENLOG -- open system log 2387c478bd9Sstevel@tonic-gate */ 239*5d54f3d8Smuffin void 240*5d54f3d8Smuffin openlog(char *ident, int logstat, int logfac) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate if (_syslog == 0 && !allocstatic()) 2437c478bd9Sstevel@tonic-gate return; 2447c478bd9Sstevel@tonic-gate if (ident != NULL) 2457c478bd9Sstevel@tonic-gate LogTag = ident; 2467c478bd9Sstevel@tonic-gate LogStat = logstat; 2477c478bd9Sstevel@tonic-gate if (logfac != 0) 2487c478bd9Sstevel@tonic-gate LogFacility = logfac & LOG_FACMASK; 2497c478bd9Sstevel@tonic-gate if (LogFile >= 0) 2507c478bd9Sstevel@tonic-gate return; 2517c478bd9Sstevel@tonic-gate SyslogAddr.sa_family = AF_UNIX; 2527c478bd9Sstevel@tonic-gate (void) strncpy(SyslogAddr.sa_data, logname, 2537c478bd9Sstevel@tonic-gate sizeof (SyslogAddr.sa_data)); 2547c478bd9Sstevel@tonic-gate if (LogStat & LOG_NDELAY) { 2557c478bd9Sstevel@tonic-gate LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); 2567c478bd9Sstevel@tonic-gate (void) fcntl(LogFile, F_SETFD, 1); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * CLOSELOG -- close the system log 2627c478bd9Sstevel@tonic-gate */ 263*5d54f3d8Smuffin void 264*5d54f3d8Smuffin closelog(void) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (_syslog == 0) 2687c478bd9Sstevel@tonic-gate return; 2697c478bd9Sstevel@tonic-gate (void) close(LogFile); 2707c478bd9Sstevel@tonic-gate LogFile = -1; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * SETLOGMASK -- set the log mask level 2757c478bd9Sstevel@tonic-gate */ 276*5d54f3d8Smuffin int 277*5d54f3d8Smuffin setlogmask(int pmask) 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate int omask; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate if (_syslog == 0 && !allocstatic()) 2827c478bd9Sstevel@tonic-gate return (-1); 2837c478bd9Sstevel@tonic-gate omask = LogMask; 2847c478bd9Sstevel@tonic-gate if (pmask != 0) 2857c478bd9Sstevel@tonic-gate LogMask = pmask; 2867c478bd9Sstevel@tonic-gate return (omask); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * snprintf/vsnprintf -- These routines are here 2917c478bd9Sstevel@tonic-gate * temporarily to solve bugid 1220257. Perhaps 2927c478bd9Sstevel@tonic-gate * they could become a public interface at some 2937c478bd9Sstevel@tonic-gate * point but not for now. 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate extern int _doprnt(); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate static int 299*5d54f3d8Smuffin snprintf(char *string, size_t n, char *format, ...) 3007c478bd9Sstevel@tonic-gate { 301*5d54f3d8Smuffin int count; 3027c478bd9Sstevel@tonic-gate FILE siop; 3037c478bd9Sstevel@tonic-gate va_list ap; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate if (n == 0) 3067c478bd9Sstevel@tonic-gate return (0); 3077c478bd9Sstevel@tonic-gate siop._cnt = n - 1; 3087c478bd9Sstevel@tonic-gate siop._base = siop._ptr = (unsigned char *)string; 3097c478bd9Sstevel@tonic-gate siop._flag = _IOWRT+_IOSTRG; 310*5d54f3d8Smuffin va_start(ap, format); 3117c478bd9Sstevel@tonic-gate count = _doprnt(format, ap, &siop); 3127c478bd9Sstevel@tonic-gate va_end(ap); 3137c478bd9Sstevel@tonic-gate *siop._ptr = '\0'; /* plant terminating null character */ 3147c478bd9Sstevel@tonic-gate return (count); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate static int 318*5d54f3d8Smuffin vsnprintf(char *string, size_t n, char *format, va_list ap) 3197c478bd9Sstevel@tonic-gate { 320*5d54f3d8Smuffin int count; 3217c478bd9Sstevel@tonic-gate FILE siop; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate if (n == 0) 3247c478bd9Sstevel@tonic-gate return (0); 3257c478bd9Sstevel@tonic-gate siop._cnt = n - 1; 3267c478bd9Sstevel@tonic-gate siop._base = siop._ptr = (unsigned char *)string; 3277c478bd9Sstevel@tonic-gate siop._flag = _IOWRT+_IOSTRG; 3287c478bd9Sstevel@tonic-gate count = _doprnt(format, ap, &siop); 3297c478bd9Sstevel@tonic-gate *siop._ptr = '\0'; /* plant terminating null character */ 3307c478bd9Sstevel@tonic-gate return (count); 3317c478bd9Sstevel@tonic-gate } 332