]> git.saurik.com Git - apple/syslog.git/blame - aslmanager.tproj/aslmanager.c
syslog-323.50.1.tar.gz
[apple/syslog.git] / aslmanager.tproj / aslmanager.c
CommitLineData
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 */
36bool dryrun;
37uint32_t debug;
38FILE *debugfp;
39dispatch_queue_t work_queue;
81582353 40
5222c21d
A
41static dispatch_queue_t server_queue;
42static time_t module_ttl;
43static xpc_connection_t listener;
44static bool main_task_enqueued;
45static bool initial_main_task = true;
46static 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 */
55static 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
134int
135cli_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 */
384void
385main_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
414static void
415accept_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
446int
447main(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}