]> the.earth.li Git - onak.git/blob - log.c
Avoid race condition when receiving incoming mails
[onak.git] / log.c
1 /*
2  * log.c - Simple logging framework.
3  *
4  * Copyright 2003 Jonathan McDowell <noodles@earth.li>
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26
27 #include "log.h"
28
29 /*
30  *      logthres - holds the minimum log level we'll output
31  *
32  *      This variable keeps track of the threshold we've set for outputting
33  *      logs - if we're asked to log something below this level we won't output
34  *      it.
35  */
36 static loglevels logthres = LOGTHING_NOTICE;
37
38 /*
39  *      logappname - the name of the application using us.
40  *
41  *      This holds information about the name of the application we're being
42  *      called by. It's set when we're initialized.
43  */
44 static char *logappname = NULL;
45
46 /*
47  *      logfilename - the file to log to.
48  *
49  *      The full name and path of the file we should log to.
50  */
51 static char *logfilename = NULL;
52
53 /*
54  *      initlogthing - initialize the logging module
55  *      @appname: The application name to use in the log.
56  *      @filename: The filename to log to. NULL means stderr.
57  *
58  *      This function sets up the logging module ready to log. The appname is
59  *      written as part of every log entry and the filename is the file we
60  *      should log to. If the appname is NULL then none is written. If the
61  *      filename is NULL all output is sent to stderr.
62  */
63 int initlogthing(const char *appname, const char *filename)
64 {
65         if (appname != NULL) {
66                 logappname = strdup(appname);
67         }
68
69         if (filename != NULL) {
70                 logfilename = strdup(filename);
71         }
72
73         return 0;
74 }
75
76 /*
77  *      cleanuplogthing - clean up the logging module
78  *
79  *      This function cleans up the logging module after use.
80  */
81 void cleanuplogthing(void)
82 {
83         if (logappname != NULL) {
84                 free(logappname);
85                 logappname = NULL;
86         }
87
88         if (logfilename != NULL) {
89                 free(logfilename);
90                 logfilename = NULL;
91         }
92
93         return;
94 }
95
96 /*
97  *      setlogthreshold - set the threshold for log output
98  *      @loglevel: The minimum log level we should output
99  *
100  *      Sets the threshold for log output; anything logged with a log level
101  *      lower than this will be silently dropped. Returns the old log threshold
102  *      value.
103  */
104 loglevels setlogthreshold(loglevels loglevel)
105 {
106         loglevels oldlevel;
107
108         oldlevel = logthres;
109         logthres = loglevel;
110
111         return oldlevel;
112 }
113
114 /*
115  *      vflog - write a log entry to an already opened log file.
116  *      @logfile: The FILE * handle of the open log file.
117  *      @format: A format string.
118  *      @ap: The va_list of the parmeters for the format string.
119  *
120  *      This function outputs a log entry to an opened file. A leading
121  *      time/date stamp and a trailing newline are automatically added. The
122  *      format parameter is of the same nature as that used in vprintf.
123  */
124 static void vflog(FILE *logfile, const char *format, va_list ap)
125 {
126         struct tm *timestamp = NULL;
127         time_t     timer = 0;
128
129         timer = time(NULL);
130         timestamp = localtime(&timer);
131
132         fprintf(logfile, "[%02d/%02d/%4d %02d:%02d:%02d] %s[%d]: ",
133                         timestamp->tm_mday,
134                         timestamp->tm_mon + 1,
135                         timestamp->tm_year + 1900,
136                         timestamp->tm_hour,
137                         timestamp->tm_min,
138                         timestamp->tm_sec,
139                         (logappname == NULL) ? "" : logappname,
140                         getpid());
141         vfprintf(logfile, format, ap);
142         fprintf(logfile, "\n");
143
144         return;
145 }
146
147 /*
148  *      flog - write a log entry to an already opened log file.
149  *      @logfile: The FILE * handle of the open log file.
150  *      @format: A format string.
151  *
152  *      This function outputs a log entry to an opened file. A leading
153  *      time/date stamp and a trailing newline are automatically added. The
154  *      format parameter is of the same nature as that used in printf.
155  */
156 static void flog(FILE *logfile, const char *format, ...)
157 {
158         va_list ap;
159
160         va_start(ap, format);
161         vflog(logfile, format, ap);
162         va_end(ap);
163 }
164
165 /*
166  *      logthing - output a log entry
167  *      @loglevel: The level of the log.
168  *      @format: A format string, followed by any parameters required.
169  *
170  *      This function outputs a log entry. A leading time/date stamp and a
171  *      trailing newline are automatically added. The loglevel is compared to
172  *      the current log threshold and if equal or above the log entry is
173  *      output. The format parameter is of the same nature as that used in
174  *      printf.
175  */
176 int logthing(loglevels loglevel, const char *format, ...)
177 {
178         FILE      *logfile = NULL;
179         va_list    ap;
180
181         if (loglevel >= logthres) {
182                 if (logfilename != NULL) {
183                         logfile = fopen(logfilename, "a");
184                         if (logfile != NULL) {
185                                 flockfile(logfile);
186                         } else {
187                                 logfile = stderr;
188                                 flog(logfile, "Couldn't open logfile: %s",
189                                                 logfilename);
190                         }
191                 } else {
192                         logfile = stderr;
193                 }
194         
195                 va_start(ap, format);
196                 vflog(logfile, format, ap);
197                 va_end(ap);
198
199                 if (logfile != stderr) {
200                         funlockfile(logfile);
201                         fclose(logfile);
202                         logfile = NULL;
203                 }
204         }
205
206         return 0;
207 }