1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 
31 NoN(syslog)
32 
33 #else
34 
35 #define LOG_TABLES
36 
37 #include "sysloglib.h"
38 
39 #include <error.h>
40 #include <tm.h>
41 
42 Syslog_state_t		log = { LOG_USER, -1, 0, ~0 };
43 
44 static 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 
55 const 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 
82 const 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 
124 static int
125 str2inet(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 
192 int
193 sockopen(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 
242 int
243 sockopen(const char* path)
244 {
245 	return -1;
246 }
247 
248 #endif
249 
250 void
251 sendlog(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|O_cloexec)) < 0 && (log.fd = sockopen(s)) < 0)
272 				continue;
273 #if !O_cloexec
274 			fcntl(log.fd, F_SETFD, FD_CLOEXEC);
275 #endif
276 		}
277 		if (!n || write(log.fd, msg, n) > 0)
278 			break;
279 		close(log.fd);
280 		log.fd = -1;
281 	}
282 	if (n && (log.flags & LOG_PERROR))
283 		write(2, msg, n);
284 }
285 
286 static int
287 extend(Sfio_t* sp, void* vp, Sffmt_t* dp)
288 {
289 	if (dp->fmt == 'm')
290 	{
291 		dp->flags |= SFFMT_VALUE;
292 		dp->fmt = 's';
293 		dp->size = -1;
294 		*((char**)vp) = fmterror(errno);
295 	}
296 	return 0;
297 }
298 
299 void
300 vsyslog(int priority, const char* format, va_list ap)
301 {
302 	register int	c;
303 	register char*	s;
304 	Sfio_t*		sp;
305 	Sffmt_t		fmt;
306 	char		buf[16];
307 
308 	if (!LOG_FACILITY(priority))
309 		priority |= log.facility;
310 	if (!(priority & log.mask))
311 		return;
312 	if (sp = sfstropen())
313 	{
314 		sfputr(sp, fmttime("%b %d %H:%M:%S", time(NiL)), -1);
315 		if (log.flags & LOG_LEVEL)
316 		{
317 			if ((c = LOG_SEVERITY(priority)) < elementsof(log_severity))
318 				s = (char*)log_severity[c].name;
319 			else
320 				sfsprintf(s = buf, sizeof(buf), "debug%d", c);
321 			sfprintf(sp, " %-8s ", s);
322 			if ((c = LOG_FACILITY(priority)) < elementsof(log_facility))
323 				s = (char*)log_facility[c].name;
324 			else
325 				sfsprintf(s = buf, sizeof(buf), "local%d", c);
326 			sfprintf(sp, " %-8s ", s);
327 		}
328 #if _lib_gethostname
329 		if (!*log.host && gethostname(log.host, sizeof(log.host)-1))
330 			strcpy(log.host, "localhost");
331 		sfprintf(sp, " %s", log.host);
332 #endif
333 		if (*log.ident)
334 			sfprintf(sp, " %s", log.ident);
335 		if (log.flags & LOG_PID)
336 		{
337 			if (!*log.ident)
338 				sfprintf(sp, " ");
339 			sfprintf(sp, "[%d]", getpid());
340 		}
341 		if (format)
342 		{
343 			sfprintf(sp, ": ");
344 			memset(&fmt, 0, sizeof(fmt));
345 			fmt.version = SFIO_VERSION;
346 			fmt.form = (char*)format;
347 			fmt.extf = extend;
348 			va_copy(fmt.args, ap);
349 			sfprintf(sp, "%!", &fmt);
350 		}
351 		if ((s = sfstrseek(sp, 0, SEEK_CUR)) && *(s - 1) != '\n')
352 			sfputc(sp, '\n');
353 		if (s = sfstruse(sp))
354 			sendlog(s);
355 		sfstrclose(sp);
356 	}
357 }
358 
359 void
360 syslog(int priority, const char* format, ...)
361 {
362 	va_list		ap;
363 
364 	va_start(ap, format);
365 	vsyslog(priority, format, ap);
366 	va_end(ap);
367 }
368 
369 #endif
370