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