1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1983 Regents of the University of California. 8 * All rights reserved. The Berkeley software License Agreement 9 * specifies the terms and conditions for redistribution. 10 */ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 13 14 /* 15 * SYSLOG -- print message on log file 16 * 17 * This routine looks a lot like printf, except that it 18 * outputs to the log file instead of the standard output. 19 * Also: 20 * adds a timestamp, 21 * prints the module name in front of the message, 22 * has some other formatting types (or will sometime), 23 * adds a newline on the end of the message. 24 * 25 * The output of this routine is intended to be read by /etc/syslogd. 26 * 27 * Author: Eric Allman 28 * Modified to use UNIX domain IPC by Ralph Campbell 29 */ 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <sys/file.h> 34 #include <sys/signal.h> 35 #include <sys/syslog.h> 36 #include <sys/time.h> 37 #include <sys/unistd.h> 38 #include <netdb.h> 39 #include <strings.h> 40 #include <stdarg.h> 41 #include <vfork.h> 42 #include <stdio.h> 43 #include <errno.h> 44 #include <malloc.h> 45 46 47 #define MAXLINE 1024 /* max message size */ 48 49 #define PRIMASK(p) (1 << ((p) & LOG_PRIMASK)) 50 #define PRIFAC(p) (((p) & LOG_FACMASK) >> 3) 51 #define IMPORTANT LOG_ERR 52 53 static char *logname = "/dev/log"; 54 static char *ctty = "/dev/console"; 55 static char *sysmsg = "/dev/sysmsg"; 56 57 static struct _syslog { 58 int _LogFile; 59 int _LogStat; 60 char *_LogTag; 61 int _LogMask; 62 struct sockaddr _SyslogAddr; 63 char *_SyslogHost; 64 int _LogFacility; 65 } *_syslog; 66 #define LogFile (_syslog->_LogFile) 67 #define LogStat (_syslog->_LogStat) 68 #define LogTag (_syslog->_LogTag) 69 #define LogMask (_syslog->_LogMask) 70 #define SyslogAddr (_syslog->_SyslogAddr) 71 #define SyslogHost (_syslog->_SyslogHost) 72 #define LogFacility (_syslog->_LogFacility) 73 74 75 extern char *strerror(int); 76 extern time_t time(); 77 78 void vsyslog(int, char *, va_list); 79 void openlog(char *, int, int); 80 static int snprintf(char *, size_t, char *, ...); 81 static int vsnprintf(char *, size_t, char *, va_list ap); 82 83 static int 84 allocstatic(void) 85 { 86 _syslog = (struct _syslog *)calloc(1, sizeof (struct _syslog)); 87 if (_syslog == 0) 88 return (0); /* can't do it */ 89 LogFile = -1; /* fd for log */ 90 LogStat = 0; /* status bits, set by openlog() */ 91 LogTag = "syslog"; /* string to tag the entry with */ 92 LogMask = 0xff; /* mask of priorities to be logged */ 93 LogFacility = LOG_USER; /* default facility code */ 94 return (1); 95 } 96 97 void 98 syslog(int pri, char *fmt, ...) 99 { 100 va_list ap; 101 102 va_start(ap, fmt); 103 vsyslog(pri, fmt, ap); 104 va_end(ap); 105 } 106 107 void 108 vsyslog(int pri, char *fmt, va_list ap) 109 { 110 char buf[MAXLINE + 1], outline[MAXLINE + 1]; 111 char *b, *f, *o; 112 int c; 113 long now; 114 int pid, olderrno = errno; 115 int retsiz, outsiz = MAXLINE + 1; 116 int taglen; 117 /* 118 * Maximum tag length is 256 (the pad in outline) minus the size of the 119 * other things that can go in the pad. 120 */ 121 #define MAX_TAG 230 122 123 124 if (_syslog == 0 && !allocstatic()) 125 return; 126 127 /* see if we should just throw out this message */ 128 if (pri <= 0 || PRIFAC(pri) >= LOG_NFACILITIES || 129 (PRIMASK(pri) & LogMask) == 0) 130 return; 131 if (LogFile < 0) 132 openlog(LogTag, LogStat | LOG_NDELAY, 0); 133 134 /* set default facility if none specified */ 135 if ((pri & LOG_FACMASK) == 0) 136 pri |= LogFacility; 137 138 /* build the message */ 139 o = outline; 140 (void) time(&now); 141 (void) sprintf(o, "<%d>%.15s ", pri, ctime(&now) + 4); 142 o += strlen(o); 143 144 if (LogTag) { 145 taglen = strlen(LogTag) < MAX_TAG ? strlen(LogTag) : MAX_TAG; 146 strncpy(o, LogTag, taglen); 147 o[taglen] = '\0'; 148 o += strlen(o); 149 } 150 if (LogStat & LOG_PID) { 151 (void) sprintf(o, "[%d]", getpid()); 152 o += strlen(o); 153 } 154 if (LogTag) { 155 (void) strcpy(o, ": "); 156 o += 2; 157 } 158 159 b = buf; 160 f = fmt; 161 while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) { 162 char *errstr; 163 164 if (c != '%') { 165 *b++ = c; 166 continue; 167 } 168 if ((c = *f++) != 'm') { 169 *b++ = '%'; 170 *b++ = c; 171 continue; 172 } 173 if ((errstr = strerror(olderrno)) == NULL) 174 (void) snprintf(b, &buf[MAXLINE] - b, "error %d", 175 olderrno); 176 else { 177 while (*errstr != '\0' && b < &buf[MAXLINE]) { 178 if (*errstr == '%') { 179 strcpy(b, "%%"); 180 b += 2; 181 } 182 else 183 *b++ = *errstr; 184 errstr++; 185 } 186 *b = '\0'; 187 } 188 b += strlen(b); 189 } 190 if (b > buf && *(b-1) != '\n') /* ensure at least one newline */ 191 *b++ = '\n'; 192 *b = '\0'; 193 (void) vsnprintf(o, &outline[sizeof (outline)] - o, buf, ap); 194 c = strlen(outline) + 1; /* add one for NULL byte */ 195 if (c > MAXLINE) { 196 c = MAXLINE; 197 outline[MAXLINE-1] = '\0'; 198 } 199 200 /* output the message to the local logger */ 201 if (sendto(LogFile, outline, c, 0, &SyslogAddr, 202 sizeof (SyslogAddr)) >= 0) 203 return; 204 if (!(LogStat & LOG_CONS)) 205 return; 206 207 /* output the message to the console */ 208 pid = vfork(); 209 if (pid == -1) 210 return; 211 if (pid == 0) { 212 int fd; 213 214 (void) signal(SIGALRM, SIG_DFL); 215 (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 216 (void) alarm(5); 217 if (((fd = open(sysmsg, O_WRONLY)) >= 0) || 218 (fd = open(ctty, O_WRONLY)) >= 0) { 219 (void) alarm(0); 220 if (outsiz > 2) { /* Just in case */ 221 (void) strcat(o, "\r\n"); 222 c += 2; 223 } 224 o = index(outline, '>') + 1; 225 (void) write(fd, o, c - (o - outline)); 226 (void) close(fd); 227 } else 228 (void) alarm(0); 229 _exit(0); 230 } 231 if (!(LogStat & LOG_NOWAIT)) 232 while ((c = wait((int *)0)) > 0 && c != pid) 233 ; 234 } 235 236 /* 237 * OPENLOG -- open system log 238 */ 239 void 240 openlog(char *ident, int logstat, int logfac) 241 { 242 if (_syslog == 0 && !allocstatic()) 243 return; 244 if (ident != NULL) 245 LogTag = ident; 246 LogStat = logstat; 247 if (logfac != 0) 248 LogFacility = logfac & LOG_FACMASK; 249 if (LogFile >= 0) 250 return; 251 SyslogAddr.sa_family = AF_UNIX; 252 (void) strncpy(SyslogAddr.sa_data, logname, 253 sizeof (SyslogAddr.sa_data)); 254 if (LogStat & LOG_NDELAY) { 255 LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); 256 (void) fcntl(LogFile, F_SETFD, 1); 257 } 258 } 259 260 /* 261 * CLOSELOG -- close the system log 262 */ 263 void 264 closelog(void) 265 { 266 267 if (_syslog == 0) 268 return; 269 (void) close(LogFile); 270 LogFile = -1; 271 } 272 273 /* 274 * SETLOGMASK -- set the log mask level 275 */ 276 int 277 setlogmask(int pmask) 278 { 279 int omask; 280 281 if (_syslog == 0 && !allocstatic()) 282 return (-1); 283 omask = LogMask; 284 if (pmask != 0) 285 LogMask = pmask; 286 return (omask); 287 } 288 289 /* 290 * snprintf/vsnprintf -- These routines are here 291 * temporarily to solve bugid 1220257. Perhaps 292 * they could become a public interface at some 293 * point but not for now. 294 */ 295 296 extern int _doprnt(); 297 298 static int 299 snprintf(char *string, size_t n, char *format, ...) 300 { 301 int count; 302 FILE siop; 303 va_list ap; 304 305 if (n == 0) 306 return (0); 307 siop._cnt = n - 1; 308 siop._base = siop._ptr = (unsigned char *)string; 309 siop._flag = _IOWRT+_IOSTRG; 310 va_start(ap, format); 311 count = _doprnt(format, ap, &siop); 312 va_end(ap); 313 *siop._ptr = '\0'; /* plant terminating null character */ 314 return (count); 315 } 316 317 static int 318 vsnprintf(char *string, size_t n, char *format, va_list ap) 319 { 320 int count; 321 FILE siop; 322 323 if (n == 0) 324 return (0); 325 siop._cnt = n - 1; 326 siop._base = siop._ptr = (unsigned char *)string; 327 siop._flag = _IOWRT+_IOSTRG; 328 count = _doprnt(format, ap, &siop); 329 *siop._ptr = '\0'; /* plant terminating null character */ 330 return (count); 331 } 332