chiark / gitweb /
229e9dca5027dd05e2d23015468bdc5098f8ceec
[sympathy.git] / src / log.c
1 /* 
2  * log.c:
3  *
4  * Copyright (c) 2008 James McKenzie <james@fishsoup.dhs.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] = "$Id: log.c,v 1.17 2011/02/04 16:14:16 james Exp $";
10
11 /* 
12  * $Log: log.c,v $
13  * Revision 1.17  2011/02/04 16:14:16  james
14  * *** empty log message ***
15  *
16  * Revision 1.16  2010/07/27 14:49:35  james
17  * add support for byte logging
18  *
19  * Revision 1.15  2010/07/16 11:04:10  james
20  * ignore tedious return values
21  *
22  * Revision 1.14  2008/03/11 17:56:04  james
23  * *** empty log message ***
24  *
25  * Revision 1.13  2008/03/11 16:56:29  james
26  * *** empty log message ***
27  *
28  * Revision 1.12  2008/03/10 11:49:33  james
29  * *** empty log message ***
30  *
31  * Revision 1.11  2008/03/07 13:16:02  james
32  * *** empty log message ***
33  *
34  * Revision 1.10  2008/03/07 12:37:04  james
35  * *** empty log message ***
36  *
37  * Revision 1.9  2008/03/03 06:20:14  james
38  * *** empty log message ***
39  *
40  * Revision 1.8  2008/03/03 06:04:42  james
41  * *** empty log message ***
42  *
43  * Revision 1.7  2008/03/03 06:04:18  james
44  * *** empty log message ***
45  *
46  * Revision 1.6  2008/03/02 10:37:56  james
47  * *** empty log message ***
48  *
49  * Revision 1.5  2008/02/27 01:31:14  james
50  * *** empty log message ***
51  *
52  * Revision 1.4  2008/02/27 00:54:16  james
53  * *** empty log message ***
54  *
55  * Revision 1.3  2008/02/23 11:48:37  james
56  * *** empty log message ***
57  *
58  * Revision 1.2  2008/02/22 14:51:54  james
59  * *** empty log message ***
60  *
61  * Revision 1.1  2008/02/14 12:14:50  james
62  * *** empty log message ***
63  *
64  */
65
66 #include "project.h"
67
68 typedef struct {
69   LOG_SIGNATURE;
70   int do_close;
71   int rotate;
72   FILE *fp;
73   char *filename;
74   int needs_newline;
75 } File_Log;
76
77
78 static Log *loggers = NULL;
79
80
81 static void
82 sighup (int dummy)
83 {
84   Log *l;
85
86   for (l = loggers; l; l = l->next) {
87     if (l->sighup)
88       l->sighup (l);
89   }
90 }
91
92
93 void
94 log_register_handlers (void)
95 {
96   struct sigaction sa = { 0 };
97
98   sa.sa_handler = sighup;
99   sa.sa_flags = SA_RESTART;
100   sigaction (SIGHUP, &sa, NULL);
101 }
102
103
104 void
105 log_add (Log * l)
106 {
107   log_register_handlers ();
108
109   l->next = loggers;
110   loggers = l;
111 }
112
113 void
114 log_remove (Log * l)
115 {
116   Log **ptr = &loggers;
117
118   /* Take out of sighup list */
119   while (*ptr && (*ptr != l))
120     ptr = &((*ptr)->next);
121
122   if (*ptr)
123     *ptr = l->next;
124 }
125
126 static void flog_newline(Log *_l,int force) 
127 {
128   File_Log *l = (File_Log *) _l;
129
130   if (force || !l->needs_newline) return;
131
132   l->needs_newline=0;
133
134   fputc ('\n', l->fp);
135   fflush (l->fp);
136 }
137
138
139 static void
140 flog_sighup (Log * _l)
141 {
142   File_Log *l = (File_Log *) _l;
143   if (!l->fp)
144     return;
145
146   log_f (_l, "<sighup received - closing log file>");
147   fclose (l->fp);
148
149   l->fp = fopen (l->filename, "a+");
150   log_f (_l, "<sighup received - opening log file>");
151 }
152
153 static void 
154 flog_emit_stamp(Log *_l)
155 {
156   File_Log *l = (File_Log *) _l;
157   struct timeval tv = { 0 };
158   struct tm *tm;
159   time_t t;
160   static const char *days[] = { "Sun", "Mon", "Tue",
161     "Wed", "Thu", "Fri", "Sat"
162   };
163   static const char *months[] = {
164     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
165     "Nov", "Dec"
166   };
167
168   if (!l->fp)
169     return;
170
171   flog_newline(_l,0);
172
173   gettimeofday (&tv, NULL);
174   t = tv.tv_sec;
175   tm = localtime (&t);
176
177   fprintf (l->fp, "%s %2d %02d:%02d:%02d.%06d ", months[tm->tm_mon],
178            tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,(int) tv.tv_usec);
179 }
180
181
182 static void flog_check_rotate(Log *_l)
183 {
184   File_Log *l = (File_Log *) _l;
185
186   if (l->rotate && rotate_check (l->filename)) {
187     fclose (l->fp);
188     rotate (l->filename);
189     l->fp = fopen (l->filename, "a+");
190   }
191 }
192
193
194 static void
195 flog_log_bytes (Log * _l, void *_buf,int len)
196 {
197   File_Log *l = (File_Log *) _l;
198   uint8_t *buf=(uint8_t *) _buf;
199
200   if (!l->fp)
201     return;
202
203   while (len--) {
204         if (*buf=='\n') {
205                 flog_newline(_l,1);     
206                 flog_check_rotate(_l);
207                 flog_emit_stamp(_l);
208         } else { 
209                 l->needs_newline++;
210                 fputc (*buf, l->fp);
211         }
212         buf++;
213   }
214 }
215
216 static void
217 flog_log (Log * _l, char *buf)
218 {
219   File_Log *l = (File_Log *) _l;
220
221   if (!l->fp)
222     return;
223
224   flog_emit_stamp(_l);
225
226   fputs (buf, l->fp);
227   fputc ('\n', l->fp);
228   fflush (l->fp);
229
230   flog_check_rotate(_l);
231 }
232
233
234
235
236 static void
237 flog_close (Log * _l)
238 {
239   File_Log *l = (File_Log *) _l;
240   if (l->fp && l->do_close)
241     fclose (l->fp);
242   if (l->filename)
243     free (l->filename);
244   free (l);
245 }
246
247 Log *
248 file_log_new (char *fn, int rotate)
249 {
250   File_Log *l;
251   int dc = 1;
252
253   l = xmalloc (sizeof (File_Log));
254
255   if (fn && strcmp (fn, "-")) {
256     l->fp = fopen (fn, "a+");
257     if (!l->fp) {
258       free (l);
259       return NULL;
260     }
261     l->sighup = flog_sighup;
262   } else {
263     l->fp = stderr;
264     dc = 0;
265   }
266
267
268   l->log = flog_log;
269   l->log_bytes = flog_log_bytes;
270   l->close = flog_close;
271   l->do_close = dc;
272   l->rotate = rotate;
273   l->filename = strdup (fn);
274
275   l->needs_newline=0;
276
277   fput_cp (l->fp, 0xffef);
278
279   log_add ((Log *) l);
280
281   return (Log *) l;
282 }
283
284 void
285 log_f (Log * log, char *fmt, ...)
286 {
287
288   int n;
289   static char *buf;
290   va_list ap;
291   static int size;
292
293   if (!log)
294     return;
295
296   if (!size) {
297     size = 128;
298     buf = malloc (size);
299   }
300
301   if (!buf)
302     return;
303
304   while (1) {
305     va_start (ap, fmt);
306     n = vsnprintf (buf, size, fmt, ap);
307     va_end (ap);
308
309     if (n > -1 && n < size) {
310       log->log (log, buf);
311       return;
312     }
313
314     if (n > -1)                 /* glibc 2.1 */
315       size = n + 1;
316     else                        /* glibc 2.0 */
317       size *= 2;                /* twice the old size */
318
319     buf = xrealloc (buf, size);
320
321     if (!buf)
322       return;
323   }
324 }