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