xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/syslog.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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