]> mj.ucw.cz Git - libucw.git/blob - lib/log.c
e1fc2bed185afc946bca9cdfe03ec6f27fa96df4
[libucw.git] / lib / log.c
1 /*
2  *      Sherlock Library -- Logging
3  *
4  *      (c) 1997--2002 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "lib/lib.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <time.h>
19 #include <alloca.h>
20
21 static char log_progname[32], *log_name_patt;
22 char *log_filename;
23 char *log_title;
24 static int log_pid;
25 static int log_params;
26 static int log_filename_size;
27 int log_switch_nest;
28 void (*log_die_hook)(void);
29
30 void
31 log_fork(void)
32 {
33   log_pid = getpid();
34 }
35
36 static void
37 do_log_switch(struct tm *tm)
38 {
39   int fd, l;
40   char name[log_filename_size];
41
42   if (!log_name_patt ||
43       log_filename[0] && !log_params)
44     return;
45   log_switch_nest++;
46   l = strftime(name, log_filename_size, log_name_patt, tm);
47   if (l < 0 || l >= log_filename_size)
48     die("Error formatting log file name: %m");
49   if (strcmp(name, log_filename))
50     {
51       strcpy(log_filename, name);
52       fd = open(name, O_WRONLY | O_CREAT | O_APPEND, 0666);
53       if (fd < 0)
54         die("Unable to open log file %s: %m", name);
55       close(2);
56       dup(fd);
57       close(fd);
58       close(1);
59       dup(2);
60     }
61   log_switch_nest--;
62 }
63
64 void
65 log_switch(void)
66 {
67   time_t tim = time(NULL);
68   do_log_switch(localtime(&tim));
69 }
70
71 static inline void
72 internal_log_switch(struct tm *tm)
73 {
74   if (!log_switch_nest)
75     do_log_switch(tm);
76 }
77
78 void
79 vlog_msg(unsigned int cat, const char *msg, va_list args)
80 {
81   time_t tim = time(NULL);
82   struct tm *tm = localtime(&tim);
83   byte *buf, *p;
84   int buflen = 256;
85   int l, l0, r;
86
87   internal_log_switch(tm);
88   while (1)
89     {
90       p = buf = alloca(buflen);
91       *p++ = cat;
92       p += strftime(p, buflen, " %Y-%m-%d %H:%M:%S ", tm);
93       if (log_title)
94         {
95           if (log_pid)
96             p += sprintf(p, "[%s (%d)] ", log_title, log_pid);
97           else
98             p += sprintf(p, "[%s] ", log_title);
99         }
100       else
101         {
102           if (log_pid)
103             p += sprintf(p, "[%d] ", log_pid);
104         }
105       l0 = p - buf + 1;
106       r = buflen - l0;
107       l = vsnprintf(p, r, msg, args);
108       if (l < 0)
109         l = r;
110       else if (l < r)
111         {
112           while (*p)
113             {
114               if (*p < 0x20 && *p != '\t')
115                 *p = 0x7f;
116               p++;
117             }
118           *p = '\n';
119           write(2, buf, l + l0);
120           return;
121         }
122       buflen = l + l0 + 1;
123     }
124 }
125
126 void
127 log_msg(unsigned int cat, const char *msg, ...)
128 {
129   va_list args;
130
131   va_start(args, msg);
132   vlog_msg(cat, msg, args);
133   va_end(args);
134 }
135
136 void
137 die(byte *msg, ...)
138 {
139   va_list args;
140
141   va_start(args, msg);
142   vlog_msg(L_FATAL, msg, args);
143   va_end(args);
144   if (log_die_hook)
145     log_die_hook();
146 #ifdef DEBUG_DIE_BY_ABORT
147   abort();
148 #else
149   exit(1);
150 #endif
151 }
152
153 #ifdef DEBUG
154 void
155 assert_failed(char *assertion, char *file, int line)
156 {
157   log(L_FATAL, "Assertion `%s' failed at %s:%d", assertion, file, line);
158   abort();
159 }
160 #else
161 void
162 assert_failed(void)
163 {
164   die("Internal error: Assertion failed.");
165 }
166 #endif
167
168 static byte *
169 log_basename(byte *n)
170 {
171   byte *p = n;
172
173   while (*n)
174         if (*n++ == '/')
175           p = n;
176   return p;
177 }
178
179 void
180 log_init(byte *argv0)
181 {
182   if (argv0)
183     {
184       strncpy(log_progname, log_basename(argv0), sizeof(log_progname)-1);
185       log_progname[sizeof(log_progname)-1] = 0;
186       log_title = log_progname;
187     }
188 }
189
190 void
191 log_file(byte *name)
192 {
193   if (name)
194     {
195       if (log_name_patt)
196         xfree(log_name_patt);
197       if (log_filename)
198         {
199           xfree(log_filename);
200           log_filename = NULL;
201         }
202       log_name_patt = xstrdup(name);
203       log_params = !!strchr(name, '%');
204       log_filename_size = strlen(name) + 64;    /* 63 is an upper bound on expansion of % escapes */
205       log_filename = xmalloc(log_filename_size);
206       log_filename[0] = 0;
207       log_switch();
208       close(0);
209       open("/dev/null", O_RDWR, 0);
210     }
211 }