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
syslog(int pri,const char * fmt,...)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
vsyslog(int pri,const char * fmt,va_list ap)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
syslogd_ok(void)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
openlog(const char * ident,int logstat,int logfac)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
closelog(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
setlogmask(int pmask)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