1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 /* 8 * Copyright (c) 1999 by Sun Microsystems, Inc. 9 * All rights reserved. 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 <netdb.h> 38 #include <strings.h> 39 #include <varargs.h> 40 #include <vfork.h> 41 #include <stdio.h> 42 43 #define MAXLINE 1024 /* max message size */ 44 #define NULL 0 /* manifest */ 45 46 #define PRIMASK(p) (1 << ((p) & LOG_PRIMASK)) 47 #define PRIFAC(p) (((p) & LOG_FACMASK) >> 3) 48 #define IMPORTANT LOG_ERR 49 50 static char *logname = "/dev/log"; 51 static char *ctty = "/dev/console"; 52 static char *sysmsg = "/dev/sysmsg"; 53 54 static struct _syslog { 55 int _LogFile; 56 int _LogStat; 57 char *_LogTag; 58 int _LogMask; 59 struct sockaddr _SyslogAddr; 60 char *_SyslogHost; 61 int _LogFacility; 62 } *_syslog; 63 #define LogFile (_syslog->_LogFile) 64 #define LogStat (_syslog->_LogStat) 65 #define LogTag (_syslog->_LogTag) 66 #define LogMask (_syslog->_LogMask) 67 #define SyslogAddr (_syslog->_SyslogAddr) 68 #define SyslogHost (_syslog->_SyslogHost) 69 #define LogFacility (_syslog->_LogFacility) 70 71 extern int errno; 72 73 extern char *calloc(); 74 extern char *strerror(int); 75 extern time_t time(); 76 extern unsigned int alarm(); 77 78 static int 79 allocstatic() 80 { 81 _syslog = (struct _syslog *)calloc(1, sizeof (struct _syslog)); 82 if (_syslog == 0) 83 return (0); /* can't do it */ 84 LogFile = -1; /* fd for log */ 85 LogStat = 0; /* status bits, set by openlog() */ 86 LogTag = "syslog"; /* string to tag the entry with */ 87 LogMask = 0xff; /* mask of priorities to be logged */ 88 LogFacility = LOG_USER; /* default facility code */ 89 return (1); 90 } 91 92 /*VARARGS2*/ 93 syslog(pri, fmt, va_alist) 94 int pri; 95 char *fmt; 96 va_dcl 97 { 98 va_list ap; 99 100 va_start(ap); 101 vsyslog(pri, fmt, ap); 102 va_end(ap); 103 } 104 105 vsyslog(pri, fmt, ap) 106 int pri; 107 char *fmt; 108 va_list ap; 109 { 110 char buf[MAXLINE + 1], outline[MAXLINE + 1]; 111 register char *b, *f, *o; 112 register 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 240 openlog(ident, logstat, logfac) 241 char *ident; 242 int logstat, logfac; 243 { 244 if (_syslog == 0 && !allocstatic()) 245 return; 246 if (ident != NULL) 247 LogTag = ident; 248 LogStat = logstat; 249 if (logfac != 0) 250 LogFacility = logfac & LOG_FACMASK; 251 if (LogFile >= 0) 252 return; 253 SyslogAddr.sa_family = AF_UNIX; 254 (void) strncpy(SyslogAddr.sa_data, logname, 255 sizeof (SyslogAddr.sa_data)); 256 if (LogStat & LOG_NDELAY) { 257 LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); 258 (void) fcntl(LogFile, F_SETFD, 1); 259 } 260 } 261 262 /* 263 * CLOSELOG -- close the system log 264 */ 265 266 closelog() 267 { 268 269 if (_syslog == 0) 270 return; 271 (void) close(LogFile); 272 LogFile = -1; 273 } 274 275 /* 276 * SETLOGMASK -- set the log mask level 277 */ 278 setlogmask(pmask) 279 int pmask; 280 { 281 int omask; 282 283 if (_syslog == 0 && !allocstatic()) 284 return (-1); 285 omask = LogMask; 286 if (pmask != 0) 287 LogMask = pmask; 288 return (omask); 289 } 290 291 /* 292 * snprintf/vsnprintf -- These routines are here 293 * temporarily to solve bugid 1220257. Perhaps 294 * they could become a public interface at some 295 * point but not for now. 296 */ 297 298 extern int _doprnt(); 299 300 /*VARARGS3*/ 301 static int 302 snprintf(string, n, format, va_alist) 303 char *string, *format; 304 size_t n; 305 va_dcl 306 { 307 register int count; 308 FILE siop; 309 va_list ap; 310 311 if (n == 0) 312 return (0); 313 siop._cnt = n - 1; 314 siop._base = siop._ptr = (unsigned char *)string; 315 siop._flag = _IOWRT+_IOSTRG; 316 va_start(ap); 317 count = _doprnt(format, ap, &siop); 318 va_end(ap); 319 *siop._ptr = '\0'; /* plant terminating null character */ 320 return (count); 321 } 322 323 /*VARARGS3*/ 324 static int 325 vsnprintf(string, n, format, ap) 326 char *string, *format; 327 size_t n; 328 va_list ap; 329 { 330 register int count; 331 FILE siop; 332 333 if (n == 0) 334 return (0); 335 siop._cnt = n - 1; 336 siop._base = siop._ptr = (unsigned char *)string; 337 siop._flag = _IOWRT+_IOSTRG; 338 count = _doprnt(format, ap, &siop); 339 *siop._ptr = '\0'; /* plant terminating null character */ 340 return (count); 341 } 342