2 * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <asl_msg_list.h>
27 #include <asl_store.h>
29 #include <vproc_priv.h>
30 #include <os/transaction_private.h>
32 #include "asl_common.h"
39 dispatch_queue_t work_queue
;
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
;
48 /* wait 5 minutes to run main task after being invoked by XPC */
49 #define MAIN_TASK_INITIAL_DELAY 300
52 * Used to set config parameters.
53 * Line format "= name value"
56 _aslmanager_set_param(asl_out_dst_data_t
*dst
, char *s
)
61 if (s
== NULL
) return;
62 if (s
[0] == '\0') return;
64 /* skip '=' and whitespace */
66 while ((*s
== ' ') || (*s
== '\t')) s
++;
68 l
= explode(s
, " \t");
69 if (l
== NULL
) return;
71 for (count
= 0; l
[count
] != NULL
; count
++);
73 /* name is required */
80 /* value is required */
87 if (!strcasecmp(l
[0], "aslmanager_debug"))
90 set_debug(DEBUG_ASL
, l
[1]);
92 else if (!strcasecmp(l
[0], "store_ttl"))
94 /* = store_ttl days */
95 dst
->ttl
[LEVEL_ALL
] = asl_core_str_to_time(l
[1], SECONDS_PER_DAY
);
97 else if (!strcasecmp(l
[0], "module_ttl"))
99 /* = module_ttl days */
100 module_ttl
= asl_core_str_to_time(l
[1], SECONDS_PER_DAY
);
102 else if (!strcasecmp(l
[0], "max_store_size"))
104 /* = max_file_size bytes */
105 dst
->all_max
= asl_core_str_to_size(l
[1]);
107 else if (!strcasecmp(l
[0], "archive"))
109 free(dst
->rotate_dir
);
110 dst
->rotate_dir
= NULL
;
112 /* = archive {0|1} path */
113 if (!strcmp(l
[1], "1"))
115 if (l
[2] == NULL
) dst
->rotate_dir
= strdup(PATH_ASL_ARCHIVE
);
116 else dst
->rotate_dir
= strdup(l
[2]);
119 else if (!strcasecmp(l
[0], "store_path"))
123 dst
->path
= strdup(l
[1]);
125 else if (!strcasecmp(l
[0], "archive_mode"))
127 dst
->mode
= strtol(l
[1], NULL
, 0);
128 if ((dst
->mode
== 0) && (errno
== EINVAL
)) dst
->mode
= 0400;
135 cli_main(int argc
, char *argv
[])
138 asl_out_module_t
*mod
, *m
;
140 asl_out_dst_data_t store
, opts
, *asl_store_dst
= NULL
;
141 const char *mname
= NULL
;
144 #if !TARGET_OS_SIMULATOR
147 if (argc
== 0) debug
= DEBUG_ASL
;
148 else debug
= DEBUG_STDERR
;
150 debug_log(ASL_LEVEL_ERR
, "aslmanager must be run by root\n");
155 module_ttl
= DEFAULT_TTL
;
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
;
162 memset(&opts
, 0, sizeof(opts
));
163 opts
.ttl
[LEVEL_ALL
] = DEFAULT_TTL
;
164 opts
.all_max
= DEFAULT_MAX_SIZE
;
166 for (i
= 1; i
< argc
; i
++)
168 if (!strcmp(argv
[i
], "-q"))
172 else if (!strcmp(argv
[i
], "-dd"))
176 else if (!strcmp(argv
[i
], "-s"))
178 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
180 store
.path
= strdup(argv
[++i
]);
181 asl_store_dst
= &store
;
189 int status
= asl_make_database_dir(NULL
, NULL
);
190 if (status
== 0) status
= asl_make_database_dir(ASL_INTERNAL_LOGS_DIR
, &path
);
193 char tstamp
[32], *str
= NULL
;
195 asl_make_timestamp(time(NULL
), MODULE_NAME_STYLE_STAMP_LCL_B
, tstamp
, sizeof(tstamp
));
196 asprintf(&str
, "%s/aslmanager.%s", path
, tstamp
);
200 if (status
== 0) debugfp
= fopen(str
, "w");
201 if (debugfp
!= NULL
) debug
|= DEBUG_FILE
;
208 /* get parameters from asl.conf */
209 mod
= asl_out_module_init();
213 for (r
= mod
->ruleset
; (r
!= NULL
) && (asl_store_dst
== NULL
); r
= r
->next
)
215 if ((r
->dst
!= NULL
) && (r
->action
== ACTION_OUT_DEST
) && (!strcmp(r
->dst
->path
, PATH_ASL_STORE
)))
216 asl_store_dst
= r
->dst
;
219 for (r
= mod
->ruleset
; r
!= NULL
; r
= r
->next
)
221 if (r
->action
== ACTION_SET_PARAM
)
223 if (r
->query
== NULL
) _aslmanager_set_param(asl_store_dst
, r
->options
);
228 work
= DO_ASLDB
| DO_MODULE
;
230 for (i
= 1; i
< argc
; i
++)
232 if (!strcmp(argv
[i
], "-a"))
234 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
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;
240 else if (!strcmp(argv
[i
], "-store_ttl"))
242 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
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
);
248 else if (!strcmp(argv
[i
], "-module_ttl"))
250 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-')) module_ttl
= asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
252 else if (!strcmp(argv
[i
], "-ttl"))
254 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
256 opts
.ttl
[LEVEL_ALL
] = asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
258 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
259 asl_store_dst
->ttl
[LEVEL_ALL
] = opts
.ttl
[LEVEL_ALL
];
261 module_ttl
= opts
.ttl
[LEVEL_ALL
];
264 else if (!strcmp(argv
[i
], "-size"))
266 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
268 opts
.all_max
= asl_core_str_to_size(argv
[++i
]);
270 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
271 asl_store_dst
->all_max
= opts
.all_max
;
274 else if (!strcmp(argv
[i
], "-checkpoint"))
278 else if (!strcmp(argv
[i
], "-module"))
282 /* optional name follows -module */
285 if (argv
[i
+ 1][0] != '-') mname
= argv
[++i
];
288 else if (!strcmp(argv
[i
], "-asldb"))
292 else if (!strcmp(argv
[i
], "-d"))
294 if (((i
+ i
) < argc
) && (argv
[i
+1][0] != '-')) set_debug(DEBUG_STDERR
, argv
[++i
]);
295 else set_debug(DEBUG_STDERR
, NULL
);
297 else if (!strcmp(argv
[i
], "-dd"))
301 if (((i
+ i
) < argc
) && (argv
[i
+1][0] != '-')) set_debug(DEBUG_STDERR
, argv
[++i
]);
302 else set_debug(DEBUG_STDERR
, "l7");
306 if (asl_store_dst
!= NULL
&& asl_store_dst
->path
== NULL
) asl_store_dst
->path
= strdup(PATH_ASL_STORE
);
308 debug_log(ASL_LEVEL_ERR
, "aslmanager starting%s\n", dryrun
? " dryrun" : "");
310 if (work
& DO_ASLDB
) process_asl_data_store(asl_store_dst
, &opts
);
312 if (work
& DO_MODULE
)
314 if (work
& DO_CHECKPT
) checkpoint(mname
);
318 for (m
= mod
; m
!= NULL
; m
= m
->next
)
322 process_module(m
, NULL
);
324 else if ((m
->name
!= NULL
) && (!strcmp(m
->name
, mname
)))
326 process_module(m
, &opts
);
332 asl_out_module_free(mod
);
334 debug_log(ASL_LEVEL_NOTICE
, "----------------------------------------\n");
335 debug_log(ASL_LEVEL_ERR
, "aslmanager finished%s\n", dryrun
? " dryrun" : "");
341 /* dispatched on server_queue, dispatches to work_queue */
345 /* if main task is already running or queued, do nothing */
346 if (main_task_enqueued
) return;
348 main_task_enqueued
= true;
350 os_transaction_t transaction
= os_transaction_create("com.apple.aslmanager");
352 if (initial_main_task
)
354 initial_main_task
= false;
355 dispatch_time_t delay
= dispatch_walltime(NULL
, MAIN_TASK_INITIAL_DELAY
* NSEC_PER_SEC
);
357 dispatch_after(delay
, work_queue
, ^{
359 main_task_enqueued
= false;
360 os_release(transaction
);
365 dispatch_async(work_queue
, ^{
367 main_task_enqueued
= false;
368 os_release(transaction
);
374 accept_connection(xpc_connection_t peer
)
376 xpc_connection_set_event_handler(peer
, ^(xpc_object_t request
) {
377 if (xpc_get_type(request
) == XPC_TYPE_DICTIONARY
)
379 uid_t uid
= xpc_connection_get_euid(peer
);
381 /* send a reply immediately */
382 xpc_object_t reply
= xpc_dictionary_create_reply(request
);
385 xpc_connection_send_message(peer
, reply
);
390 * Some day, we may use the dictionary to pass parameters
391 * to aslmanager, but for now, we ignore the input.
394 if (uid
== geteuid())
399 else if (xpc_get_type(request
) == XPC_TYPE_ERROR
)
405 xpc_connection_resume(peer
);
409 main(int argc
, char *argv
[])
411 int64_t is_managed
= 0;
413 vproc_swap_integer(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &is_managed
);
415 if (is_managed
== 0) return cli_main(argc
, argv
);
418 setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_THROTTLE
);
421 server_queue
= dispatch_queue_create("aslmanager", NULL
);
423 work_queue
= dispatch_queue_create("work queue", NULL
);
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");
433 dispatch_resume(sig_term_src
);
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
);
440 xpc_connection_resume(listener
);