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
;
144 bool cache_delete
= false;
145 bool cache_delete_query
= false;
147 #if !TARGET_OS_SIMULATOR
150 if (argc
== 0) debug
= DEBUG_ASL
;
151 else debug
= DEBUG_STDERR
;
153 debug_log(ASL_LEVEL_ERR
, "aslmanager must be run by root\n");
158 module_ttl
= DEFAULT_TTL
;
160 /* cobble up a dst_data with defaults and parameter settings */
161 memset(&store
, 0, sizeof(store
));
162 store
.ttl
[LEVEL_ALL
] = DEFAULT_TTL
;
163 store
.all_max
= DEFAULT_MAX_SIZE
;
165 memset(&opts
, 0, sizeof(opts
));
166 opts
.ttl
[LEVEL_ALL
] = DEFAULT_TTL
;
167 opts
.all_max
= DEFAULT_MAX_SIZE
;
169 for (i
= 1; i
< argc
; i
++)
171 if (!strcmp(argv
[i
], "-q"))
175 else if (!strcmp(argv
[i
], "-dd"))
179 else if (!strcmp(argv
[i
], "-s"))
181 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
183 store
.path
= strdup(argv
[++i
]);
184 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
;
209 /* get parameters from asl.conf */
210 mod
= asl_out_module_init();
214 for (r
= mod
->ruleset
; (r
!= NULL
) && (asl_store_dst
== NULL
); r
= r
->next
)
216 if ((r
->dst
!= NULL
) && (r
->action
== ACTION_OUT_DEST
) && (!strcmp(r
->dst
->path
, PATH_ASL_STORE
)))
217 asl_store_dst
= r
->dst
;
220 for (r
= mod
->ruleset
; r
!= NULL
; r
= r
->next
)
222 if (r
->action
== ACTION_SET_PARAM
)
224 if (r
->query
== NULL
) _aslmanager_set_param(asl_store_dst
, r
->options
);
229 work
= DO_ASLDB
| DO_MODULE
;
231 for (i
= 1; i
< argc
; i
++)
233 if (!strcmp(argv
[i
], "-a"))
235 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
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;
241 else if (!strcmp(argv
[i
], "-store_ttl"))
243 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
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
);
249 else if (!strcmp(argv
[i
], "-module_ttl"))
251 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-')) module_ttl
= asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
253 else if (!strcmp(argv
[i
], "-ttl"))
255 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
257 opts
.ttl
[LEVEL_ALL
] = asl_core_str_to_time(argv
[++i
], SECONDS_PER_DAY
);
259 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
260 asl_store_dst
->ttl
[LEVEL_ALL
] = opts
.ttl
[LEVEL_ALL
];
262 module_ttl
= opts
.ttl
[LEVEL_ALL
];
265 else if (!strcmp(argv
[i
], "-size"))
267 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] != '-'))
269 opts
.all_max
= asl_core_str_to_size(argv
[++i
]);
271 if (asl_store_dst
== NULL
) asl_store_dst
= &store
;
272 asl_store_dst
->all_max
= opts
.all_max
;
275 else if (!strcmp(argv
[i
], "-checkpoint"))
279 else if (!strcmp(argv
[i
], "-cache_delete"))
282 if (((i
+ 1) < argc
) && (argv
[i
+ 1][0] == 'q')) cache_delete_query
= true;
284 else if (!strcmp(argv
[i
], "-module"))
288 /* optional name follows -module */
291 if (argv
[i
+ 1][0] != '-') mname
= argv
[++i
];
294 else if (!strcmp(argv
[i
], "-asldb"))
298 else if (!strcmp(argv
[i
], "-d"))
300 if (((i
+ i
) < argc
) && (argv
[i
+1][0] != '-')) set_debug(DEBUG_STDERR
, argv
[++i
]);
301 else set_debug(DEBUG_STDERR
, NULL
);
303 else if (!strcmp(argv
[i
], "-dd"))
307 if (((i
+ i
) < argc
) && (argv
[i
+1][0] != '-')) set_debug(DEBUG_STDERR
, argv
[++i
]);
308 else set_debug(DEBUG_STDERR
, "l7");
312 if (asl_store_dst
->path
== NULL
) asl_store_dst
->path
= strdup(PATH_ASL_STORE
);
314 debug_log(ASL_LEVEL_ERR
, "aslmanager starting%s\n", dryrun
? " dryrun" : "");
318 size_t curr_size
= 0;
320 if (cache_delete_task(true, &curr_size
) != 0)
322 debug_log(ASL_LEVEL_NOTICE
, "cache_delete_process failed - can't determine current size\n");
326 debug_log(ASL_LEVEL_NOTICE
, "cache delete current size = %lu\n", curr_size
);
328 if (!cache_delete_query
)
330 size_t new_size
= curr_size
- opts
.all_max
;
332 if (cache_delete_task(false, &new_size
) != 0)
334 debug_log(ASL_LEVEL_NOTICE
, "cache_delete_process failed - delete failed\n");
338 debug_log(ASL_LEVEL_NOTICE
, "cache delete new size = %lu\n", new_size
);
343 asl_out_module_free(mod
);
345 debug_log(ASL_LEVEL_NOTICE
, "----------------------------------------\n");
346 debug_log(ASL_LEVEL_ERR
, "aslmanager finished%s\n", dryrun
? " dryrun" : "");
352 if (work
& DO_ASLDB
) process_asl_data_store(asl_store_dst
, &opts
);
354 if (work
& DO_MODULE
)
356 if (work
& DO_CHECKPT
) checkpoint(mname
);
360 for (m
= mod
; m
!= NULL
; m
= m
->next
)
364 process_module(m
, NULL
);
366 else if ((m
->name
!= NULL
) && (!strcmp(m
->name
, mname
)))
368 process_module(m
, &opts
);
374 asl_out_module_free(mod
);
376 debug_log(ASL_LEVEL_NOTICE
, "----------------------------------------\n");
377 debug_log(ASL_LEVEL_ERR
, "aslmanager finished%s\n", dryrun
? " dryrun" : "");
383 /* dispatched on server_queue, dispatches to work_queue */
387 /* if main task is already running or queued, do nothing */
388 if (main_task_enqueued
) return;
390 main_task_enqueued
= true;
391 xpc_transaction_begin();
393 if (initial_main_task
)
395 initial_main_task
= false;
396 dispatch_time_t delay
= dispatch_walltime(NULL
, MAIN_TASK_INITIAL_DELAY
* NSEC_PER_SEC
);
398 dispatch_after(delay
, work_queue
, ^{
400 main_task_enqueued
= false;
401 xpc_transaction_end();
406 dispatch_async(work_queue
, ^{
408 main_task_enqueued
= false;
409 xpc_transaction_end();
415 accept_connection(xpc_connection_t peer
)
417 xpc_connection_set_event_handler(peer
, ^(xpc_object_t request
) {
418 if (xpc_get_type(request
) == XPC_TYPE_DICTIONARY
)
420 uid_t uid
= xpc_connection_get_euid(peer
);
422 /* send a reply immediately */
423 xpc_object_t reply
= xpc_dictionary_create_reply(request
);
424 xpc_connection_send_message(peer
, reply
);
428 * Some day, we may use the dictionary to pass parameters
429 * to aslmanager, but for now, we ignore the input.
432 if (uid
== geteuid())
437 else if (xpc_get_type(request
) == XPC_TYPE_ERROR
)
443 xpc_connection_resume(peer
);
447 main(int argc
, char *argv
[])
449 int64_t is_managed
= 0;
451 vproc_swap_integer(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &is_managed
);
453 if (is_managed
== 0) return cli_main(argc
, argv
);
456 setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_THROTTLE
);
459 server_queue
= dispatch_queue_create("aslmanager", NULL
);
461 work_queue
= dispatch_queue_create("work queue", NULL
);
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");
471 dispatch_resume(sig_term_src
);
473 /* Handle incoming messages. */
474 listener
= xpc_connection_create_mach_service("com.apple.aslmanager", server_queue
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
475 xpc_connection_set_event_handler(listener
, ^(xpc_object_t peer
) {
476 if (xpc_get_type(peer
) == XPC_TYPE_CONNECTION
) accept_connection(peer
);
478 xpc_connection_resume(listener
);
480 cache_delete_register();