1 #include <errno.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdarg.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8
9 #include "version.h"
10 #include "str.h"
11
12 int use_syslog = 0;
13 static FILE *logfp = 0;
14
15 #ifdef HAVE_SYSLOG
16 #include <syslog.h>
17
18 const int log_debug = LOG_DEBUG;
19 const int log_info = LOG_INFO;
20 const int log_warning = LOG_WARNING;
21 const int log_fatal = LOG_CRIT;
22
23 #else
24
25 const int log_debug = -1;
26 const int log_info = 0;
27 const int log_warning = 1;
28 const int log_fatal = 2;
29
30 #endif
31
log_pipe(const char * s)32 static void log_pipe(const char *s)
33 {
34 int fds[2];
35
36 if (pipe(fds) == -1) {
37 cfatal("Could not create pipe: %s");
38 }
39
40 switch (fork()) {
41 case -1:
42 cfatal("Could not fork: %s");
43 break;
44 case 0:
45 close(0);
46 close(1);
47 close(2);
48 dup2(fds[0], 0);
49 execl("/bin/sh", "/bin/sh", "-c", s);
50 exit(1);
51 };
52 close(fds[0]);
53 logfp = fdopen(fds[1], "w");
54 if (!logfp) {
55 logfp = stderr;
56 cfatal("Could not attach fd to logger: %s");
57 }
58 }
log_file(const char * s)59 static void log_file(const char *s)
60 {
61 int fd;
62
63 fd = open(s, O_CREAT|O_WRONLY|O_APPEND, 0666);
64 if (fd == -1) {
65 cfatal("Could not open `%s' for writing: %s", s);
66 }
67
68 logfp = fdopen(fd, "w");
69 if (!logfp) {
70 logfp = stderr;
71 cfatal("Could not attach fd to logger: %s");
72 }
73 }
74
log_init(char * s)75 void log_init(char *s)
76 {
77 int fd;
78
79 use_syslog = 0;
80 logfp = stderr;
81 if (s && str_equali(s, "quiet")) {
82 logfp = fopen("/dev/null", "w");
83 } else if (s && *s == '/') {
84 log_file(s);
85 } else if (s && *s == '|') {
86 log_pipe(s+1);
87 } else if (s && str_starti(s, "file:/")) {
88 log_file(s+5);
89 } else if (s && str_starti(s, "pipe:/")) {
90 log_pipe(s+5);
91 } else if (s && str_starti(s, "exec:/")) {
92 log_pipe(s+5);
93 } else if (s && str_starti(s, "prog:/")) {
94 log_pipe(s+5);
95 } else if (s && str_starti(s, "program:/")) {
96 log_pipe(s+8);
97
98 } else if (s && str_equali(s, "syslog")) {
99 #ifdef HAVE_SYSLOG
100 use_syslog = 1;
101 openlog(PROGRAM, LOG_CONS | LOG_NDELAY
102 #ifdef LOG_PERROR
103 | LOG_PERROR
104 #endif
105 | LOG_PID, LOG_DAEMON);
106 logfp = 0;
107 #else
108 use_syslog = 0;
109 warning("You do not have syslog() support compiled in, defaulting to stderr");
110 #endif
111 }
112 }
_log_helper(int lev,int clib_flag,const char * m,va_list ap)113 static void _log_helper(int lev, int clib_flag, const char *m, va_list ap)
114 {
115 str_t buf;
116 char lbuf[32];
117
118 str_init(buf);
119 while (*m) {
120 if (*m == '%') {
121 switch (m[1]) {
122 case '%':
123 str_addch(buf, '%');
124 break;
125 case 's':
126 if (clib_flag) {/* Clib */
127 clib_flag = 0;
128 str_cat(buf, strerror(errno));
129 } else
130 str_cat(buf, va_arg(ap, char *));
131 break;
132 case 'd':
133 sprintf(lbuf, "%d", va_arg(ap, int));
134 str_cat(buf, lbuf);
135 break;
136 case 'c':
137 str_addch(buf, va_arg(ap, int));
138 break;
139 default:
140 fatal("unknown log() specifier %%%c", m[1]);
141 };
142 m++; m++;
143 } else {
144 str_addch(buf, m[0]);
145 m++;
146 }
147 }
148 #ifdef HAVE_SYSLOG
149 if (use_syslog) {
150 fprintf(stderr, "level = %d: %s\n", lev, str(buf));
151 syslog(lev, "%s", str(buf));
152 } else
153 #endif
154 if (logfp) {
155 fprintf(logfp, "%s %s: %s\n", PROGRAM,
156 (lev == log_info ? "info"
157 :lev == log_warning ? "warning"
158 :lev == log_debug ? "debug"
159 :"fatal"),
160 str(buf));
161 fflush(logfp);
162 }
163 mem_free(str(buf));
164 }
status(const char * s,...)165 void inline status(const char *s, ...)
166 {
167 va_list ap;
168
169 if (!logfp) return;
170 va_start(ap, s);
171 vfprintf(logfp, s, ap);
172 fputc('\n', logfp);
173 fflush(logfp);
174 va_end(ap);
175 }
log(int lev,const char * m,...)176 void inline log(int lev, const char *m, ...)
177 {
178 va_list ap;
179 va_start(ap, m);
180 _log_helper(lev, 0, m, ap);
181 va_end(ap);
182 }
183 #define MAKE_LOGGING_FUNCTION(A,B) \
184 void inline A(const char *m, ...) \
185 { \
186 va_list ap; \
187 va_start(ap, m); \
188 _log_helper(log_ ## A, 0, m, ap); \
189 va_end(ap); B; \
190 } \
191 void inline c ## A(const char *m, ...) \
192 { \
193 va_list ap; \
194 va_start(ap, m); \
195 _log_helper(log_ ## A, 1, m, ap); \
196 va_end(ap); B; \
197 }
198 MAKE_LOGGING_FUNCTION(fatal,exit(1))
199 MAKE_LOGGING_FUNCTION(warning,return)
200 MAKE_LOGGING_FUNCTION(debug,return)
201 #undef MAKE_LOGGING_FUNCTION
202