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