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