1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 41 /* 42 * SYSLOG -- print message on log file 43 * 44 * This routine looks a lot like printf, except that it 45 * outputs to the log file instead of the standard output. 46 * Also: 47 * adds a timestamp, 48 * prints the module name in front of the message, 49 * has some other formatting types (or will sometime), 50 * adds a newline on the end of the message. 51 * 52 * The output of this routine is intended to be read by /etc/syslogd. 53 */ 54 55 #pragma weak _syslog = syslog 56 57 #include "lint.h" 58 #include <sys/types.h> 59 #include <sys/types32.h> 60 #include <sys/mman.h> 61 #include <sys/stropts.h> 62 #include <sys/strlog.h> 63 #include <sys/log.h> /* for LOG_MAXPS */ 64 #include <stdlib.h> 65 #include <procfs.h> 66 #include <syslog.h> 67 #include <signal.h> 68 #include <fcntl.h> 69 #include <string.h> 70 #include <stdarg.h> 71 #include <unistd.h> 72 #include <wait.h> 73 #include <stdio.h> 74 #include <string.h> 75 #include <errno.h> 76 #include <thread.h> 77 #include <synch.h> 78 #include <sys/door.h> 79 #include <sys/stat.h> 80 #include <stropts.h> 81 #include <sys/fork.h> 82 #include <sys/wait.h> 83 #include "libc.h" 84 85 #define MAXLINE 8192 /* max message size (but see below) */ 86 87 #define PRIMASK(p) (1 << ((p) & LOG_PRIMASK)) 88 #define PRIFAC(p) (((p) & LOG_FACMASK) >> 3) 89 #define IMPORTANT LOG_ERR 90 91 #ifndef FALSE 92 #define FALSE 0 93 #endif 94 95 #ifndef TRUE 96 #define TRUE 1 97 #endif 98 99 #define logname "/dev/conslog" 100 #define ctty "/dev/syscon" 101 #define sysmsg "/dev/sysmsg" 102 103 #define DOORFILE "/var/run/syslog_door" 104 105 static struct __syslog { 106 int _LogFile; 107 int _LogStat; 108 const char *_LogTag; 109 int _LogMask; 110 char *_SyslogHost; 111 int _LogFacility; 112 int _LogFileInvalid; 113 int _OpenLogCalled; 114 dev_t _LogDev; 115 char _ProcName[PRFNSZ + 1]; 116 } __syslog = { 117 -1, /* fd for log */ 118 0, /* status bits, set by openlog() */ 119 "syslog", /* string to tag the entry with */ 120 0xff, /* mask of priorities to be logged */ 121 NULL, 122 LOG_USER, /* default facility code */ 123 FALSE, /* check for validity of fd for log */ 124 0, /* openlog has not yet been called */ 125 }; 126 127 #define LogFile (__syslog._LogFile) 128 #define LogStat (__syslog._LogStat) 129 #define LogTag (__syslog._LogTag) 130 #define LogMask (__syslog._LogMask) 131 #define SyslogHost (__syslog._SyslogHost) 132 #define LogFacility (__syslog._LogFacility) 133 #define LogFileInvalid (__syslog._LogFileInvalid) 134 #define OpenLogCalled (__syslog._OpenLogCalled) 135 #define LogDev (__syslog._LogDev) 136 #define ProcName (__syslog._ProcName) 137 138 static int syslogd_ok(void); 139 140 /* 141 * Regrettably, there are several instances inside libc where 142 * syslog() is called from the bottom of a deep call stack 143 * and a critical lock was acquired near the top of the stack. 144 * 145 * Because syslog() uses stdio (and it is called from within stdio) 146 * it runs the danger of deadlocking, perhaps with an interposed 147 * malloc() when fork() is occurring concurrently, perhaps with 148 * some other lock within libc. 149 * 150 * The only fix for this problem is to restructure libc not to do 151 * this thing and always to call syslog() with no locks held. 152 * This restructuring will require a substantial effort. 153 * 154 * Meanwhile, we just hope that on the rare occasion that syslog() 155 * is called from within libc (such occurrences should "never happen") 156 * that we don't get caught in a race condition deadlock. 157 */ 158 void 159 syslog(int pri, const char *fmt, ...) 160 { 161 va_list ap; 162 163 va_start(ap, fmt); 164 vsyslog(pri, fmt, ap); 165 va_end(ap); 166 } 167 168 169 void 170 vsyslog(int pri, const char *fmt, va_list ap) 171 { 172 char *b, *f, *o; 173 char c; 174 int clen; 175 char buf[MAXLINE + 2]; 176 char outline[MAXLINE + 256]; /* pad to allow date, system name... */ 177 struct timeval now; 178 pid_t pid; 179 struct log_ctl hdr; 180 struct strbuf dat; 181 struct strbuf ctl; 182 char timestr[26]; /* hardwired value 26 due to Posix */ 183 size_t taglen; 184 int olderrno = errno; 185 struct stat statbuff; 186 int procfd; 187 char procfile[32]; 188 psinfo_t p; 189 int showpid; 190 uint32_t msgid; 191 char *msgid_start, *msgid_end; 192 int nowait; 193 int ret; 194 195 /* 196 * Maximum tag length is 256 (the pad in outline) minus the size of the 197 * other things that can go in the pad. 198 */ 199 #define MAX_TAG 230 200 201 /* see if we should just throw out this message */ 202 if (pri < 0 || PRIFAC(pri) >= LOG_NFACILITIES || 203 (PRIMASK(pri) & LogMask) == 0) 204 return; 205 206 if (LogFileInvalid) 207 return; 208 209 /* 210 * if openlog() has not been called by the application, 211 * try to get the name of the application and set it 212 * as the ident string for messages. If unable to get 213 * it for any reason, fall back to using the default 214 * of syslog. If we succeed in getting the name, also 215 * turn on LOG_PID, to provide greater detail. 216 */ 217 showpid = 0; 218 if (OpenLogCalled == 0) { 219 (void) sprintf(procfile, "/proc/%d/psinfo", (int)getpid()); 220 if ((procfd = open(procfile, O_RDONLY)) >= 0) { 221 if (read(procfd, &p, sizeof (psinfo_t)) >= 0) { 222 (void) strncpy(ProcName, p.pr_fname, PRFNSZ); 223 LogTag = (const char *) &ProcName; 224 showpid = LOG_PID; 225 } 226 (void) close(procfd); 227 } 228 } 229 if (LogFile < 0) 230 openlog(LogTag, LogStat|LOG_NDELAY|showpid, 0); 231 232 if ((fstat(LogFile, &statbuff) != 0) || 233 (!S_ISCHR(statbuff.st_mode)) || (statbuff.st_rdev != LogDev)) { 234 LogFileInvalid = TRUE; 235 return; 236 } 237 238 /* set default facility if none specified */ 239 if ((pri & LOG_FACMASK) == 0) 240 pri |= LogFacility; 241 242 /* build the header */ 243 hdr.pri = pri; 244 hdr.flags = SL_CONSOLE; 245 hdr.level = 0; 246 247 /* build the message */ 248 /* 249 * To avoid potential security problems, bounds checking is done 250 * on outline and buf. 251 * The following code presumes that the header information will 252 * fit in 250-odd bytes, as was accounted for in the buffer size 253 * allocation. This is dependent on the assumption that the LogTag 254 * and the string returned by sprintf() for getpid() will return 255 * be less than 230-odd characters combined. 256 */ 257 o = outline; 258 (void) gettimeofday(&now, NULL); 259 (void) sprintf(o, "%.15s.%03d ", ctime_r(&now.tv_sec, timestr, 26) + 4, 260 now.tv_usec / 1000); 261 o += strlen(o); 262 263 if (LogTag) { 264 taglen = strlen(LogTag) < MAX_TAG ? strlen(LogTag) : MAX_TAG; 265 (void) strncpy(o, LogTag, taglen); 266 o[taglen] = '\0'; 267 o += strlen(o); 268 } 269 if (LogStat & LOG_PID) { 270 (void) sprintf(o, "[%d]", (int)getpid()); 271 o += strlen(o); 272 } 273 if (LogTag) { 274 (void) strcpy(o, ": "); 275 o += 2; 276 } 277 278 STRLOG_MAKE_MSGID(fmt, msgid); 279 (void) sprintf(o, "[ID %u FACILITY_AND_PRIORITY] ", msgid); 280 o += strlen(o); 281 282 b = buf; 283 f = (char *)fmt; 284 while ((c = *f++) != '\0' && b < &buf[MAXLINE]) { 285 char *errmsg; 286 if (c != '%') { 287 *b++ = c; 288 continue; 289 } 290 if ((c = *f++) != 'm') { 291 *b++ = '%'; 292 *b++ = c; 293 continue; 294 } 295 if ((errmsg = strerror(olderrno)) == NULL) 296 (void) snprintf(b, &buf[MAXLINE] - b, "error %d", 297 olderrno); 298 else { 299 while (*errmsg != '\0' && b < &buf[MAXLINE]) { 300 if (*errmsg == '%') { 301 (void) strcpy(b, "%%"); 302 b += 2; 303 } 304 else 305 *b++ = *errmsg; 306 errmsg++; 307 } 308 *b = '\0'; 309 } 310 b += strlen(b); 311 } 312 if (b > buf && *(b-1) != '\n') /* ensure at least one newline */ 313 *b++ = '\n'; 314 *b = '\0'; 315 /* LINTED variable format specifier */ 316 (void) vsnprintf(o, &outline[sizeof (outline)] - o, buf, ap); 317 clen = (int)strlen(outline) + 1; /* add one for NULL byte */ 318 if (clen > MAXLINE) { 319 clen = MAXLINE; 320 outline[MAXLINE-1] = '\0'; 321 } 322 323 /* 324 * 1136432 points out that the underlying log driver actually 325 * refuses to accept (ERANGE) messages longer than LOG_MAXPS 326 * bytes. So it really doesn't make much sense to putmsg a 327 * longer message.. 328 */ 329 if (clen > LOG_MAXPS) { 330 clen = LOG_MAXPS; 331 outline[LOG_MAXPS-1] = '\0'; 332 } 333 334 /* set up the strbufs */ 335 ctl.maxlen = sizeof (struct log_ctl); 336 ctl.len = sizeof (struct log_ctl); 337 ctl.buf = (caddr_t)&hdr; 338 dat.maxlen = sizeof (outline); 339 dat.len = clen; 340 dat.buf = outline; 341 342 /* output the message to the local logger */ 343 ret = putmsg(LogFile, &ctl, &dat, 0); 344 if (!(LogStat & LOG_CONS)) 345 return; 346 if ((ret >= 0) && syslogd_ok()) 347 return; 348 349 /* 350 * Output the message to the console directly. To reduce visual 351 * clutter, we strip out the message ID. 352 */ 353 if ((msgid_start = strstr(outline, "[ID ")) != NULL && 354 (msgid_end = strstr(msgid_start, "] ")) != NULL) 355 (void) strcpy(msgid_start, msgid_end + 2); 356 357 clen = strlen(outline) + 1; 358 359 nowait = (LogStat & LOG_NOWAIT); 360 pid = forkx(nowait? 0 : (FORK_NOSIGCHLD | FORK_WAITPID)); 361 if (pid == -1) 362 return; 363 364 if (pid == 0) { 365 sigset_t sigs; 366 int fd; 367 368 (void) sigset(SIGALRM, SIG_DFL); 369 (void) sigemptyset(&sigs); 370 (void) sigaddset(&sigs, SIGALRM); 371 (void) sigprocmask(SIG_UNBLOCK, &sigs, NULL); 372 (void) alarm(5); 373 if (((fd = open(sysmsg, O_WRONLY)) >= 0) || 374 (fd = open(ctty, O_WRONLY)) >= 0) { 375 (void) alarm(0); 376 outline[clen - 1] = '\r'; 377 (void) write(fd, outline, clen); 378 (void) close(fd); 379 } 380 _exit(0); 381 } 382 if (!nowait) 383 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 384 continue; 385 } 386 387 /* 388 * Use a door call to syslogd to see if it's alive. 389 */ 390 static int 391 syslogd_ok(void) 392 { 393 int d; 394 int s; 395 door_arg_t darg; 396 door_info_t info; 397 398 if ((d = open(DOORFILE, O_RDONLY)) < 0) 399 return (0); 400 /* 401 * see if our pid matches the pid of the door server. 402 * If so, syslogd has called syslog(), probably as 403 * a result of some name service library error, and 404 * we don't want to let syslog continue and possibly 405 * fork here. 406 */ 407 info.di_target = 0; 408 if (__door_info(d, &info) < 0 || info.di_target == getpid()) { 409 (void) close(d); 410 return (0); 411 } 412 darg.data_ptr = NULL; 413 darg.data_size = 0; 414 darg.desc_ptr = NULL; 415 darg.desc_num = 0; 416 darg.rbuf = NULL; 417 darg.rsize = 0; 418 s = __door_call(d, &darg); 419 (void) close(d); 420 if (s < 0) 421 return (0); /* failure - syslogd dead */ 422 else 423 return (1); 424 } 425 426 /* 427 * OPENLOG -- open system log 428 */ 429 430 void 431 openlog(const char *ident, int logstat, int logfac) 432 { 433 struct stat statbuff; 434 435 OpenLogCalled = 1; 436 if (ident != NULL) 437 LogTag = ident; 438 LogStat = logstat; 439 if (logfac != 0) 440 LogFacility = logfac & LOG_FACMASK; 441 442 /* 443 * if the fstat(2) fails or the st_rdev has changed 444 * then we must open the file 445 */ 446 if ((fstat(LogFile, &statbuff) == 0) && 447 (S_ISCHR(statbuff.st_mode)) && (statbuff.st_rdev == LogDev)) 448 return; 449 450 if (LogStat & LOG_NDELAY) { 451 LogFile = open(logname, O_WRONLY); 452 (void) fcntl(LogFile, F_SETFD, 1); 453 (void) fstat(LogFile, &statbuff); 454 LogDev = statbuff.st_rdev; 455 } 456 } 457 458 /* 459 * CLOSELOG -- close the system log 460 */ 461 462 void 463 closelog(void) 464 { 465 struct stat statbuff; 466 467 OpenLogCalled = 0; 468 469 /* if the LogFile is invalid it can not be closed */ 470 if (LogFileInvalid) 471 return; 472 473 /* 474 * if the fstat(2) fails or the st_rdev has changed 475 * then we can not close the file 476 */ 477 if ((fstat(LogFile, &statbuff) == 0) && (statbuff.st_rdev == LogDev)) { 478 (void) close(LogFile); 479 LogFile = -1; 480 LogStat = 0; 481 } 482 } 483 484 /* 485 * SETLOGMASK -- set the log mask level 486 */ 487 int 488 setlogmask(int pmask) 489 { 490 int omask = 0; 491 492 omask = LogMask; 493 if (pmask != 0) 494 LogMask = pmask; 495 return (omask); 496 } 497