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