]>
Commit | Line | Data |
---|---|---|
b16a592a A |
1 | /* |
2 | * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
02b408bf A |
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. | |
b16a592a A |
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, | |
02b408bf A |
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. | |
b16a592a A |
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 | } |