]>
Commit | Line | Data |
---|---|---|
57b0aad2 | 1 | /* |
5222c21d | 2 | * Copyright (c) 2007-2015 Apple Inc. All rights reserved. |
57b0aad2 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5222c21d A |
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 | */ | |
81582353 | 23 | |
5222c21d A |
24 | #include <asl.h> |
25 | #include <asl_msg.h> | |
26 | #include <asl_msg_list.h> | |
27 | #include <asl_store.h> | |
28 | #include <errno.h> | |
29 | #include <vproc_priv.h> | |
57b0aad2 | 30 | |
5222c21d A |
31 | #include "asl_common.h" |
32 | #include "daemon.h" | |
33 | #include "cache_delete.h" | |
57b0aad2 | 34 | |
5222c21d A |
35 | /* global */ |
36 | bool dryrun; | |
37 | uint32_t debug; | |
38 | FILE *debugfp; | |
39 | dispatch_queue_t work_queue; | |
81582353 | 40 | |
5222c21d A |
41 | static dispatch_queue_t server_queue; |
42 | static time_t module_ttl; | |
43 | static xpc_connection_t listener; | |
44 | static bool main_task_enqueued; | |
45 | static bool initial_main_task = true; | |
46 | static dispatch_source_t sig_term_src; | |
81582353 | 47 | |
5222c21d A |
48 | /* wait 5 minutes to run main task after being invoked by XPC */ |
49 | #define MAIN_TASK_INITIAL_DELAY 300 | |
81582353 | 50 | |
5222c21d A |
51 | /* |
52 | * Used to set config parameters. | |
53 | * Line format "= name value" | |
54 | */ | |
55 | static void | |
56 | _aslmanager_set_param(asl_out_dst_data_t *dst, char *s) | |
81582353 | 57 | { |
5222c21d A |
58 | char **l; |
59 | uint32_t count; | |
81582353 | 60 | |
5222c21d A |
61 | if (s == NULL) return; |
62 | if (s[0] == '\0') return; | |
81582353 | 63 | |
5222c21d A |
64 | /* skip '=' and whitespace */ |
65 | if (*s == '=') s++; | |
66 | while ((*s == ' ') || (*s == '\t')) s++; | |
81582353 | 67 | |
5222c21d A |
68 | l = explode(s, " \t"); |
69 | if (l == NULL) return; | |
81582353 | 70 | |
5222c21d | 71 | for (count = 0; l[count] != NULL; count++); |
81582353 | 72 | |
5222c21d A |
73 | /* name is required */ |
74 | if (count == 0) | |
81582353 | 75 | { |
5222c21d A |
76 | free_string_list(l); |
77 | return; | |
81582353 A |
78 | } |
79 | ||
5222c21d A |
80 | /* value is required */ |
81 | if (count == 1) | |
81582353 | 82 | { |
5222c21d A |
83 | free_string_list(l); |
84 | return; | |
81582353 | 85 | } |
57b0aad2 | 86 | |
5222c21d | 87 | if (!strcasecmp(l[0], "aslmanager_debug")) |
f3df4c03 | 88 | { |
5222c21d A |
89 | /* = debug level */ |
90 | set_debug(DEBUG_ASL, l[1]); | |
f3df4c03 | 91 | } |
5222c21d | 92 | else if (!strcasecmp(l[0], "store_ttl")) |
81582353 | 93 | { |
5222c21d A |
94 | /* = store_ttl days */ |
95 | dst->ttl[LEVEL_ALL] = asl_core_str_to_time(l[1], SECONDS_PER_DAY); | |
57b0aad2 | 96 | } |
5222c21d | 97 | else if (!strcasecmp(l[0], "module_ttl")) |
81582353 | 98 | { |
5222c21d A |
99 | /* = module_ttl days */ |
100 | module_ttl = asl_core_str_to_time(l[1], SECONDS_PER_DAY); | |
81582353 | 101 | } |
5222c21d | 102 | else if (!strcasecmp(l[0], "max_store_size")) |
81582353 | 103 | { |
5222c21d A |
104 | /* = max_file_size bytes */ |
105 | dst->all_max = asl_core_str_to_size(l[1]); | |
81582353 | 106 | } |
5222c21d | 107 | else if (!strcasecmp(l[0], "archive")) |
81582353 | 108 | { |
5222c21d A |
109 | free(dst->rotate_dir); |
110 | dst->rotate_dir = NULL; | |
81582353 | 111 | |
5222c21d A |
112 | /* = archive {0|1} path */ |
113 | if (!strcmp(l[1], "1")) | |
114 | { | |
115 | if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); | |
116 | else dst->rotate_dir = strdup(l[2]); | |
57b0aad2 | 117 | } |
81582353 | 118 | } |
5222c21d | 119 | else if (!strcasecmp(l[0], "store_path")) |
81582353 | 120 | { |
5222c21d A |
121 | /* = archive path */ |
122 | free(dst->path); | |
123 | dst->path = strdup(l[1]); | |
81582353 | 124 | } |
5222c21d | 125 | else if (!strcasecmp(l[0], "archive_mode")) |
c4fdb7d1 | 126 | { |
5222c21d A |
127 | dst->mode = strtol(l[1], NULL, 0); |
128 | if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400; | |
c4fdb7d1 | 129 | } |
57b0aad2 | 130 | |
5222c21d | 131 | free_string_list(l); |
57b0aad2 A |
132 | } |
133 | ||
81582353 A |
134 | int |
135 | cli_main(int argc, char *argv[]) | |
136 | { | |
137 | int i, work; | |
138 | asl_out_module_t *mod, *m; | |
139 | asl_out_rule_t *r; | |
5222c21d | 140 | asl_out_dst_data_t store, opts, *asl_store_dst = NULL; |
81582353 | 141 | const char *mname = NULL; |
5222c21d A |
142 | char *path = NULL; |
143 | bool quiet = false; | |
144 | bool cache_delete = false; | |
145 | bool cache_delete_query = false; | |
81582353 | 146 | |
5222c21d | 147 | #if !TARGET_OS_SIMULATOR |
81582353 A |
148 | if (geteuid() != 0) |
149 | { | |
150 | if (argc == 0) debug = DEBUG_ASL; | |
151 | else debug = DEBUG_STDERR; | |
152 | ||
153 | debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n"); | |
154 | exit(1); | |
155 | } | |
5222c21d | 156 | #endif |
81582353 A |
157 | |
158 | module_ttl = DEFAULT_TTL; | |
159 | ||
f3df4c03 | 160 | /* cobble up a dst_data with defaults and parameter settings */ |
81582353 | 161 | memset(&store, 0, sizeof(store)); |
f3df4c03 | 162 | store.ttl[LEVEL_ALL] = DEFAULT_TTL; |
81582353 A |
163 | store.all_max = DEFAULT_MAX_SIZE; |
164 | ||
5222c21d A |
165 | memset(&opts, 0, sizeof(opts)); |
166 | opts.ttl[LEVEL_ALL] = DEFAULT_TTL; | |
167 | opts.all_max = DEFAULT_MAX_SIZE; | |
168 | ||
f3df4c03 A |
169 | for (i = 1; i < argc; i++) |
170 | { | |
5222c21d A |
171 | if (!strcmp(argv[i], "-q")) |
172 | { | |
173 | quiet = true; | |
174 | } | |
175 | else if (!strcmp(argv[i], "-dd")) | |
176 | { | |
177 | quiet = true; | |
178 | } | |
179 | else if (!strcmp(argv[i], "-s")) | |
f3df4c03 A |
180 | { |
181 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) | |
182 | { | |
183 | store.path = strdup(argv[++i]); | |
184 | asl_store_dst = &store; | |
185 | } | |
186 | } | |
187 | } | |
188 | ||
5222c21d A |
189 | if (!quiet) |
190 | { | |
191 | int status = asl_make_database_dir(NULL, NULL); | |
192 | if (status == 0) status = asl_make_database_dir(ASL_INTERNAL_LOGS_DIR, &path); | |
193 | if (status == 0) | |
194 | { | |
195 | char tstamp[32], *str = NULL; | |
196 | ||
197 | asl_make_timestamp(time(NULL), MODULE_NAME_STYLE_STAMP_LCL_B, tstamp, sizeof(tstamp)); | |
198 | asprintf(&str, "%s/aslmanager.%s", path, tstamp); | |
199 | ||
200 | if (str != NULL) | |
201 | { | |
202 | if (status == 0) debugfp = fopen(str, "w"); | |
203 | if (debugfp != NULL) debug |= DEBUG_FILE; | |
204 | free(str); | |
205 | } | |
206 | } | |
207 | } | |
208 | ||
81582353 A |
209 | /* get parameters from asl.conf */ |
210 | mod = asl_out_module_init(); | |
211 | ||
212 | if (mod != NULL) | |
213 | { | |
5222c21d | 214 | for (r = mod->ruleset; (r != NULL) && (asl_store_dst == NULL); r = r->next) |
f3df4c03 | 215 | { |
5222c21d | 216 | if ((r->dst != NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE))) |
f3df4c03 A |
217 | asl_store_dst = r->dst; |
218 | } | |
219 | ||
81582353 A |
220 | for (r = mod->ruleset; r != NULL; r = r->next) |
221 | { | |
222 | if (r->action == ACTION_SET_PARAM) | |
223 | { | |
f3df4c03 | 224 | if (r->query == NULL) _aslmanager_set_param(asl_store_dst, r->options); |
81582353 A |
225 | } |
226 | } | |
227 | } | |
228 | ||
229 | work = DO_ASLDB | DO_MODULE; | |
230 | ||
231 | for (i = 1; i < argc; i++) | |
232 | { | |
233 | if (!strcmp(argv[i], "-a")) | |
234 | { | |
5222c21d A |
235 | if (asl_store_dst == NULL) asl_store_dst = &store; |
236 | ||
f3df4c03 A |
237 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->rotate_dir = strdup(argv[++i]); |
238 | else asl_store_dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); | |
239 | asl_store_dst->mode = 0400; | |
81582353 A |
240 | } |
241 | else if (!strcmp(argv[i], "-store_ttl")) | |
242 | { | |
5222c21d A |
243 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) |
244 | { | |
245 | if (asl_store_dst == NULL) asl_store_dst = &store; | |
246 | asl_store_dst->ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY); | |
247 | } | |
81582353 A |
248 | } |
249 | else if (!strcmp(argv[i], "-module_ttl")) | |
250 | { | |
5222c21d | 251 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY); |
81582353 A |
252 | } |
253 | else if (!strcmp(argv[i], "-ttl")) | |
254 | { | |
5222c21d A |
255 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) |
256 | { | |
257 | opts.ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY); | |
258 | ||
259 | if (asl_store_dst == NULL) asl_store_dst = &store; | |
260 | asl_store_dst->ttl[LEVEL_ALL] = opts.ttl[LEVEL_ALL]; | |
261 | ||
262 | module_ttl = opts.ttl[LEVEL_ALL]; | |
263 | } | |
81582353 A |
264 | } |
265 | else if (!strcmp(argv[i], "-size")) | |
266 | { | |
5222c21d A |
267 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) |
268 | { | |
269 | opts.all_max = asl_core_str_to_size(argv[++i]); | |
270 | ||
271 | if (asl_store_dst == NULL) asl_store_dst = &store; | |
272 | asl_store_dst->all_max = opts.all_max; | |
273 | } | |
81582353 A |
274 | } |
275 | else if (!strcmp(argv[i], "-checkpoint")) | |
276 | { | |
277 | work |= DO_CHECKPT; | |
278 | } | |
5222c21d A |
279 | else if (!strcmp(argv[i], "-cache_delete")) |
280 | { | |
281 | cache_delete = true; | |
282 | if (((i + 1) < argc) && (argv[i + 1][0] == 'q')) cache_delete_query = true; | |
283 | } | |
81582353 A |
284 | else if (!strcmp(argv[i], "-module")) |
285 | { | |
286 | work &= ~DO_ASLDB; | |
287 | ||
288 | /* optional name follows -module */ | |
289 | if ((i +1) < argc) | |
290 | { | |
291 | if (argv[i + 1][0] != '-') mname = argv[++i]; | |
292 | } | |
293 | } | |
294 | else if (!strcmp(argv[i], "-asldb")) | |
295 | { | |
296 | work = DO_ASLDB; | |
297 | } | |
298 | else if (!strcmp(argv[i], "-d")) | |
299 | { | |
300 | if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); | |
301 | else set_debug(DEBUG_STDERR, NULL); | |
302 | } | |
303 | else if (!strcmp(argv[i], "-dd")) | |
304 | { | |
5222c21d | 305 | dryrun = true; |
81582353 A |
306 | |
307 | if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); | |
5222c21d | 308 | else set_debug(DEBUG_STDERR, "l7"); |
81582353 A |
309 | } |
310 | } | |
311 | ||
f3df4c03 | 312 | if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE); |
81582353 | 313 | |
5222c21d A |
314 | debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", dryrun ? " dryrun" : ""); |
315 | ||
316 | if (cache_delete) | |
317 | { | |
318 | size_t curr_size = 0; | |
319 | ||
320 | if (cache_delete_task(true, &curr_size) != 0) | |
321 | { | |
322 | debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - can't determine current size\n"); | |
323 | } | |
324 | else | |
325 | { | |
326 | debug_log(ASL_LEVEL_NOTICE, "cache delete current size = %lu\n", curr_size); | |
327 | ||
328 | if (!cache_delete_query) | |
329 | { | |
330 | size_t new_size = curr_size - opts.all_max; | |
331 | ||
332 | if (cache_delete_task(false, &new_size) != 0) | |
333 | { | |
334 | debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - delete failed\n"); | |
335 | } | |
336 | else | |
337 | { | |
338 | debug_log(ASL_LEVEL_NOTICE, "cache delete new size = %lu\n", new_size); | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | asl_out_module_free(mod); | |
344 | ||
345 | debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); | |
346 | debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : ""); | |
347 | debug_close(); | |
348 | ||
349 | return 0; | |
350 | } | |
81582353 | 351 | |
5222c21d | 352 | if (work & DO_ASLDB) process_asl_data_store(asl_store_dst, &opts); |
81582353 A |
353 | |
354 | if (work & DO_MODULE) | |
355 | { | |
356 | if (work & DO_CHECKPT) checkpoint(mname); | |
357 | ||
358 | if (mod != NULL) | |
359 | { | |
360 | for (m = mod; m != NULL; m = m->next) | |
361 | { | |
5222c21d | 362 | if (mname == NULL) |
81582353 | 363 | { |
5222c21d A |
364 | process_module(m, NULL); |
365 | } | |
366 | else if ((m->name != NULL) && (!strcmp(m->name, mname))) | |
367 | { | |
368 | process_module(m, &opts); | |
81582353 A |
369 | } |
370 | } | |
371 | } | |
372 | } | |
373 | ||
374 | asl_out_module_free(mod); | |
375 | ||
376 | debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); | |
5222c21d A |
377 | debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : ""); |
378 | debug_close(); | |
81582353 A |
379 | |
380 | return 0; | |
381 | } | |
382 | ||
5222c21d A |
383 | /* dispatched on server_queue, dispatches to work_queue */ |
384 | void | |
385 | main_task(void) | |
386 | { | |
387 | /* if main task is already running or queued, do nothing */ | |
388 | if (main_task_enqueued) return; | |
389 | ||
390 | main_task_enqueued = true; | |
391 | xpc_transaction_begin(); | |
392 | ||
393 | if (initial_main_task) | |
394 | { | |
395 | initial_main_task = false; | |
396 | dispatch_time_t delay = dispatch_walltime(NULL, MAIN_TASK_INITIAL_DELAY * NSEC_PER_SEC); | |
397 | ||
398 | dispatch_after(delay, work_queue, ^{ | |
399 | cli_main(0, NULL); | |
400 | main_task_enqueued = false; | |
401 | xpc_transaction_end(); | |
402 | }); | |
403 | } | |
404 | else | |
405 | { | |
406 | dispatch_async(work_queue, ^{ | |
407 | cli_main(0, NULL); | |
408 | main_task_enqueued = false; | |
409 | xpc_transaction_end(); | |
410 | }); | |
411 | } | |
412 | } | |
413 | ||
81582353 A |
414 | static void |
415 | accept_connection(xpc_connection_t peer) | |
416 | { | |
417 | xpc_connection_set_event_handler(peer, ^(xpc_object_t request) { | |
418 | if (xpc_get_type(request) == XPC_TYPE_DICTIONARY) | |
419 | { | |
420 | uid_t uid = xpc_connection_get_euid(peer); | |
421 | ||
422 | /* send a reply immediately */ | |
423 | xpc_object_t reply = xpc_dictionary_create_reply(request); | |
424 | xpc_connection_send_message(peer, reply); | |
425 | xpc_release(reply); | |
426 | ||
427 | /* | |
428 | * Some day, we may use the dictionary to pass parameters | |
429 | * to aslmanager, but for now, we ignore the input. | |
430 | */ | |
5222c21d A |
431 | |
432 | if (uid == geteuid()) | |
433 | { | |
434 | main_task(); | |
435 | } | |
81582353 A |
436 | } |
437 | else if (xpc_get_type(request) == XPC_TYPE_ERROR) | |
438 | { | |
439 | /* disconnect */ | |
440 | } | |
81582353 A |
441 | }); |
442 | ||
443 | xpc_connection_resume(peer); | |
444 | } | |
445 | ||
446 | int | |
447 | main(int argc, char *argv[]) | |
448 | { | |
449 | int64_t is_managed = 0; | |
450 | ||
451 | vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &is_managed); | |
452 | ||
453 | if (is_managed == 0) return cli_main(argc, argv); | |
454 | ||
5222c21d A |
455 | /* Set I/O policy */ |
456 | setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); | |
457 | ||
81582353 | 458 | /* XPC server */ |
5222c21d A |
459 | server_queue = dispatch_queue_create("aslmanager", NULL); |
460 | ||
461 | work_queue = dispatch_queue_create("work queue", NULL); | |
462 | ||
463 | /* Exit on SIGTERM */ | |
464 | signal(SIGTERM, SIG_IGN); | |
465 | sig_term_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGTERM, 0, dispatch_get_main_queue()); | |
466 | dispatch_source_set_event_handler(sig_term_src, ^{ | |
467 | debug_log(ASL_LEVEL_NOTICE, "SIGTERM exit\n"); | |
468 | exit(0); | |
469 | }); | |
470 | ||
471 | dispatch_resume(sig_term_src); | |
81582353 A |
472 | |
473 | /* Handle incoming messages. */ | |
5222c21d | 474 | listener = xpc_connection_create_mach_service("com.apple.aslmanager", server_queue, XPC_CONNECTION_MACH_SERVICE_LISTENER); |
81582353 A |
475 | xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) { |
476 | if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer); | |
477 | }); | |
478 | xpc_connection_resume(listener); | |
479 | ||
5222c21d A |
480 | cache_delete_register(); |
481 | ||
81582353 A |
482 | dispatch_main(); |
483 | } |