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
allocstatic(void)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
syslog(int pri,char * fmt,...)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
vsyslog(int pri,char * fmt,va_list ap)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
openlog(char * ident,int logstat,int logfac)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
closelog(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
setlogmask(int pmask)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
snprintf(char * string,size_t n,char * format,...)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
vsnprintf(char * string,size_t n,char * format,va_list ap)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