1 /*	$NetBSD: log.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $	*/
2 
3 /*****************************************************************
4 **
5 **	@(#) log.c -- The ZKT error logging module
6 **
7 **	Copyright (c) June 2008, Holger Zuleger HZnet. All rights reserved.
8 **
9 **	This software is open source.
10 **
11 **	Redistribution and use in source and binary forms, with or without
12 **	modification, are permitted provided that the following conditions
13 **	are met:
14 **
15 **	Redistributions of source code must retain the above copyright notice,
16 **	this list of conditions and the following disclaimer.
17 **
18 **	Redistributions in binary form must reproduce the above copyright notice,
19 **	this list of conditions and the following disclaimer in the documentation
20 **	and/or other materials provided with the distribution.
21 **
22 **	Neither the name of Holger Zuleger HZnet nor the names of its contributors may
23 **	be used to endorse or promote products derived from this software without
24 **	specific prior written permission.
25 **
26 **	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 **	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 **	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 **	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30 **	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 **	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 **	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 **	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 **	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 **	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 **	POSSIBILITY OF SUCH DAMAGE.
37 **
38 **
39 *****************************************************************/
40 # include <stdio.h>
41 # include <string.h>
42 # include <stdlib.h>
43 # include <ctype.h>
44 # include <sys/types.h>
45 # include <sys/stat.h>
46 # include <sys/time.h>
47 # include <time.h>
48 # include <assert.h>
49 # include <errno.h>
50 # include <syslog.h>
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54 # include "config_zkt.h"
55 # include "misc.h"
56 # include "debug.h"
57 #define extern
58 # include "log.h"
59 #undef extern
60 
61 /*****************************************************************
62 **	module internal vars & declarations
63 *****************************************************************/
64 static	FILE	*lg_fp;
65 static	FILE	*lg_fpsave;
66 static	int	lg_minfilelevel;
67 static	int	lg_syslogging;
68 static	int	lg_minsyslevel;
69 static	long	lg_errcnt;
70 static	const char	*lg_progname;
71 
72 typedef	struct {
73 	lg_lvl_t	level;
74 	const	char	*str;
75 	int		syslog_level;
76 } lg_symtbl_t;
77 
78 static	lg_symtbl_t	symtbl[] = {
79 	{ LG_NONE,	"none",		-1 },
80 	{ LG_DEBUG,	"debug",	LOG_DEBUG },
81 	{ LG_INFO,	"info",		LOG_INFO },
82 	{ LG_NOTICE,	"notice",	LOG_NOTICE },
83 	{ LG_WARNING,	"warning",	LOG_WARNING },
84 	{ LG_ERROR,	"error",	LOG_ERR },
85 	{ LG_FATAL,	"fatal",	LOG_CRIT },
86 
87 	{ LG_NONE,	"user",		LOG_USER },
88 	{ LG_NONE,	"daemon",	LOG_DAEMON },
89 	{ LG_NONE,	"local0",	LOG_LOCAL0 },
90 	{ LG_NONE,	"local1",	LOG_LOCAL1 },
91 	{ LG_NONE,	"local2",	LOG_LOCAL2 },
92 	{ LG_NONE,	"local3",	LOG_LOCAL3 },
93 	{ LG_NONE,	"local4",	LOG_LOCAL4 },
94 	{ LG_NONE,	"local5",	LOG_LOCAL5 },
95 	{ LG_NONE,	"local6",	LOG_LOCAL6 },
96 	{ LG_NONE,	"local7",	LOG_LOCAL7 },
97 	{ LG_NONE,	NULL,		-1 }
98 };
99 
100 # define	MAXFNAME	(1023)
101 /*****************************************************************
102 **	function definitions (for function declarations see log.h)
103 *****************************************************************/
104 
105 /*****************************************************************
106 **	lg_fileopen (path, name) -- open the log file
107 **	Name is a (absolute or relative) file or directory name.
108 **	If path is given and name is a relative path name then path
109 **	is prepended to name.
110 **	returns the open file pointer or NULL on error
111 *****************************************************************/
lg_fileopen(const char * path,const char * name)112 static	FILE	*lg_fileopen (const char *path, const char *name)
113 {
114 	int	len;
115 	FILE	*fp;
116 	struct	tm	*t;
117 	time_t	sec;
118 	char	fname[MAXFNAME+1];
119 
120 	if ( name == NULL || *name == '\0' )
121 		return NULL;
122 	else if ( *name == '/' || path == NULL )
123 		snprintf (fname, MAXFNAME, "%s", name);
124 	else
125 		snprintf (fname, MAXFNAME, "%s/%s", path, name);
126 
127 # ifdef LOG_TEST
128 	fprintf (stderr, "\t ==> \"%s\"", fname);
129 # endif
130 	if ( is_directory (fname) )
131 	{
132 		len = strlen (fname);
133 
134 		time (&sec);
135 		t = gmtime (&sec);
136 		snprintf (fname+len, MAXFNAME-len, LOG_FNAMETMPL,
137 			t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
138 			t->tm_hour, t->tm_min, t->tm_sec);
139 # ifdef LOG_TEST
140 	fprintf (stderr, " isdir \"%s\"", fname);
141 # endif
142 	}
143 
144 # ifdef LOG_TEST
145 	fprintf (stderr, "\n");
146 # endif
147 
148 	if ( (fp = fopen (fname, "a")) == NULL )
149 		return NULL;
150 
151 	return fp;
152 }
153 
154 /*****************************************************************
155 **	lg_str2lvl (level_name)
156 *****************************************************************/
lg_str2lvl(const char * name)157 lg_lvl_t	lg_str2lvl (const char *name)
158 {
159 	lg_symtbl_t	*p;
160 
161 	if ( !name )
162 		return LG_NONE;
163 
164 	for ( p = symtbl; p->str; p++ )
165 		if ( strcasecmp (name, p->str) == 0 )
166 			return p->level;
167 
168 	return LG_NONE;
169 }
170 
171 /*****************************************************************
172 **	lg_lvl2syslog (level)
173 *****************************************************************/
lg_lvl2syslog(lg_lvl_t level)174 lg_lvl_t	lg_lvl2syslog (lg_lvl_t level)
175 {
176 	lg_symtbl_t	*p;
177 
178 	for ( p = symtbl; p->str; p++ )
179 		if ( level == p->level )
180 			return p->syslog_level;
181 
182 	assert ( p->str != NULL );	/* we assume not to reach this! */
183 
184 	return LOG_DEBUG;	/* if not found, return DEBUG as default */
185 }
186 
187 /*****************************************************************
188 **	lg_str2syslog (facility_name)
189 *****************************************************************/
lg_str2syslog(const char * facility)190 int	lg_str2syslog (const char *facility)
191 {
192 	lg_symtbl_t	*p;
193 
194 	dbg_val1 ("lg_str2syslog (%s)\n", facility);
195 	if ( !facility )
196 		return LG_NONE;
197 
198 	for ( p = symtbl; p->str; p++ )
199 		if ( strcasecmp (facility, p->str) == 0 )
200 			return p->syslog_level;
201 
202 	return LG_NONE;
203 }
204 
205 /*****************************************************************
206 **	lg_lvl2str (level)
207 *****************************************************************/
lg_lvl2str(lg_lvl_t level)208 const	char	*lg_lvl2str (lg_lvl_t level)
209 {
210 	lg_symtbl_t	*p;
211 
212 	if ( level < LG_DEBUG )
213 		return "none";
214 
215 	for ( p = symtbl; p->str; p++ )
216 		if ( level == p->level )
217 			return p->str;
218 	return "fatal";
219 }
220 
221 /*****************************************************************
222 **	lg_geterrcnt () -- returns the current value of the internal
223 **	error counter
224 *****************************************************************/
lg_geterrcnt()225 long	lg_geterrcnt ()
226 {
227 	return lg_errcnt;
228 }
229 
230 /*****************************************************************
231 **	lg_seterrcnt () -- sets the internal error counter
232 **	returns the current value
233 *****************************************************************/
lg_seterrcnt(long value)234 long	lg_seterrcnt (long value)
235 {
236 	return lg_errcnt = value;
237 }
238 
239 /*****************************************************************
240 **	lg_reseterrcnt () -- resets the internal error counter to 0
241 **	returns the current value
242 *****************************************************************/
lg_reseterrcnt()243 long	lg_reseterrcnt ()
244 {
245 	return lg_seterrcnt (0L);
246 }
247 
248 
249 /*****************************************************************
250 **	lg_open (prog, facility, syslevel, path, file, filelevel)
251 **		-- open the log channel
252 **	return values:
253 **		 0 on success
254 **		 -1 on file open error
255 *****************************************************************/
lg_open(const char * progname,const char * facility,const char * syslevel,const char * path,const char * file,const char * filelevel)256 int	lg_open (const char *progname, const char *facility, const char *syslevel, const char *path, const char *file, const char *filelevel)
257 {
258 	int	sysfacility;
259 
260 	dbg_val6 ("lg_open (%s, %s, %s, %s, %s, %s)\n", progname, facility, syslevel, path, file, filelevel);
261 
262 	lg_minsyslevel = lg_str2lvl (syslevel);
263 	lg_minfilelevel = lg_str2lvl (filelevel);
264 
265 	sysfacility = lg_str2syslog (facility);
266 	if ( sysfacility >= 0 )
267 	{
268 		lg_syslogging = 1;
269 		dbg_val2 ("lg_open: openlog (%s, LOG_NDELAY, %d)\n", progname, lg_str2syslog (facility));
270 		openlog (progname, LOG_NDELAY, lg_str2syslog (facility));
271 	}
272 	if ( file && * file )
273 	{
274 		if ( (lg_fp = lg_fileopen (path, file)) == NULL )
275 			return -1;
276 		lg_progname = progname;
277 	}
278 
279 	return 0;
280 }
281 
282 /*****************************************************************
283 **	lg_close () -- close the open filepointer for error logging
284 **	return 0 if no error log file is currently open,
285 **	otherwise the return code of fclose is returned.
286 *****************************************************************/
lg_close()287 int	lg_close ()
288 {
289 	int	ret = 0;
290 
291 	if ( lg_syslogging )
292 	{
293 		closelog ();
294 		lg_syslogging = 0;
295 	}
296 	if ( lg_fp )
297 	{
298 		ret = fclose (lg_fp);
299 		lg_fp = NULL;
300 	}
301 
302 	return ret;
303 }
304 
305 /*****************************************************************
306 **	lg_zone_start (domain)
307 **		-- reopen the log channel
308 **	return values:
309 **		 0 on success
310 **		 -1 on file open error
311 *****************************************************************/
lg_zone_start(const char * dir,const char * domain)312 int	lg_zone_start (const char *dir, const char *domain)
313 {
314 	char	fname[255+1];
315 
316 	dbg_val2 ("lg_zone_start (%s, %s)\n", dir, domain);
317 
318 	snprintf (fname, sizeof (fname), LOG_DOMAINTMPL, domain);
319 	if ( lg_fp )
320 		lg_fpsave = lg_fp;
321 	lg_fp = lg_fileopen (dir, fname);
322 
323 	return lg_fp != NULL;
324 }
325 
326 /*****************************************************************
327 **	lg_zone_end (domain)
328 **		-- close the (reopened) log channel
329 **	return values:
330 **		 0 on success
331 **		 -1 on file open error
332 *****************************************************************/
lg_zone_end()333 int	lg_zone_end ()
334 {
335 	if ( lg_fp && lg_fpsave )
336 	{
337 		lg_close ();
338 		lg_fp = lg_fpsave;
339 		lg_fpsave = NULL;
340 		return 1;
341 	}
342 
343 	return 0;
344 }
345 
346 /*****************************************************************
347 **
348 **	lg_args (level, argc, argv[])
349 **	log all command line arguments (up to a length of 511 chars)
350 **	with priority level
351 **
352 *****************************************************************/
lg_args(lg_lvl_t level,int argc,char * const argv[])353 void	lg_args (lg_lvl_t level, int argc, char * const argv[])
354 {
355 	char	cmdline[511+1];
356 	int	len;
357 	int	i;
358 
359 	len = 0;
360 	for ( i = 0; i < argc && len < sizeof (cmdline); i++ )
361 		len += snprintf (cmdline+len, sizeof (cmdline) - len, " %s", argv[i]);
362 
363 #if 1
364 	lg_mesg (level, "------------------------------------------------------------");
365 #else
366 	lg_mesg (level, "");
367 #endif
368 	lg_mesg (level, "running%s ", cmdline);
369 }
370 
371 /*****************************************************************
372 **
373 **	lg_mesg (level, fmt, ...)
374 **
375 **	Write a given message to the error log file and counts
376 **	all messages written with an level greater than LOG_ERR.
377 **
378 **	All messages will be on one line in the logfile, so it's
379 **	not necessary to add an '\n' to the message.
380 **
381 **	To call this function before an elog_open() is called is
382 **	useless!
383 **
384 *****************************************************************/
lg_mesg(int priority,char * fmt,...)385 void	lg_mesg (int priority, char *fmt, ...)
386 {
387 	va_list ap;
388 	struct	timeval	tv;
389 	struct	tm	*t;
390 	char	format[256];
391 
392 	assert (fmt != NULL);
393 	assert (priority >= LG_DEBUG && priority <= LG_FATAL);
394 
395 	format[0] ='\0';
396 
397 	dbg_val3 ("syslog = %d prio = %d >= sysmin = %d\n", lg_syslogging, priority, lg_minsyslevel);
398 	if ( lg_syslogging && priority >= lg_minsyslevel )
399 	{
400 #if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL
401 		snprintf (format, sizeof (format), "%s: %s", lg_lvl2str(priority), fmt);
402 		fmt = format;
403 #endif
404 		va_start(ap, fmt);
405 		vsyslog (lg_lvl2syslog (priority), fmt, ap);
406 		va_end(ap);
407 	}
408 
409 	dbg_val3 ("filelg = %d prio = %d >= filmin = %d\n", lg_fp!=NULL, priority, lg_minfilelevel);
410 	if ( lg_fp && priority >= lg_minfilelevel )
411 	{
412 #if defined (LOG_WITH_TIMESTAMP) && LOG_WITH_TIMESTAMP
413 		gettimeofday (&tv, NULL);
414 		t = localtime ((time_t *) &tv.tv_sec);
415 		fprintf (lg_fp, "%04d-%02d-%02d ",
416 			t->tm_year+1900, t->tm_mon+1, t->tm_mday);
417 		fprintf (lg_fp, "%02d:%02d:%02d.%03ld: ",
418 			t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000);
419 #endif
420 #if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME
421 		if ( lg_progname )
422 			fprintf (lg_fp, "%s: ", lg_progname);
423 #endif
424 #if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL
425 		if ( fmt != format )	/* level is not in fmt string */
426 			fprintf (lg_fp, "%s: ", lg_lvl2str(priority));
427 #endif
428 		va_start(ap, fmt);
429 		vfprintf (lg_fp, fmt, ap);
430 		va_end(ap);
431 		fprintf (lg_fp, "\n");
432 	}
433 
434 	if ( priority >= LG_ERROR )
435 		lg_errcnt++;
436 }
437 
438 
439 #ifdef LOG_TEST
440 const char *progname;
main(int argc,char * argv[])441 int	main (int argc, char *argv[])
442 {
443 	const	char	*levelstr;
444 	const	char	*newlevelstr;
445 	int	level;
446 	int	err;
447 
448 	progname = *argv;
449 
450 	if ( --argc )
451 		levelstr = *++argv;
452 	else
453 		levelstr = "fatal";
454 
455 	level = lg_str2lvl (levelstr);
456 	newlevelstr = lg_lvl2str (level+1);
457 	dbg_val4 ("base level = %s(%d) newlevel = %s(%d)\n", levelstr, level, newlevelstr, level+1);
458 	if ( (err = lg_open (progname,
459 #if 1
460 				"user",
461 #else
462 				"none",
463 #endif
464 				levelstr, ".",
465 #if 1
466 				"test.log",
467 #else
468 				NULL,
469 #endif
470 				newlevelstr)) )
471 		fprintf (stderr, "\topen error %d\n", err);
472 	else
473 	{
474 		lg_mesg (LG_DEBUG, "debug message");
475 		lg_mesg (LG_INFO, "INFO message");
476 		lg_mesg (LG_NOTICE, "Notice message");
477 		lg_mesg (LG_WARNING, "Warning message");
478 		lg_mesg (LG_ERROR, "Error message");
479 		lg_mesg (LG_FATAL, "Fatal message ");
480 	}
481 
482 	if ( (err = lg_close ()) < 0 )
483 		fprintf (stderr, "\tclose error %d\n", err);
484 
485 	return 0;
486 }
487 #endif
488