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