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