]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/syslogd.c
syslog-13.1.tar.gz
[apple/syslog.git] / syslogd.tproj / syslogd.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/fcntl.h>
32 #include <sys/queue.h>
33 #include <sys/time.h>
34 #include <dirent.h>
35 #include <dlfcn.h>
36 #include <libgen.h>
37 #include <notify.h>
38 #include "daemon.h"
39
40 #define DEFAULT_MARK_SEC 0
41 #define DEFAULT_PRUNE_DAYS 7
42 #define PRUNE_AFTER_START_DELAY 300
43
44 #define NOTIFY_DELAY 1
45
46 #define streq(A,B) (strcmp(A,B)==0)
47 #define forever for(;;)
48
49 static int debug = 0;
50 static int reset = 0;
51
52 static TAILQ_HEAD(ml, module_list) Moduleq;
53
54 /* global */
55 int asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
56 int prune = 0;
57
58 extern int __notify_78945668_info__;
59
60 /* Static Modules */
61 int asl_in_init();
62 int asl_in_reset();
63 int asl_in_close();
64 static int activate_asl_in = 1;
65
66 int asl_action_init();
67 int asl_action_reset();
68 int asl_action_close();
69 static int activate_asl_action = 1;
70
71 int klog_in_init();
72 int klog_in_reset();
73 int klog_in_close();
74 static int activate_klog_in = 1;
75
76 int bsd_in_init();
77 int bsd_in_reset();
78 int bsd_in_close();
79 static int activate_bsd_in = 1;
80
81 int bsd_out_init();
82 int bsd_out_reset();
83 int bsd_out_close();
84 static int activate_bsd_out = 1;
85
86 int udp_in_init();
87 int udp_in_reset();
88 int udp_in_close();
89 static int activate_udp_in = 0;
90
91 /*
92 * Module approach: only one type of module. This module may implement
93 * the set of functions necessary for any of the functions (input, output,
94 * etc.) Prior to using the modules, dlsym() is consulted to see what it
95 * implements.
96 */
97
98 static int
99 static_modules()
100 {
101 struct module_list *tmp;
102
103 if (activate_asl_in != 0)
104 {
105 tmp = calloc(1, sizeof(struct module_list));
106 if (tmp == NULL) return 1;
107 tmp->name = strdup("asl_in");
108 tmp->module = NULL;
109 tmp->init = asl_in_init;
110 tmp->reset = asl_in_reset;
111 tmp->close = asl_in_close;
112 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
113 }
114
115 if (activate_asl_action != 0)
116 {
117 tmp = calloc(1, sizeof(struct module_list));
118 if (tmp == NULL) return 1;
119 tmp->name = strdup("asl_action");
120 tmp->module = NULL;
121 tmp->init = asl_action_init;
122 tmp->reset = asl_action_reset;
123 tmp->close = asl_action_close;
124 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
125 }
126
127 if (activate_klog_in != 0)
128 {
129 tmp = calloc(1, sizeof(struct module_list));
130 if (tmp == NULL) return 1;
131 tmp->name = strdup("klog_in");
132 tmp->module = NULL;
133 tmp->init = klog_in_init;
134 tmp->reset = klog_in_reset;
135 tmp->close = klog_in_close;
136 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
137 }
138
139 if (activate_bsd_in != 0)
140 {
141 tmp = calloc(1, sizeof(struct module_list));
142 if (tmp == NULL) return 1;
143 tmp->name = strdup("bsd_in");
144 tmp->module = NULL;
145 tmp->init = bsd_in_init;
146 tmp->reset = bsd_in_reset;
147 tmp->close = bsd_in_close;
148 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
149 }
150
151 if (activate_bsd_out != 0)
152 {
153 tmp = calloc(1, sizeof(struct module_list));
154 if (tmp == NULL) return 1;
155 tmp->name = strdup("bsd_out");
156 tmp->module = NULL;
157 tmp->init = bsd_out_init;
158 tmp->reset = bsd_out_reset;
159 tmp->close = bsd_out_close;
160 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
161 }
162
163 if (activate_udp_in != 0)
164 {
165 tmp = calloc(1, sizeof(struct module_list));
166 if (tmp == NULL) return 1;
167 tmp->name = strdup("udp_in");
168 tmp->module = NULL;
169 tmp->init = udp_in_init;
170 tmp->reset = udp_in_reset;
171 tmp->close = udp_in_close;
172 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
173 }
174
175 return 0;
176 }
177
178 /*
179 * Loads all the modules. This DOES NOT call the modules initializer
180 * functions. It simply scans the modules directory looking for modules
181 * and loads them. This does not mean the module will be used.
182 */
183 static int
184 load_modules(char *mp)
185 {
186 DIR *d;
187 struct dirent *de;
188 struct module_list *tmp;
189 void *c, *bn;
190 char *modulepath = NULL;
191
192 d = opendir(mp);
193 if (d == NULL) return -1;
194
195 while (NULL != (de = readdir(d)))
196 {
197 if (de->d_name[0] == '.') continue;
198
199 /* Must have ".so" in the name" */
200 if (!strstr(de->d_name, ".so")) continue;
201
202 asprintf(&modulepath, "%s/%s", mp, de->d_name);
203 if (!modulepath) continue;
204
205 c = dlopen(modulepath, RTLD_LOCAL);
206 if (c == NULL)
207 {
208 free(modulepath);
209 continue;
210 }
211
212 tmp = calloc(1, sizeof(struct module_list));
213 if (tmp == NULL)
214 {
215 free(modulepath);
216 dlclose(c);
217 continue;
218 }
219
220 bn = basename(modulepath);
221 tmp->name = strdup(bn);
222 tmp->module = c;
223 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
224
225 tmp->init = dlsym(tmp->module, "aslmod_init");
226 tmp->reset = dlsym(tmp->module, "aslmod_reset");
227 tmp->close = dlsym(tmp->module, "aslmod_close");
228
229 free(modulepath);
230 }
231
232 closedir(d);
233
234 return 0;
235 }
236
237 static void
238 writepid(void)
239 {
240 FILE *fp;
241
242 fp = fopen(_PATH_PIDFILE, "w");
243 if (fp != NULL)
244 {
245 fprintf(fp, "%d\n", getpid());
246 fclose(fp);
247 }
248 }
249
250 static void
251 closeall(void)
252 {
253 int i;
254
255 for (i = getdtablesize() - 1; i >= 0; i--) close(i);
256
257 open("/dev/null", O_RDWR, 0);
258 dup(0);
259 dup(0);
260 }
261
262 static void
263 detach(void)
264 {
265 signal(SIGINT, SIG_IGN);
266 signal(SIGPIPE, SIG_IGN);
267 setsid();
268 }
269
270 static void
271 catch_sighup(int x)
272 {
273 reset = 1;
274 }
275
276 static void
277 catch_sigwinch(int x)
278 {
279 prune = 1;
280 }
281
282 static void
283 send_reset(void)
284 {
285 struct module_list *mod;
286
287 for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
288 {
289 if (mod->reset != NULL) mod->reset();
290 }
291 }
292
293 int
294 main(int argc, char *argv[])
295 {
296 struct module_list *mod;
297 fd_set rd, wr, ex;
298 int fd, i, max, status, pdays, daemonize;
299 time_t lastmark, msec, ssec, tick, delta, ptime, notify_time;
300 char *mp, *str;
301 struct timeval timeout, *pto;
302 asl_msg_t *pq;
303
304 mp = _PATH_MODULE_LIB;
305 msec = DEFAULT_MARK_SEC;
306 pdays = DEFAULT_PRUNE_DAYS;
307 daemonize = 0;
308 __notify_78945668_info__ = -1;
309
310 for (i = 1; i < argc; i++)
311 {
312 if (streq(argv[i], "-d"))
313 {
314 debug = 1;
315 }
316 if (streq(argv[i], "-D"))
317 {
318 daemonize = 1;
319 }
320 if (streq(argv[i], "-u"))
321 {
322 activate_udp_in = 1;
323 }
324 else if (streq(argv[i], "-m"))
325 {
326 if ((i + 1) < argc) msec = 60 * atoi(argv[++i]);
327 }
328 else if (streq(argv[i], "-p"))
329 {
330 if ((i + 1) < argc) pdays = atoi(argv[++i]);
331 }
332 else if (streq(argv[i], "-l"))
333 {
334 if ((i + 1) < argc) mp = argv[++i];
335 }
336 else if (streq(argv[i], "-c"))
337 {
338 if ((i + 1) < argc)
339 {
340 i++;
341 if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(argv[i]));
342 }
343 }
344 else if (streq(argv[i], "-asl_in"))
345 {
346 if ((i + 1) < argc) activate_asl_in = atoi(argv[++i]);
347 }
348 else if (streq(argv[i], "-asl_action"))
349 {
350 if ((i + 1) < argc) activate_asl_action = atoi(argv[++i]);
351 }
352 else if (streq(argv[i], "-klog_in"))
353 {
354 if ((i + 1) < argc) activate_klog_in = atoi(argv[++i]);
355 }
356 else if (streq(argv[i], "-bsd_in"))
357 {
358 if ((i + 1) < argc) activate_bsd_in = atoi(argv[++i]);
359 }
360 else if (streq(argv[i], "-bsd_out"))
361 {
362 if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]);
363 }
364 else if (streq(argv[i], "-udp_in"))
365 {
366 if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
367 }
368 }
369
370 TAILQ_INIT(&Moduleq);
371 static_modules();
372 load_modules(mp);
373 aslevent_init();
374
375 if (debug == 0)
376 {
377 if (daemonize != 0)
378 {
379 if (fork() != 0) exit(0);
380
381 detach();
382 closeall();
383 }
384
385 writepid();
386 }
387
388 signal(SIGHUP, catch_sighup);
389 signal(SIGWINCH, catch_sigwinch);
390
391 FD_ZERO(&rd);
392 FD_ZERO(&wr);
393 FD_ZERO(&ex);
394
395 for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
396 {
397 fd = mod->init();
398 if (fd < 0) continue;
399 }
400
401 lastmark = time(NULL);
402 notify_time = lastmark;
403 memset(&timeout, 0, sizeof(struct timeval));
404 pto = NULL;
405
406 ssec = msec;
407 if (ssec > 0)
408 {
409 timeout.tv_sec = ssec;
410 pto = &timeout;
411 }
412
413 ptime = 0;
414 if (pdays > 0) ptime = lastmark + PRUNE_AFTER_START_DELAY;
415
416 forever
417 {
418 if (pto != NULL) pto->tv_sec = ssec;
419 max = aslevent_fdsets(&rd, &wr, &ex);
420
421 status = select(max+1, &rd, &wr, &ex, pto);
422
423 if (reset != 0)
424 {
425 send_reset();
426 reset = 0;
427 }
428
429 if (pto != NULL)
430 {
431 tick = time(NULL);
432 delta = tick - lastmark;
433 if (delta >= msec)
434 {
435 lastmark = tick;
436 aslmark();
437 }
438 }
439
440 if (prune != 0)
441 {
442 asl_prune(NULL);
443 prune = 0;
444 ptime = 0;
445 }
446 else if (ptime != 0)
447 {
448 tick = time(NULL);
449 if (tick >= ptime)
450 {
451 pq = asl_new(ASL_TYPE_QUERY);
452 str = NULL;
453 asprintf(&str, "-%dd", pdays);
454 asl_set_query(pq, ASL_KEY_TIME, str, ASL_QUERY_OP_LESS);
455 if (str != NULL) free(str);
456
457 /* asl_prune frees the query */
458 asl_prune(pq);
459 ptime = 0;
460 }
461 }
462
463 if (__notify_78945668_info__ < 0)
464 {
465 tick = time(NULL);
466 if (tick >= notify_time)
467 {
468 if (notify_post("com.apple.system.syslogd") == NOTIFY_STATUS_OK) __notify_78945668_info__ = 0;
469 else notify_time = tick + NOTIFY_DELAY;
470 }
471 }
472
473 if (status != 0) aslevent_handleevent(rd, wr, ex, NULL);
474 }
475 }
476
477 int
478 asldebug(const char *str, ...)
479 {
480 va_list v;
481
482 if (debug == 0) return 0;
483
484 va_start(v, str);
485 return vprintf(str, v);
486 }