xref: /titanic_51/usr/src/lib/libast/common/comp/syslog.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin  * syslog implementation
25da2e3ebdSchin  */
26da2e3ebdSchin 
27da2e3ebdSchin #include <ast.h>
28da2e3ebdSchin 
29da2e3ebdSchin #if _lib_syslog
30da2e3ebdSchin 
31da2e3ebdSchin NoN(syslog)
32da2e3ebdSchin 
33da2e3ebdSchin #else
34da2e3ebdSchin 
35da2e3ebdSchin #define LOG_TABLES
36da2e3ebdSchin 
37da2e3ebdSchin #include "sysloglib.h"
38da2e3ebdSchin 
39da2e3ebdSchin #include <error.h>
40da2e3ebdSchin #include <tm.h>
41da2e3ebdSchin 
42da2e3ebdSchin Syslog_state_t		log = { LOG_USER, -1, 0, ~0 };
43da2e3ebdSchin 
44da2e3ebdSchin static const Namval_t	attempt[] =
45da2e3ebdSchin {
4634f9b3eeSRoland Mainz #if _UWIN
4734f9b3eeSRoland Mainz 	"/var/log/syslog",		0,
4834f9b3eeSRoland Mainz #endif
49da2e3ebdSchin 	"/dev/log",			0,
5034f9b3eeSRoland Mainz 	"var/log/syslog",		0,
51da2e3ebdSchin 	"lib/syslog/log",		0,
52da2e3ebdSchin 	"/dev/console",			LOG_CONS,
53da2e3ebdSchin };
54da2e3ebdSchin 
55da2e3ebdSchin const Namval_t		log_facility[] =
56da2e3ebdSchin {
57da2e3ebdSchin 	"default",	0,
58da2e3ebdSchin 	"user",		LOG_USER,
59da2e3ebdSchin 	"kernel",	LOG_KERN,
60da2e3ebdSchin 	"mail",		LOG_MAIL,
61da2e3ebdSchin 	"daemon",	LOG_DAEMON,
62da2e3ebdSchin 	"security",	LOG_AUTH,
63da2e3ebdSchin 	"syslog",	LOG_SYSLOG,
64da2e3ebdSchin 	"lpr",		LOG_LPR,
65da2e3ebdSchin 	"news",		LOG_NEWS,
66da2e3ebdSchin 	"uucp",		LOG_UUCP,
67da2e3ebdSchin 	"cron",		LOG_CRON,
68da2e3ebdSchin 	"audit",	LOG_AUDIT,
69da2e3ebdSchin 	"logalert",	LOG_LFMT,
70da2e3ebdSchin #ifdef LOG_SYSTEM2
71da2e3ebdSchin 	"system2",	LOG_SYSTEM2,
72da2e3ebdSchin #endif
73da2e3ebdSchin #ifdef LOG_SYSTEM1
74da2e3ebdSchin 	"system1",	LOG_SYSTEM1,
75da2e3ebdSchin #endif
76da2e3ebdSchin #ifdef LOG_SYSTEM0
77da2e3ebdSchin 	"system0",	LOG_SYSTEM0,
78da2e3ebdSchin #endif
79da2e3ebdSchin 	0,		0
80da2e3ebdSchin };
81da2e3ebdSchin 
82da2e3ebdSchin const Namval_t		log_severity[] =
83da2e3ebdSchin {
84da2e3ebdSchin 	"panic",	LOG_EMERG,
85da2e3ebdSchin 	"alert",	LOG_ALERT,
86da2e3ebdSchin 	"critical",	LOG_CRIT,
87da2e3ebdSchin 	"error",	LOG_ERR,
88da2e3ebdSchin 	"warning",	LOG_WARNING,
89da2e3ebdSchin 	"notice",	LOG_NOTICE,
90da2e3ebdSchin 	"info",		LOG_INFO,
91da2e3ebdSchin 	"debug",	LOG_DEBUG,
92da2e3ebdSchin 	0,		0
93da2e3ebdSchin };
94da2e3ebdSchin 
95da2e3ebdSchin #if _UWIN
96da2e3ebdSchin 
97da2e3ebdSchin /*
98da2e3ebdSchin  * open /dev/(fdp|tcp|udp)/HOST/SERVICE for read
99da2e3ebdSchin  */
100da2e3ebdSchin 
101da2e3ebdSchin #include <ctype.h>
102da2e3ebdSchin #include <ls.h>
103da2e3ebdSchin #include <sys/socket.h>
104da2e3ebdSchin #include <sys/un.h>
105da2e3ebdSchin #include <netdb.h>
106da2e3ebdSchin #include <netinet/in.h>
107da2e3ebdSchin 
108da2e3ebdSchin #if !defined(htons) && !_lib_htons
109da2e3ebdSchin #	define htons(x)	(x)
110da2e3ebdSchin #endif
111da2e3ebdSchin #if !defined(htonl) && !_lib_htonl
112da2e3ebdSchin #	define htonl(x)	(x)
113da2e3ebdSchin #endif
114da2e3ebdSchin 
115da2e3ebdSchin #ifndef INADDR_LOOPBACK
116da2e3ebdSchin #define INADDR_LOOPBACK		0x7f000001L
117da2e3ebdSchin #endif
118da2e3ebdSchin 
119da2e3ebdSchin /*
120da2e3ebdSchin  * convert s to sockaddr_in
121da2e3ebdSchin  * -1 returned on error
122da2e3ebdSchin  */
123da2e3ebdSchin 
124da2e3ebdSchin static int
125da2e3ebdSchin str2inet(register char* s, char* prot, struct sockaddr_in* addr)
126da2e3ebdSchin {
127da2e3ebdSchin 	register int	c;
128da2e3ebdSchin 	register int	v;
129da2e3ebdSchin 	register int	n = 0;
130da2e3ebdSchin 	unsigned long	a = 0;
131da2e3ebdSchin 	unsigned short	p = 0;
132da2e3ebdSchin 
133da2e3ebdSchin 	if (!memcmp(s, "local/", 6))
134da2e3ebdSchin 	{
135da2e3ebdSchin 		a = INADDR_LOOPBACK;
136da2e3ebdSchin 		n = 4;
137da2e3ebdSchin 		s += 6;
138da2e3ebdSchin 	}
139da2e3ebdSchin 	else if (!isdigit(*s))
140da2e3ebdSchin 	{
141da2e3ebdSchin 		struct hostent*	hp;
142da2e3ebdSchin 		char*		e = strchr(s, '/');
143da2e3ebdSchin 
144da2e3ebdSchin 		if (!(e = strchr(s, '/')))
145da2e3ebdSchin 			return -1;
146da2e3ebdSchin 		*e = 0;
147da2e3ebdSchin 		hp = gethostbyname(s);
148da2e3ebdSchin 		*e = '/';
149da2e3ebdSchin 		if (!hp || hp->h_addrtype != AF_INET || hp->h_length > sizeof(struct in_addr))
150da2e3ebdSchin 			return -1;
151da2e3ebdSchin 		a = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
152da2e3ebdSchin 		n = 6;
153da2e3ebdSchin 		s = e + 1;
154da2e3ebdSchin 	}
155da2e3ebdSchin 	for (;;)
156da2e3ebdSchin 	{
157da2e3ebdSchin 		v = 0;
158da2e3ebdSchin 		while ((c = *s++) >= '0' && c <= '9')
159da2e3ebdSchin 			v = v * 10 + c - '0';
160da2e3ebdSchin 		if (++n <= 4)
161da2e3ebdSchin 			a = (a << 8) | (v & 0xff);
162da2e3ebdSchin 		else
163da2e3ebdSchin 		{
164da2e3ebdSchin 			if (n <= 5)
165da2e3ebdSchin 				a = htonl(a);
166da2e3ebdSchin 			if (c)
167da2e3ebdSchin 			{
168da2e3ebdSchin 				struct servent*	sp;
169da2e3ebdSchin 
170da2e3ebdSchin 				if (!(sp = getservbyname(s - 1, prot)))
171da2e3ebdSchin 					return -1;
172da2e3ebdSchin 				p = sp->s_port;
173da2e3ebdSchin 			}
174da2e3ebdSchin 			else
175da2e3ebdSchin 				p = htons(v);
176da2e3ebdSchin 			break;
177da2e3ebdSchin 		}
178da2e3ebdSchin 		if (c != '.' && c != '/')
179da2e3ebdSchin 			return -1;
180da2e3ebdSchin 	}
181da2e3ebdSchin 	memset((char*)addr, 0, sizeof(*addr));
182da2e3ebdSchin 	addr->sin_family = AF_INET;
183da2e3ebdSchin 	addr->sin_addr.s_addr = a;
184da2e3ebdSchin 	addr->sin_port = p;
185da2e3ebdSchin 	return 0;
186da2e3ebdSchin }
187da2e3ebdSchin 
188da2e3ebdSchin /*
189da2e3ebdSchin  * call this after open fails to see if path is a socket
190da2e3ebdSchin  */
191da2e3ebdSchin 
192da2e3ebdSchin int
193da2e3ebdSchin sockopen(const char* path)
194da2e3ebdSchin {
195da2e3ebdSchin 	int			fd;
196da2e3ebdSchin 	struct sockaddr_in	addr;
197da2e3ebdSchin 	char			buf[PATH_MAX];
198da2e3ebdSchin 
199da2e3ebdSchin 	if (pathgetlink(path, buf, sizeof(buf)) <= 0)
200da2e3ebdSchin 	{
201da2e3ebdSchin 		if (strlen(path) >= sizeof(buf))
202da2e3ebdSchin 			return -1;
203da2e3ebdSchin 		strcpy(buf, path);
204da2e3ebdSchin 	}
205da2e3ebdSchin #if LOCAL
206da2e3ebdSchin 	{
207da2e3ebdSchin 		int			ul;
208da2e3ebdSchin 		struct sockaddr_un	ua;
209da2e3ebdSchin 		struct stat		st;
210da2e3ebdSchin 
211da2e3ebdSchin 		if ((ul = strlen(buf)) < sizeof(ua.sun_path) && !stat(buf, &st) && S_ISSOCK(st.st_mode))
212da2e3ebdSchin 		{
213da2e3ebdSchin 			if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
214da2e3ebdSchin 				return -1;
215da2e3ebdSchin 			ua.sun_family = AF_UNIX;
216da2e3ebdSchin 			strcpy(ua.sun_path, buf);
217da2e3ebdSchin 			ul += sizeof(ua.sun_family) + 1;
218da2e3ebdSchin 			if (!connect(fd, (struct sockaddr*)&ua, ul))
219da2e3ebdSchin 				return fd;
220da2e3ebdSchin 			close(fd);
221da2e3ebdSchin 			return -1;
222da2e3ebdSchin 		}
223da2e3ebdSchin 	}
224da2e3ebdSchin #endif
225da2e3ebdSchin 	if (!strmatch(buf, "/dev/(tcp|udp)/*/*"))
226da2e3ebdSchin 		return -1;
227da2e3ebdSchin 	buf[8] = 0;
228da2e3ebdSchin 	if (str2inet(buf + 9, buf + 5, &addr))
229da2e3ebdSchin 		return -1;
230da2e3ebdSchin 	if ((fd = socket(AF_INET, buf[5] == 't' ? SOCK_STREAM : SOCK_DGRAM, 0)) < 0)
231da2e3ebdSchin 		return -1;
232da2e3ebdSchin 	if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)))
233da2e3ebdSchin 	{
234da2e3ebdSchin 		close(fd);
235da2e3ebdSchin 		return -1;
236da2e3ebdSchin 	}
237da2e3ebdSchin 	return fd;
238da2e3ebdSchin }
239da2e3ebdSchin 
240da2e3ebdSchin #else
241da2e3ebdSchin 
242da2e3ebdSchin int
243da2e3ebdSchin sockopen(const char* path)
244da2e3ebdSchin {
245da2e3ebdSchin 	return -1;
246da2e3ebdSchin }
247da2e3ebdSchin 
248da2e3ebdSchin #endif
249da2e3ebdSchin 
250da2e3ebdSchin void
251da2e3ebdSchin sendlog(const char* msg)
252da2e3ebdSchin {
253da2e3ebdSchin 	register char*		s;
254da2e3ebdSchin 	register Namval_t*	p;
255da2e3ebdSchin 	register int		n;
256da2e3ebdSchin 
257da2e3ebdSchin 	n = msg ? strlen(msg) : 0;
258da2e3ebdSchin 	for (;;)
259da2e3ebdSchin 	{
260da2e3ebdSchin 		if (log.fd < 0)
261da2e3ebdSchin 		{
262da2e3ebdSchin 			char	buf[PATH_MAX];
263da2e3ebdSchin 
264da2e3ebdSchin 			if (log.attempt >= elementsof(attempt))
265da2e3ebdSchin 				break;
266da2e3ebdSchin 			p = (Namval_t*)&attempt[log.attempt++];
267da2e3ebdSchin 			if (p->value && !(p->value & log.flags))
268da2e3ebdSchin 				continue;
269da2e3ebdSchin 			if (*(s = p->name) != '/' && !(s = pathpath(buf, s, "", PATH_REGULAR|PATH_READ)))
270da2e3ebdSchin 				continue;
271da2e3ebdSchin 			if ((log.fd = open(s, O_WRONLY|O_APPEND|O_NOCTTY)) < 0 && (log.fd = sockopen(s)) < 0)
272da2e3ebdSchin 				continue;
273da2e3ebdSchin 			fcntl(log.fd, F_SETFD, FD_CLOEXEC);
274da2e3ebdSchin 		}
275da2e3ebdSchin 		if (!n || write(log.fd, msg, n) > 0)
276da2e3ebdSchin 			break;
277da2e3ebdSchin 		close(log.fd);
278da2e3ebdSchin 		log.fd = -1;
279da2e3ebdSchin 	}
280da2e3ebdSchin 	if (n && (log.flags & LOG_PERROR))
281da2e3ebdSchin 		write(2, msg, n);
282da2e3ebdSchin }
283da2e3ebdSchin 
284da2e3ebdSchin static int
285da2e3ebdSchin extend(Sfio_t* sp, void* vp, Sffmt_t* dp)
286da2e3ebdSchin {
287da2e3ebdSchin 	if (dp->fmt == 'm')
288da2e3ebdSchin 	{
289da2e3ebdSchin 		dp->flags |= SFFMT_VALUE;
290da2e3ebdSchin 		dp->fmt = 's';
291da2e3ebdSchin 		dp->size = -1;
292da2e3ebdSchin 		*((char**)vp) = fmterror(errno);
293da2e3ebdSchin 	}
294da2e3ebdSchin 	return 0;
295da2e3ebdSchin }
296da2e3ebdSchin 
297da2e3ebdSchin void
298da2e3ebdSchin vsyslog(int priority, const char* format, va_list ap)
299da2e3ebdSchin {
300da2e3ebdSchin 	register int	c;
301da2e3ebdSchin 	register char*	s;
302da2e3ebdSchin 	Sfio_t*		sp;
303da2e3ebdSchin 	Sffmt_t		fmt;
304da2e3ebdSchin 	char		buf[16];
305da2e3ebdSchin 
306da2e3ebdSchin 	if (!LOG_FACILITY(priority))
307da2e3ebdSchin 		priority |= log.facility;
308da2e3ebdSchin 	if (!(priority & log.mask))
309da2e3ebdSchin 		return;
310da2e3ebdSchin 	if (sp = sfstropen())
311da2e3ebdSchin 	{
312da2e3ebdSchin 		sfputr(sp, fmttime("%b %d %H:%M:%S", time(NiL)), -1);
313da2e3ebdSchin 		if (log.flags & LOG_LEVEL)
314da2e3ebdSchin 		{
315da2e3ebdSchin 			if ((c = LOG_SEVERITY(priority)) < elementsof(log_severity))
316da2e3ebdSchin 				s = (char*)log_severity[c].name;
317da2e3ebdSchin 			else
318da2e3ebdSchin 				sfsprintf(s = buf, sizeof(buf), "debug%d", c);
319da2e3ebdSchin 			sfprintf(sp, " %-8s ", s);
320da2e3ebdSchin 			if ((c = LOG_FACILITY(priority)) < elementsof(log_facility))
321da2e3ebdSchin 				s = (char*)log_facility[c].name;
322da2e3ebdSchin 			else
323da2e3ebdSchin 				sfsprintf(s = buf, sizeof(buf), "local%d", c);
324da2e3ebdSchin 			sfprintf(sp, " %-8s ", s);
325da2e3ebdSchin 		}
326da2e3ebdSchin #if _lib_gethostname
327da2e3ebdSchin 		if (!*log.host && gethostname(log.host, sizeof(log.host)-1))
328da2e3ebdSchin 			strcpy(log.host, "localhost");
329da2e3ebdSchin 		sfprintf(sp, " %s", log.host);
330da2e3ebdSchin #endif
331da2e3ebdSchin 		if (*log.ident)
332da2e3ebdSchin 			sfprintf(sp, " %s", log.ident);
333da2e3ebdSchin 		if (log.flags & LOG_PID)
334da2e3ebdSchin 		{
335da2e3ebdSchin 			if (!*log.ident)
336da2e3ebdSchin 				sfprintf(sp, " ");
337da2e3ebdSchin 			sfprintf(sp, "[%d]", getpid());
338da2e3ebdSchin 		}
339da2e3ebdSchin 		if (format)
340da2e3ebdSchin 		{
341da2e3ebdSchin 			sfprintf(sp, ": ");
342da2e3ebdSchin 			memset(&fmt, 0, sizeof(fmt));
343da2e3ebdSchin 			fmt.version = SFIO_VERSION;
344da2e3ebdSchin 			fmt.form = (char*)format;
345da2e3ebdSchin 			fmt.extf = extend;
346da2e3ebdSchin 			va_copy(fmt.args, ap);
347da2e3ebdSchin 			sfprintf(sp, "%!", &fmt);
348da2e3ebdSchin 		}
349da2e3ebdSchin 		if ((s = sfstrseek(sp, 0, SEEK_CUR)) && *(s - 1) != '\n')
350da2e3ebdSchin 			sfputc(sp, '\n');
351da2e3ebdSchin 		if (s = sfstruse(sp))
352da2e3ebdSchin 			sendlog(s);
353da2e3ebdSchin 		sfstrclose(sp);
354da2e3ebdSchin 	}
355da2e3ebdSchin }
356da2e3ebdSchin 
357da2e3ebdSchin void
358da2e3ebdSchin syslog(int priority, const char* format, ...)
359da2e3ebdSchin {
360da2e3ebdSchin 	va_list		ap;
361da2e3ebdSchin 
362da2e3ebdSchin 	va_start(ap, format);
363da2e3ebdSchin 	vsyslog(priority, format, ap);
364da2e3ebdSchin 	va_end(ap);
365da2e3ebdSchin }
366da2e3ebdSchin 
367da2e3ebdSchin #endif
368