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>
31 #include "asl_common.h"
33 #include "cache_delete.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
;
143 bool cache_delete
= false;
144 bool cache_delete_query
= false;
146 #if !TARGET_OS_SIMULATOR
149 if (argc
== 0) debug
= DEBUG_ASL
;
150 else debug
= DEBUG_STDERR
;
152 debug_log(ASL_LEVEL_ERR
, "aslmanager must be run by root\n");
157 module_ttl
= DEFAULT_TTL
;
159 /* cobble up a dst_data with defaults and parameter settings */
160 memset(&store
, 0, sizeof(store
));
161 store
.ttl
[LEVEL_ALL
] = DEFAULT_TTL
;
162 store
.all_max
= DEFAULT_MAX_SIZE
;
164 memset(&opts
, 0, sizeof(opts
));
165 opts
.ttl
[LEVEL_ALL
] = DEFAULT_TTL
;
166 opts
.all_max
= DEFAULT_MAX_SIZE
;
168 for (i
= 1; i
< argc
; i
++)
170 if (!strcmp(argv
[i
], "-q"))
174 else if (!strcmp(argv
[i
], "-dd"))
178 else if (!strcmp(argv
[i
], "-s"))
180 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
182 store
.path
= strdup(argv
[++i
]);
183 asl_store_dst
= &store
;
191 int status
= asl_make_database_dir(NULL
, NULL
);
192 if (status
== 0) status
= asl_make_database_dir(ASL_INTERNAL_LOGS_DIR
, &path
);
195 char tstamp
[32], *str
= NULL
;
197 asl_make_timestamp(time(NULL
), MODULE_NAME_STYLE_STAMP_LCL_B
, tstamp
, sizeof(tstamp
));
198 asprintf(&str
, "%s/aslmanager.%s", path
, tstamp
);
202 if (status
== 0) debugfp
= fopen(str
, "w");
203 if (debugfp
!= NULL
) debug
|= DEBUG_FILE
;
210 /* get parameters from asl.conf */
211 mod
= asl_out_module_init();
215 for (r
= mod
->ruleset
; (r
!= NULL
) && (asl_store_dst
== NULL
); r
= r
->next
)
217 if ((r
->dst
!= NULL
) && (r
->action
== ACTION_OUT_DEST
) && (!strcmp(r
->dst
->path
, PATH_ASL_STORE
)))
218 asl_store_dst
= r
->dst
;
221 for (r
= mod
->ruleset
; r
!= NULL
; r
= r
->next
)
223 if (r
->action
== ACTION_SET_PARAM
)
225 if (r
->query
== NULL
) _aslmanager_set_param(asl_store_dst
, r
->options
);
230 work
= DO_ASLDB
| DO_MODULE
;
232 for (i
= 1; i
< argc
; i
++)
234 if (!strcmp(argv
[i
], "-a"))
236 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
238 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-')) asl_store_dst
->rotate_dir
= strdup(argv
[++i
]);
239 else asl_store_dst
->rotate_dir
= strdup(PATH_ASL_ARCHIVE
);
240 asl_store_dst
->mode
= 0400;
242 else if (!strcmp(argv
[i
], "-store_ttl"))
244 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
246 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
247 asl_store_dst
->ttl
[LEVEL_ALL
] = asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
250 else if (!strcmp(argv
[i
], "-module_ttl"))
252 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-')) module_ttl
= asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
254 else if (!strcmp(argv
[i
], "-ttl"))
256 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
258 opts
.ttl
[LEVEL_ALL
] = asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
260 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
261 asl_store_dst
->ttl
[LEVEL_ALL
] = opts
.ttl
[LEVEL_ALL
];
263 module_ttl
= opts
.ttl
[LEVEL_ALL
];
266 else if (!strcmp(argv
[i
], "-size"))
268 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
270 opts
.all_max
= asl_core_str_to_size(argv
[++i
]);
272 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
273 asl_store_dst
->all_max
= opts
.all_max
;
276 else if (!strcmp(argv
[i
], "-checkpoint"))
280 else if (!strcmp(argv
[i
], "-cache_delete"))
283 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] == 'q')) cache_delete_query
= true;
285 else if (!strcmp(argv
[i
], "-module"))
289 /* optional name follows -module */
292 if (argv
[i
+ 1][0] != '-') mname
= argv
[++i
];
295 else if (!strcmp(argv
[i
], "-asldb"))
299 else if (!strcmp(argv
[i
], "-d"))
301 if (((i
+ i
) < argc
) && (argv
[i
+1][0] != '-')) set_debug(DEBUG_STDERR
, argv
[++i
]);
302 else set_debug(DEBUG_STDERR
, NULL
);
304 else if (!strcmp(argv
[i
], "-dd"))
308 if (((i
+ i
) < argc
) && (argv
[i
+1][0] != '-')) set_debug(DEBUG_STDERR
, argv
[++i
]);
309 else set_debug(DEBUG_STDERR
, "l7");
313 if (asl_store_dst
!= NULL
&& asl_store_dst
->path
== NULL
) asl_store_dst
->path
= strdup(PATH_ASL_STORE
);
315 debug_log(ASL_LEVEL_ERR
, "aslmanager starting%s\n", dryrun
? " dryrun" : "");
319 size_t curr_size
= 0;
321 if (cache_delete_task(true, &curr_size
) != 0)
323 debug_log(ASL_LEVEL_NOTICE
, "cache_delete_process failed - can't determine current size\n");
327 debug_log(ASL_LEVEL_NOTICE
, "cache delete current size = %lu\n", curr_size
);
329 if (!cache_delete_query
)
331 size_t new_size
= curr_size
- opts
.all_max
;
333 if (cache_delete_task(false, &new_size
) != 0)
335 debug_log(ASL_LEVEL_NOTICE
, "cache_delete_process failed - delete failed\n");
339 debug_log(ASL_LEVEL_NOTICE
, "cache delete new size = %lu\n", new_size
);
344 asl_out_module_free(mod
);
346 debug_log(ASL_LEVEL_NOTICE
, "----------------------------------------\n");
347 debug_log(ASL_LEVEL_ERR
, "aslmanager finished%s\n", dryrun
? " dryrun" : "");
353 if (work
& DO_ASLDB
) process_asl_data_store(asl_store_dst
, &opts
);
355 if (work
& DO_MODULE
)
357 if (work
& DO_CHECKPT
) checkpoint(mname
);
361 for (m
= mod
; m
!= NULL
; m
= m
->next
)
365 process_module(m
, NULL
);
367 else if ((m
->name
!= NULL
) && (!strcmp(m
->name
, mname
)))
369 process_module(m
, &opts
);
375 asl_out_module_free(mod
);
377 debug_log(ASL_LEVEL_NOTICE
, "----------------------------------------\n");
378 debug_log(ASL_LEVEL_ERR
, "aslmanager finished%s\n", dryrun
? " dryrun" : "");
384 /* dispatched on server_queue, dispatches to work_queue */
388 /* if main task is already running or queued, do nothing */
389 if (main_task_enqueued
) return;
391 main_task_enqueued
= true;
392 xpc_transaction_begin();
394 if (initial_main_task
)
396 initial_main_task
= false;
397 dispatch_time_t delay
= dispatch_walltime(NULL
, MAIN_TASK_INITIAL_DELAY
* NSEC_PER_SEC
);
399 dispatch_after(delay
, work_queue
, ^{
401 main_task_enqueued
= false;
402 xpc_transaction_end();
407 dispatch_async(work_queue
, ^{
409 main_task_enqueued
= false;
410 xpc_transaction_end();
416 accept_connection(xpc_connection_t peer
)
418 xpc_connection_set_event_handler(peer
, ^(xpc_object_t request
) {
419 if (xpc_get_type(request
) == XPC_TYPE_DICTIONARY
)
421 uid_t uid
= xpc_connection_get_euid(peer
);
423 /* send a reply immediately */
424 xpc_object_t reply
= xpc_dictionary_create_reply(request
);
425 xpc_connection_send_message(peer
, reply
);
429 * Some day, we may use the dictionary to pass parameters
430 * to aslmanager, but for now, we ignore the input.
433 if (uid
== geteuid())
438 else if (xpc_get_type(request
) == XPC_TYPE_ERROR
)
444 xpc_connection_resume(peer
);
448 main(int argc
, char *argv
[])
450 int64_t is_managed
= 0;
452 vproc_swap_integer(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &is_managed
);
454 if (is_managed
== 0) return cli_main(argc
, argv
);
457 setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_THROTTLE
);
460 server_queue
= dispatch_queue_create("aslmanager", NULL
);
462 work_queue
= dispatch_queue_create("work queue", NULL
);
464 /* Exit on SIGTERM */
465 signal(SIGTERM
, SIG_IGN
);
466 sig_term_src
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, (uintptr_t)SIGTERM
, 0, dispatch_get_main_queue());
467 dispatch_source_set_event_handler(sig_term_src
, ^{
468 debug_log(ASL_LEVEL_NOTICE
, "SIGTERM exit\n");
472 dispatch_resume(sig_term_src
);
474 /* Handle incoming messages. */
475 listener
= xpc_connection_create_mach_service("com.apple.aslmanager", server_queue
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
476 xpc_connection_set_event_handler(listener
, ^(xpc_object_t peer
) {
477 if (xpc_get_type(peer
) == XPC_TYPE_CONNECTION
) accept_connection(peer
);
479 xpc_connection_resume(listener
);
481 cache_delete_register();