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