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