1 /*
2 
3  #        ####    ####   ######     #    #       ######           ####
4  #       #    #  #    #  #          #    #       #               #    #
5  #       #    #  #       #####      #    #       #####           #
6  #       #    #  #  ###  #          #    #       #        ###    #
7  #       #    #  #    #  #          #    #       #        ###    #    #
8  ######   ####    ####   #          #    ######  ######   ###     ####
9 
10 	Handles logging facilities.
11 */
12 
13 /*
14  * $Id$
15  *
16  *  Copyright (c) 1990-2006, Raphael Manfredi
17  *
18  *  You may redistribute only under the terms of the Artistic License,
19  *  as specified in the README file that comes with the distribution.
20  *  You may reuse parts of this distribution only within the terms of
21  *  that same Artistic License; a copy of which may be found at the root
22  *  of the source tree for mailagent 3.0.
23  *
24  * $Log: logfile.c,v $
25  * Revision 3.0.1.5  2001/01/10 16:50:08  ram
26  * patch69: fixed incorrect selection of sys_errlist[]
27  *
28  * Revision 3.0.1.4  1999/01/13  18:07:00  ram
29  * patch64: only use last two digits from year in logfiles
30  *
31  * Revision 3.0.1.3  1997/02/20  11:36:23  ram
32  * patch55: prefer open(O_APPEND) to fopen("a") for stdio append bugs
33  *
34  * Revision 3.0.1.2  1996/12/24  13:58:03  ram
35  * patch45: log onto stderr if logfile not opened correctly
36  *
37  * Revision 3.0.1.1  1994/07/01  14:53:21  ram
38  * patch8: metaconfig now defines Strerror instead of strerror
39  *
40  * Revision 3.0  1993/11/29  13:48:14  ram
41  * Baseline for mailagent 3.0 netwide release.
42  *
43  */
44 
45 #include "config.h"
46 #include "portable.h"
47 #include <stdio.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 
51 #ifdef I_STDLIB
52 #include <stdlib.h>
53 #else
54 #ifdef I_MALLOC
55 #include <malloc.h>
56 #else
57 extern char *malloc();				/* Memory allocation */
58 #endif
59 #endif	/* I_STDLIB */
60 
61 #ifdef I_STRING
62 #include <string.h>
63 #else
64 #include <strings.h>
65 #endif
66 
67 #ifdef I_TIME
68 # include <time.h>
69 #endif
70 #ifdef I_SYS_TIME
71 # include <sys/time.h>
72 #endif
73 #ifdef I_SYS_TIME_KERNEL
74 # define KERNEL
75 # include <sys/time.h>
76 # undef KERNEL
77 #endif
78 
79 #ifdef I_STRING
80 #include <string.h>
81 #else
82 #include <strings.h>
83 #endif
84 
85 /* Get the O_* constants */
86 #ifdef I_FCNTL
87 #include <fcntl.h>
88 #endif
89 #ifdef I_SYS_FILE
90 #include <sys/file.h>
91 #endif
92 #ifndef I_FCNTL
93 #ifndef I_SYS_FILE
94 #include <sys/fcntl.h>	/* Try this one in last resort */
95 #endif
96 #endif
97 
98 #include "confmagic.h"
99 
100 #define MAX_STRING	1024			/* Maximum length for logging string */
101 
102 private FILE *logfile = (FILE *) 0;	/* File pointer used for logging */
103 shared int loglvl = 20;				/* Logging level */
104 private char *logname;				/* Name of the logfile in use */
105 private void expand();				/* Run the %m %e expansion on the string */
106 private int add_error();			/* Prints description of error in errno */
107 private int add_errcode();			/* Print the symbolic error name */
108 
109 public char *progname = "ram";	/* Program name */
110 public Pid_t progpid = 0;		/* Program PID */
111 
112 extern Time_t time();			/* Time in seconds since the Epoch */
113 extern char *strsave();			/* Save string in memory */
114 extern int errno;				/* System error report variable */
115 
116 /* VARARGS2 */
add_log(level,format,arg1,arg2,arg3,arg4,arg5)117 public void add_log(level, format, arg1, arg2, arg3, arg4, arg5)
118 int level;
119 char *format;
120 long arg1, arg2, arg3, arg4, arg5;	/* Use long instead of int for 64 bits */
121 {
122 	/* Add logging informations at specified level. Note that the arguments are
123 	 * declared as 'int', but it should work fine, even when we give doubles,
124 	 * because they will be pased "as is" to fprintf. Maybe I should use
125 	 * vfprintf when it is available--RAM.
126 	 * The only magic string substitution which occurs is the '%m', which is
127 	 * replaced by the error message, as given by errno and '%e' which gives
128 	 * the symbolic name of the error (if available, otherwise the number).
129 	 * The log file must have been opened with open_log() before add_log calls.
130 	 */
131 
132 	struct tm *ct;				/* Current time (pointer to static data) */
133 	Time_t clock;				/* Number of seconds since the Epoch */
134 	char buffer[MAX_STRING];	/* Buffer which holds the expanded %m string */
135 	FILE *stdlog = logfile;		/* Where logging is to be done */
136 
137 	if (loglvl < level)			/* Logging level is not high enough */
138 		return;
139 
140 	if (logfile == (FILE *) 0)	/* Logfile not opened for whatever reason */
141 		stdlog = stderr;		/* User stderr then -- RAM, 21/10/96 */
142 
143 	clock = time((Time_t *) 0);	/* Number of seconds */
144 	ct = localtime(&clock);		/* Get local time from amount of seconds */
145 	expand(format, buffer);		/* Expansion of %m and %e into buffer */
146 
147 	fprintf(stdlog, "%.2d/%.2d/%.2d %.2d:%.2d:%.2d %s[%d]: ",
148 		ct->tm_year % 100, ct->tm_mon + 1, ct->tm_mday,
149 		ct->tm_hour, ct->tm_min, ct->tm_sec,
150 		progname, progpid);
151 
152 	fprintf(stdlog, buffer, arg1, arg2, arg3, arg4, arg5);
153 	putc('\n', stdlog);
154 	fflush(stdlog);
155 }
156 
open_log(name)157 public int open_log(name)
158 char *name;
159 {
160 	/* Open log file 'name' for logging. If a previous log file was opened,
161 	 * it is closed before. The routine returns -1 in case of error.
162 	 */
163 
164 	if (logfile != (FILE *) 0)
165 		fclose(logfile);
166 
167 	/*
168 	 * We used to perform an:
169 	 *		fopen(name, "a");
170 	 * at this point, but Sudish Joseph <joseph@cis.ohio-state.edu> has
171 	 * mentionned a possible stdio library bug whereby "a" would do a seek
172 	 * at the end before writing, hence being the target for a possible race
173 	 * condition. Use O_APPEND to fix this, if available.
174 	 */
175 
176 #ifdef O_APPEND
177 	{
178 		int fd;
179 		fd = open(name, O_WRONLY | O_CREAT | O_APPEND, 0600);
180 		if (fd == -1)
181 			return -1;
182 		logfile = fdopen(fd, "a");
183 	}
184 #else
185 	logfile = fopen(name, "a");		/* Append to existing file */
186 #endif
187 
188 	logname = strsave(name);		/* Save file name */
189 
190 	if (logfile == (FILE *) 0)
191 		return -1;
192 
193 	return 0;
194 }
195 
close_log()196 public void close_log()
197 {
198 	/* Close log file */
199 
200 	if (logfile != (FILE *) 0)
201 		fclose(logfile);
202 
203 	logfile = (FILE *) 0;
204 }
205 
set_loglvl(level)206 public void set_loglvl(level)
207 int level;
208 {
209 	/* Set logging level to 'level' */
210 
211 	loglvl = level;
212 }
213 
expand(from,to)214 private void expand(from, to)
215 char *from;
216 char *to;
217 {
218 	/* The string held in 'from' is copied into 'to' and every '%m' is expanded
219 	 * into the error message deduced from the value of errno.
220 	 */
221 
222 	int len;							/* Length of substituted text */
223 
224 	while ((*to++ = *from)) {
225 		if (*from++ == '%') {
226 			switch (*from) {
227 			case 'm':					/* %m is the English description */
228 				len = add_error(to - 1);
229 				to += len - 1;
230 				from++;
231 				break;
232 			case 'e':					/* %e is the symbolic error code */
233 				len = add_errcode(to - 1);
234 				to += len - 1;
235 				from++;
236 				break;
237 			}
238 		}
239 	}
240 }
241 
add_error(where)242 private int add_error(where)
243 char *where;
244 {
245 	/* Prints a description of the error code held in 'errno' into 'where' if
246 	 * it is available, otherwise simply print the error code number.
247 	 */
248 
249 #if !defined(HAS_STRERROR) && defined(HAS_SYS_ERRLIST)
250 	extern int sys_nerr;					/* Size of sys_errlist[] */
251 	extern char *sys_errlist[];				/* Maps error code to string */
252 #endif
253 
254 #ifdef HAS_STRERROR
255 	sprintf(where, "%s", strerror(errno));
256 #else
257 #ifdef HAS_SYS_ERRLIST
258 	sprintf(where, "%s", Strerror(errno));	/* Macro defined by Configure */
259 #else
260 	sprintf(where, "error #%d", errno);
261 #endif
262 #endif
263 
264 	return strlen(where);
265 }
266 
add_errcode(where)267 private int add_errcode(where)
268 char *where;
269 {
270 	/* Prints the symbolic description of the error code heldin in 'errno' into
271 	 * 'where' if possible. Otherwise, prints the error number.
272 	 */
273 
274 #ifdef HAS_SYS_ERRNOLIST
275 	extern int sys_nerrno;					/* Size of sys_errnolist[] */
276 	extern char *sys_errnolist[];			/* Error code to symbolic name */
277 #endif
278 
279 #ifdef HAS_SYS_ERRNOLIST
280 	if (errno < 0 || errno >= sys_nerrno)
281 		sprintf(where, "UNKNOWN");
282 	else
283 		sprintf(where, "%s", sys_errnolist[errno]);
284 #else
285 		sprintf(where, "%d", errno);
286 #endif
287 
288 	return strlen(where);
289 }
290 
291