]>
Commit | Line | Data |
---|---|---|
57b0aad2 | 1 | /* |
c4fdb7d1 | 2 | * Copyright (c) 2007-2009 Apple Inc. All rights reserved. |
57b0aad2 A |
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 <stdio.h> | |
25 | #include <dirent.h> | |
26 | #include <string.h> | |
27 | #include <stdlib.h> | |
28 | #include <unistd.h> | |
29 | #include <stdint.h> | |
30 | #include <errno.h> | |
31 | #include <time.h> | |
32 | #include <sys/time.h> | |
33 | #include <sys/stat.h> | |
81582353 A |
34 | #include <sys/param.h> |
35 | #include <servers/bootstrap.h> | |
36 | #include <bootstrap_priv.h> | |
37 | #include <mach/mach.h> | |
a83ff38a | 38 | #include <copyfile.h> |
81582353 A |
39 | #include <fcntl.h> |
40 | #include <zlib.h> | |
41 | #include <xpc/xpc.h> | |
42 | #include <xpc/private.h> | |
43 | #include <os/assumes.h> | |
44 | #include <vproc_priv.h> | |
57b0aad2 A |
45 | #include <asl.h> |
46 | #include <asl_private.h> | |
47 | #include <asl_core.h> | |
48 | #include <asl_file.h> | |
49 | #include <asl_store.h> | |
81582353 | 50 | #include "asl_common.h" |
57b0aad2 | 51 | |
c4fdb7d1 | 52 | #define DEFAULT_MAX_SIZE 150000000 |
81582353 A |
53 | #define IOBUFSIZE 4096 |
54 | ||
55 | #define DO_ASLDB 0x00000001 | |
56 | #define DO_MODULE 0x00000002 | |
57 | #define DO_CHECKPT 0x00000004 | |
58 | ||
59 | #define DEBUG_FLAG_MASK 0xfffffff0 | |
60 | #define DEBUG_LEVEL_MASK 0x0000000f | |
61 | #define DEBUG_STDERR 0x00000010 | |
62 | #define DEBUG_ASL 0x00000020 | |
63 | ||
64 | extern kern_return_t _asl_server_query | |
65 | ( | |
66 | mach_port_t server, | |
67 | caddr_t request, | |
68 | mach_msg_type_number_t requestCnt, | |
69 | uint64_t startid, | |
70 | int count, | |
71 | int flags, | |
72 | caddr_t *reply, | |
73 | mach_msg_type_number_t *replyCnt, | |
74 | uint64_t *lastid, | |
75 | int *status, | |
76 | security_token_t *token | |
77 | ); | |
c4fdb7d1 A |
78 | |
79 | /* global */ | |
81582353 A |
80 | static time_t module_ttl; |
81 | static uint32_t debug; | |
82 | static int dryrun; | |
83 | static int asl_aux_fd = -1; | |
84 | static aslclient aslc; | |
85 | static mach_port_t asl_server_port; | |
86 | static xpc_connection_t listener; | |
87 | static dispatch_queue_t serverq; | |
94194072 | 88 | |
57b0aad2 A |
89 | typedef struct name_list_s |
90 | { | |
91 | char *name; | |
92 | size_t size; | |
93 | struct name_list_s *next; | |
94 | } name_list_t; | |
95 | ||
81582353 A |
96 | void |
97 | set_debug(int flag, const char *str) | |
98 | { | |
99 | int level, x; | |
100 | ||
101 | if (str == NULL) x = ASL_LEVEL_ERR; | |
102 | else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1); | |
103 | else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str); | |
104 | else x = ASL_LEVEL_ERR; | |
105 | ||
106 | if (x <= 0) x = 0; | |
107 | else if (x > 7) x = 7; | |
108 | ||
109 | level = debug & DEBUG_LEVEL_MASK; | |
110 | if (x > level) level = x; | |
111 | ||
112 | debug = debug & DEBUG_FLAG_MASK; | |
113 | debug |= flag; | |
114 | debug |= level; | |
115 | } | |
116 | ||
117 | void | |
118 | debug_log(int level, const char *str, ...) | |
119 | { | |
120 | va_list v; | |
121 | ||
122 | if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK))) | |
123 | { | |
124 | va_start(v, str); | |
125 | vfprintf(stderr, str, v); | |
126 | va_end(v); | |
127 | } | |
128 | ||
129 | if (debug & DEBUG_ASL) | |
130 | { | |
131 | char *line = NULL; | |
132 | ||
133 | if (aslc == NULL) | |
134 | { | |
135 | aslc = asl_open("aslmanager", "syslog", 0); | |
136 | aslmsg msg = asl_new(ASL_TYPE_MSG); | |
137 | ||
138 | asl_set(msg, ASL_KEY_MSG, "Status Report"); | |
139 | asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE); | |
140 | asl_create_auxiliary_file(msg, "Status Report", "public.text", &asl_aux_fd); | |
141 | asl_free(msg); | |
142 | } | |
143 | ||
144 | va_start(v, str); | |
145 | vasprintf(&line, str, v); | |
146 | va_end(v); | |
147 | ||
148 | if (line != NULL) write(asl_aux_fd, line, strlen(line)); | |
149 | free(line); | |
150 | } | |
151 | } | |
152 | ||
153 | __attribute__((noreturn)) static void | |
154 | xpc_server_exit(int status) | |
155 | { | |
156 | xpc_connection_cancel(listener); | |
157 | xpc_release(listener); | |
158 | dispatch_release(serverq); | |
159 | exit(status); | |
160 | } | |
161 | ||
57b0aad2 | 162 | name_list_t * |
81582353 | 163 | add_to_name_list(name_list_t *l, const char *name, size_t size) |
57b0aad2 A |
164 | { |
165 | name_list_t *e, *x; | |
166 | ||
167 | if (name == NULL) return l; | |
168 | ||
169 | e = (name_list_t *)calloc(1, sizeof(name_list_t)); | |
170 | if (e == NULL) return NULL; | |
171 | ||
172 | e->name = strdup(name); | |
173 | if (e->name == NULL) | |
174 | { | |
175 | free(e); | |
176 | return NULL; | |
177 | } | |
178 | ||
179 | e->size = size; | |
180 | ||
181 | /* list is sorted by name (i.e. primarily by timestamp) */ | |
182 | if (l == NULL) return e; | |
183 | ||
184 | if (strcmp(e->name, l->name) <= 0) | |
185 | { | |
186 | e->next = l; | |
187 | return e; | |
188 | } | |
189 | ||
190 | for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next); | |
191 | ||
192 | e->next = x->next; | |
193 | x->next = e; | |
194 | return l; | |
195 | } | |
196 | ||
197 | void | |
81582353 | 198 | free_name_list(name_list_t *l) |
57b0aad2 A |
199 | { |
200 | name_list_t *e; | |
201 | ||
202 | while (l != NULL) | |
203 | { | |
204 | e = l; | |
205 | l = l->next; | |
206 | free(e->name); | |
207 | free(e); | |
208 | } | |
209 | ||
210 | free(l); | |
211 | } | |
212 | ||
81582353 A |
213 | /* |
214 | * Copy ASL files by reading and writing each record. | |
215 | * Setting ASL_FILE_FLAG_UNLIMITED_CACHE when copying optimizes tring uniquing. | |
216 | */ | |
57b0aad2 | 217 | uint32_t |
81582353 | 218 | copy_asl_file(const char *src, const char *dst, mode_t mode) |
57b0aad2 | 219 | { |
c4fdb7d1 A |
220 | asl_search_result_t *res; |
221 | asl_file_t *f; | |
57b0aad2 | 222 | uint32_t status, i; |
57b0aad2 A |
223 | uint64_t mid; |
224 | ||
81582353 A |
225 | if (src == NULL) return ASL_STATUS_INVALID_ARG; |
226 | if (dst == NULL) return ASL_STATUS_INVALID_ARG; | |
57b0aad2 | 227 | |
c4fdb7d1 | 228 | f = NULL; |
81582353 | 229 | status = asl_file_open_read(src, &f); |
57b0aad2 A |
230 | if (status != ASL_STATUS_OK) return status; |
231 | ||
c4fdb7d1 A |
232 | res = NULL; |
233 | mid = 0; | |
57b0aad2 | 234 | |
c4fdb7d1 A |
235 | status = asl_file_match(f, NULL, &res, &mid, 0, 0, 1); |
236 | asl_file_close(f); | |
237 | ||
238 | if (status != ASL_STATUS_OK) return status; | |
81582353 | 239 | if (res == NULL) return ASL_STATUS_OK; |
c4fdb7d1 A |
240 | if (res->count == 0) |
241 | { | |
242 | aslresponse_free(res); | |
243 | return ASL_STATUS_OK; | |
244 | } | |
245 | ||
246 | f = NULL; | |
81582353 | 247 | status = asl_file_open_write(dst, mode, -1, -1, &f); |
c4fdb7d1 A |
248 | if (status != ASL_STATUS_OK) return status; |
249 | if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED; | |
250 | ||
251 | f->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID; | |
252 | ||
253 | for (i = 0; i < res->count; i++) | |
57b0aad2 | 254 | { |
c4fdb7d1 | 255 | mid = 0; |
a83ff38a | 256 | status = asl_file_save(f, (aslmsg)(res->msg[i]), &mid); |
c4fdb7d1 A |
257 | if (status != ASL_STATUS_OK) break; |
258 | } | |
259 | ||
260 | asl_file_close(f); | |
261 | return status; | |
262 | } | |
263 | ||
a83ff38a | 264 | int |
81582353 | 265 | copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst) |
a83ff38a | 266 | { |
81582353 A |
267 | int in, out; |
268 | size_t n; | |
269 | gzFile gz; | |
270 | char buf[IOBUFSIZE]; | |
a83ff38a | 271 | |
81582353 A |
272 | in = open(src, O_RDONLY, 0); |
273 | if (in < 0) return -1; | |
a83ff38a | 274 | |
81582353 A |
275 | out = open(dst, O_WRONLY | O_CREAT, asldst->mode); |
276 | if (out >= 0) out = asl_out_dst_set_access(out, asldst); | |
277 | if (out < 0) | |
278 | { | |
279 | close(in); | |
280 | return -1; | |
281 | } | |
a83ff38a | 282 | |
81582353 A |
283 | gz = gzdopen(out, "w"); |
284 | if (gz == NULL) | |
a83ff38a | 285 | { |
81582353 A |
286 | close(in); |
287 | close(out); | |
288 | return -1; | |
a83ff38a A |
289 | } |
290 | ||
81582353 A |
291 | do { |
292 | n = read(in, buf, sizeof(buf)); | |
293 | if (n > 0) gzwrite(gz, buf, n); | |
294 | } while (n == IOBUFSIZE); | |
a83ff38a | 295 | |
81582353 A |
296 | gzclose(gz); |
297 | close(in); | |
298 | close(out); | |
a83ff38a | 299 | |
81582353 A |
300 | return 0; |
301 | } | |
a83ff38a | 302 | |
81582353 A |
303 | int32_t |
304 | filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags) | |
c4fdb7d1 | 305 | { |
81582353 | 306 | char *dot; |
c4fdb7d1 | 307 | |
81582353 | 308 | if ((src == NULL) || (dst == NULL)) return 0; |
c4fdb7d1 | 309 | |
81582353 A |
310 | dot = strrchr(src, '.'); |
311 | if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS; | |
57b0aad2 | 312 | |
81582353 | 313 | if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0; |
c4fdb7d1 | 314 | |
81582353 A |
315 | if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst); |
316 | else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst); | |
317 | else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst); | |
c4fdb7d1 | 318 | |
81582353 | 319 | if (dryrun == 1) return 0; |
57b0aad2 | 320 | |
81582353 | 321 | if (flags & MODULE_FLAG_TYPE_ASL) |
c4fdb7d1 | 322 | { |
81582353 A |
323 | uint32_t status = copy_asl_file(src, dst, asldst->mode); |
324 | if (status != 0) | |
57b0aad2 | 325 | { |
81582353 A |
326 | debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst); |
327 | return 0; | |
57b0aad2 | 328 | } |
c4fdb7d1 | 329 | } |
81582353 A |
330 | else if (flags & MODULE_FLAG_COMPRESS) |
331 | { | |
332 | char gzdst[MAXPATHLEN]; | |
c4fdb7d1 | 333 | |
81582353 | 334 | snprintf(gzdst, sizeof(gzdst), "%s.gz", dst); |
c4fdb7d1 | 335 | |
81582353 A |
336 | int status = copy_compress_file(asldst, src, gzdst); |
337 | if (status != 0) | |
338 | { | |
339 | debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst); | |
340 | return 0; | |
341 | } | |
342 | } | |
343 | else | |
344 | { | |
345 | int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE); | |
346 | if (status != 0) | |
347 | { | |
348 | debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst); | |
349 | return 0; | |
350 | } | |
351 | } | |
352 | ||
353 | return 1; | |
c4fdb7d1 A |
354 | } |
355 | ||
81582353 A |
356 | void |
357 | filesystem_rename(const char *src, const char *dst) | |
c4fdb7d1 | 358 | { |
81582353 | 359 | int status = 0; |
c4fdb7d1 | 360 | |
81582353 A |
361 | debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst); |
362 | if (dryrun == 1) return; | |
c4fdb7d1 | 363 | |
81582353 A |
364 | status = rename(src, dst); |
365 | if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst); | |
366 | } | |
c4fdb7d1 | 367 | |
81582353 A |
368 | void |
369 | filesystem_unlink(const char *path) | |
370 | { | |
371 | int status = 0; | |
c4fdb7d1 | 372 | |
81582353 A |
373 | debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path); |
374 | if (dryrun == 1) return; | |
57b0aad2 | 375 | |
81582353 A |
376 | status = unlink(path); |
377 | if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); | |
c4fdb7d1 | 378 | } |
57b0aad2 | 379 | |
c4fdb7d1 | 380 | void |
81582353 | 381 | filesystem_rmdir(const char *path) |
c4fdb7d1 | 382 | { |
81582353 | 383 | int status = 0; |
57b0aad2 | 384 | |
81582353 A |
385 | debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path); |
386 | if (dryrun == 1) return; | |
387 | ||
388 | status = rmdir(path); | |
389 | if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path); | |
390 | } | |
391 | ||
392 | int | |
393 | remove_directory(const char *path) | |
394 | { | |
395 | DIR *dp; | |
396 | struct dirent *dent; | |
397 | char *str; | |
398 | ||
399 | dp = opendir(path); | |
400 | if (dp == NULL) return 0; | |
401 | ||
402 | while ((dent = readdir(dp)) != NULL) | |
403 | { | |
404 | if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; | |
405 | asprintf(&str, "%s/%s", path, dent->d_name); | |
406 | if (str != NULL) | |
407 | { | |
408 | filesystem_unlink(str); | |
409 | free(str); | |
410 | str = NULL; | |
411 | } | |
412 | } | |
413 | ||
414 | closedir(dp); | |
415 | filesystem_rmdir(path); | |
416 | ||
417 | return 0; | |
c4fdb7d1 A |
418 | } |
419 | ||
420 | /* | |
81582353 | 421 | * Used to set config parameters. |
c4fdb7d1 A |
422 | * Line format "= name value" |
423 | */ | |
424 | static void | |
81582353 | 425 | _aslmanager_set_param(asl_out_dst_data_t *dst, char *s) |
c4fdb7d1 A |
426 | { |
427 | char **l; | |
428 | uint32_t count; | |
429 | ||
430 | if (s == NULL) return; | |
431 | if (s[0] == '\0') return; | |
432 | ||
433 | /* skip '=' and whitespace */ | |
81582353 | 434 | if (*s == '=') s++; |
c4fdb7d1 A |
435 | while ((*s == ' ') || (*s == '\t')) s++; |
436 | ||
437 | l = explode(s, " \t"); | |
438 | if (l == NULL) return; | |
439 | ||
440 | for (count = 0; l[count] != NULL; count++); | |
441 | ||
442 | /* name is required */ | |
443 | if (count == 0) | |
57b0aad2 | 444 | { |
81582353 | 445 | free_string_list(l); |
c4fdb7d1 | 446 | return; |
57b0aad2 A |
447 | } |
448 | ||
c4fdb7d1 A |
449 | /* value is required */ |
450 | if (count == 1) | |
451 | { | |
81582353 | 452 | free_string_list(l); |
c4fdb7d1 A |
453 | return; |
454 | } | |
57b0aad2 | 455 | |
c4fdb7d1 A |
456 | if (!strcasecmp(l[0], "aslmanager_debug")) |
457 | { | |
81582353 A |
458 | /* = debug level */ |
459 | set_debug(DEBUG_ASL, l[1]); | |
c4fdb7d1 A |
460 | } |
461 | else if (!strcasecmp(l[0], "store_ttl")) | |
462 | { | |
463 | /* = store_ttl days */ | |
81582353 A |
464 | dst->ttl = (time_t)atoll(l[1]); |
465 | } | |
466 | else if (!strcasecmp(l[0], "module_ttl")) | |
467 | { | |
468 | /* = module_ttl days */ | |
469 | module_ttl = (time_t)atoll(l[1]); | |
c4fdb7d1 A |
470 | } |
471 | else if (!strcasecmp(l[0], "max_store_size")) | |
472 | { | |
473 | /* = max_file_size bytes */ | |
81582353 | 474 | dst->all_max = atoi(l[1]); |
c4fdb7d1 A |
475 | } |
476 | else if (!strcasecmp(l[0], "archive")) | |
477 | { | |
81582353 A |
478 | free(dst->rotate_dir); |
479 | dst->rotate_dir = NULL; | |
480 | ||
c4fdb7d1 A |
481 | /* = archive {0|1} path */ |
482 | if (!strcmp(l[1], "1")) | |
483 | { | |
81582353 A |
484 | if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); |
485 | else dst->rotate_dir = strdup(l[2]); | |
c4fdb7d1 | 486 | } |
c4fdb7d1 A |
487 | } |
488 | else if (!strcasecmp(l[0], "store_path")) | |
489 | { | |
490 | /* = archive path */ | |
81582353 A |
491 | free(dst->path); |
492 | dst->path = strdup(l[1]); | |
c4fdb7d1 A |
493 | } |
494 | else if (!strcasecmp(l[0], "archive_mode")) | |
495 | { | |
81582353 A |
496 | dst->mode = strtol(l[1], NULL, 0); |
497 | if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400; | |
c4fdb7d1 | 498 | } |
57b0aad2 | 499 | |
81582353 | 500 | free_string_list(l); |
57b0aad2 A |
501 | } |
502 | ||
a83ff38a A |
503 | size_t |
504 | directory_size(const char *path) | |
505 | { | |
506 | DIR *dp; | |
507 | struct dirent *dent; | |
508 | struct stat sb; | |
509 | size_t size; | |
510 | char *str; | |
511 | ||
512 | dp = opendir(path); | |
513 | if (dp == NULL) return 0; | |
514 | ||
515 | size = 0; | |
516 | while ((dent = readdir(dp)) != NULL) | |
517 | { | |
518 | if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; | |
519 | ||
520 | memset(&sb, 0, sizeof(struct stat)); | |
521 | str = NULL; | |
522 | asprintf(&str, "%s/%s", path, dent->d_name); | |
523 | ||
524 | if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode)) | |
525 | { | |
526 | size += sb.st_size; | |
527 | free(str); | |
528 | } | |
529 | } | |
530 | ||
531 | closedir(dp); | |
532 | return size; | |
533 | } | |
534 | ||
81582353 A |
535 | static int |
536 | process_asl_data_store(asl_out_dst_data_t *dst) | |
57b0aad2 | 537 | { |
81582353 A |
538 | int32_t today_ymd_stringlen, expire_ymd_stringlen; |
539 | time_t now, ttl, ymd_expire; | |
57b0aad2 | 540 | struct tm ctm; |
c4fdb7d1 | 541 | char today_ymd_string[32], expire_ymd_string[32], *str; |
57b0aad2 A |
542 | DIR *dp; |
543 | struct dirent *dent; | |
a83ff38a | 544 | name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e; |
c4fdb7d1 | 545 | size_t file_size, store_size; |
57b0aad2 A |
546 | struct stat sb; |
547 | ||
c4fdb7d1 A |
548 | ymd_list = NULL; |
549 | bb_list = NULL; | |
a83ff38a A |
550 | aux_list = NULL; |
551 | bb_aux_list = NULL; | |
57b0aad2 | 552 | store_size = 0; |
57b0aad2 | 553 | |
81582353 A |
554 | if (dst == NULL) return 0; |
555 | if (dst->path == NULL) return 0; | |
c4fdb7d1 | 556 | |
81582353 A |
557 | debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); |
558 | debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path); | |
c4fdb7d1 | 559 | |
81582353 | 560 | if (dst->rotate_dir != NULL) |
57b0aad2 | 561 | { |
81582353 | 562 | /* check archive */ |
57b0aad2 | 563 | memset(&sb, 0, sizeof(struct stat)); |
81582353 | 564 | if (stat(dst->rotate_dir, &sb) == 0) |
57b0aad2 A |
565 | { |
566 | /* must be a directory */ | |
a83ff38a | 567 | if (!S_ISDIR(sb.st_mode)) |
57b0aad2 | 568 | { |
81582353 | 569 | debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir); |
57b0aad2 A |
570 | return -1; |
571 | } | |
572 | } | |
573 | else | |
574 | { | |
575 | if (errno == ENOENT) | |
576 | { | |
577 | /* archive doesn't exist - create it */ | |
81582353 | 578 | if (mkdir(dst->rotate_dir, 0755) != 0) |
57b0aad2 | 579 | { |
81582353 | 580 | debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno)); |
57b0aad2 | 581 | return -1; |
c4fdb7d1 | 582 | } |
57b0aad2 A |
583 | } |
584 | else | |
585 | { | |
586 | /* stat failed for some other reason */ | |
81582353 | 587 | debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno)); |
57b0aad2 A |
588 | return -1; |
589 | } | |
590 | } | |
591 | } | |
592 | ||
81582353 | 593 | chdir(dst->path); |
57b0aad2 | 594 | |
c4fdb7d1 | 595 | /* determine current time */ |
57b0aad2 | 596 | now = time(NULL); |
57b0aad2 | 597 | |
c4fdb7d1 A |
598 | /* ttl 0 means files never expire */ |
599 | ymd_expire = 0; | |
81582353 A |
600 | ttl = dst->ttl * SECONDS_PER_DAY; |
601 | ||
602 | if ((ttl > 0) && (ttl <= now)) ymd_expire = now - ttl; | |
c4fdb7d1 A |
603 | |
604 | /* construct today's date as YYYY.MM.DD */ | |
57b0aad2 | 605 | memset(&ctm, 0, sizeof(struct tm)); |
c4fdb7d1 | 606 | if (localtime_r((const time_t *)&now, &ctm) == NULL) return -1; |
57b0aad2 | 607 | |
c4fdb7d1 A |
608 | snprintf(today_ymd_string, sizeof(today_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); |
609 | today_ymd_stringlen = strlen(today_ymd_string); | |
57b0aad2 | 610 | |
c4fdb7d1 A |
611 | /* construct regular file expiry date as YYYY.MM.DD */ |
612 | memset(&ctm, 0, sizeof(struct tm)); | |
613 | if (localtime_r((const time_t *)&ymd_expire, &ctm) == NULL) return -1; | |
57b0aad2 | 614 | |
c4fdb7d1 A |
615 | snprintf(expire_ymd_string, sizeof(expire_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); |
616 | expire_ymd_stringlen = strlen(expire_ymd_string); | |
57b0aad2 | 617 | |
81582353 | 618 | debug_log(ASL_LEVEL_NOTICE, "Expiry Date %s\n", expire_ymd_string); |
57b0aad2 | 619 | |
81582353 | 620 | dp = opendir(dst->path); |
c4fdb7d1 A |
621 | if (dp == NULL) return -1; |
622 | ||
a83ff38a | 623 | /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */ |
57b0aad2 A |
624 | while ((dent = readdir(dp)) != NULL) |
625 | { | |
57b0aad2 A |
626 | memset(&sb, 0, sizeof(struct stat)); |
627 | file_size = 0; | |
628 | if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size; | |
57b0aad2 | 629 | |
c4fdb7d1 A |
630 | if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9')) |
631 | { | |
81582353 | 632 | ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size); |
c4fdb7d1 A |
633 | store_size += file_size; |
634 | } | |
a83ff38a A |
635 | else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode)) |
636 | { | |
637 | file_size = directory_size(dent->d_name); | |
81582353 | 638 | aux_list = add_to_name_list(aux_list, dent->d_name, file_size); |
a83ff38a A |
639 | store_size += file_size; |
640 | } | |
641 | else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode)) | |
642 | { | |
643 | file_size = directory_size(dent->d_name); | |
81582353 | 644 | bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size); |
a83ff38a A |
645 | store_size += file_size; |
646 | } | |
c4fdb7d1 A |
647 | else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9')) |
648 | { | |
81582353 | 649 | bb_list = add_to_name_list(bb_list, dent->d_name, file_size); |
c4fdb7d1 A |
650 | store_size += file_size; |
651 | } | |
652 | else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) | |
653 | {} | |
654 | else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore"))) | |
655 | {} | |
656 | else | |
657 | { | |
81582353 | 658 | debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name); |
c4fdb7d1 | 659 | } |
57b0aad2 A |
660 | } |
661 | ||
662 | closedir(dp); | |
663 | ||
81582353 A |
664 | debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); |
665 | debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files\n"); | |
666 | for (e = ymd_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); | |
667 | debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n"); | |
668 | for (e = aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); | |
669 | debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n"); | |
670 | for (e = bb_aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); | |
671 | debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n"); | |
672 | for (e = bb_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); | |
57b0aad2 | 673 | |
c4fdb7d1 | 674 | /* Delete/achive expired YMD files */ |
81582353 | 675 | debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n"); |
57b0aad2 | 676 | |
c4fdb7d1 | 677 | e = ymd_list; |
57b0aad2 A |
678 | while (e != NULL) |
679 | { | |
c4fdb7d1 A |
680 | /* stop when a file name/date is after the expire date */ |
681 | if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) > 0) break; | |
57b0aad2 | 682 | |
81582353 | 683 | if (dst->rotate_dir != NULL) |
c4fdb7d1 A |
684 | { |
685 | str = NULL; | |
81582353 | 686 | asprintf(&str, "%s/%s", dst->rotate_dir, e->name); |
c4fdb7d1 | 687 | if (str == NULL) return -1; |
57b0aad2 | 688 | |
81582353 | 689 | filesystem_copy(dst, e->name, str, 0); |
c4fdb7d1 A |
690 | free(str); |
691 | } | |
692 | ||
81582353 | 693 | filesystem_unlink(e->name); |
c4fdb7d1 A |
694 | store_size -= e->size; |
695 | e->size = 0; | |
57b0aad2 | 696 | |
c4fdb7d1 A |
697 | e = e->next; |
698 | } | |
57b0aad2 | 699 | |
81582353 | 700 | debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n"); |
a83ff38a A |
701 | |
702 | /* Delete/achive expired YMD AUX directories */ | |
81582353 | 703 | debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n"); |
a83ff38a A |
704 | |
705 | e = aux_list; | |
706 | while (e != NULL) | |
707 | { | |
708 | /* stop when a file name/date is after the expire date */ | |
709 | if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break; | |
710 | ||
81582353 | 711 | if (dst->rotate_dir != NULL) |
a83ff38a A |
712 | { |
713 | str = NULL; | |
81582353 | 714 | asprintf(&str, "%s/%s", dst->rotate_dir, e->name); |
a83ff38a A |
715 | if (str == NULL) return -1; |
716 | ||
81582353 | 717 | filesystem_copy(dst, e->name, str, 0); |
a83ff38a A |
718 | free(str); |
719 | } | |
720 | ||
a83ff38a | 721 | remove_directory(e->name); |
a83ff38a A |
722 | store_size -= e->size; |
723 | e->size = 0; | |
724 | ||
725 | e = e->next; | |
726 | } | |
727 | ||
81582353 | 728 | debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n"); |
a83ff38a A |
729 | |
730 | /* Delete/achive expired BB.AUX directories */ | |
81582353 | 731 | debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n"); |
a83ff38a A |
732 | |
733 | e = bb_aux_list; | |
734 | while (e != NULL) | |
735 | { | |
736 | /* stop when a file name/date is after the expire date */ | |
737 | if (strncmp(e->name + 7, today_ymd_string, today_ymd_stringlen) > 0) break; | |
738 | ||
81582353 | 739 | if (dst->rotate_dir != NULL) |
a83ff38a A |
740 | { |
741 | str = NULL; | |
81582353 | 742 | asprintf(&str, "%s/%s", dst->rotate_dir, e->name); |
a83ff38a A |
743 | if (str == NULL) return -1; |
744 | ||
81582353 | 745 | filesystem_copy(dst, e->name, str, 0); |
a83ff38a A |
746 | free(str); |
747 | } | |
748 | ||
a83ff38a | 749 | remove_directory(e->name); |
a83ff38a A |
750 | store_size -= e->size; |
751 | e->size = 0; | |
752 | ||
753 | e = e->next; | |
754 | } | |
755 | ||
81582353 | 756 | debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n"); |
57b0aad2 | 757 | |
c4fdb7d1 | 758 | /* Delete/achive expired BB files */ |
81582353 | 759 | debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n"); |
57b0aad2 | 760 | |
c4fdb7d1 A |
761 | e = bb_list; |
762 | while (e != NULL) | |
763 | { | |
764 | /* stop when a file name/date is after the expire date */ | |
765 | if (strncmp(e->name + 3, today_ymd_string, today_ymd_stringlen) > 0) break; | |
57b0aad2 | 766 | |
81582353 | 767 | if (dst->rotate_dir != NULL) |
57b0aad2 A |
768 | { |
769 | str = NULL; | |
81582353 | 770 | asprintf(&str, "%s/%s", dst->rotate_dir, e->name); |
c4fdb7d1 | 771 | if (str == NULL) return -1; |
57b0aad2 | 772 | |
c4fdb7d1 | 773 | /* syslog -x [str] -f [e->name] */ |
81582353 | 774 | filesystem_copy(dst, e->name, str, 0); |
57b0aad2 A |
775 | free(str); |
776 | } | |
777 | ||
81582353 | 778 | filesystem_unlink(e->name); |
57b0aad2 A |
779 | store_size -= e->size; |
780 | e->size = 0; | |
781 | ||
782 | e = e->next; | |
783 | } | |
784 | ||
81582353 | 785 | debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n"); |
57b0aad2 | 786 | |
81582353 A |
787 | if (dst->all_max > 0) |
788 | { | |
789 | /* if data store is over max_size, delete/archive more YMD files */ | |
790 | if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n"); | |
a83ff38a | 791 | |
81582353 A |
792 | e = ymd_list; |
793 | while ((e != NULL) && (store_size > dst->all_max)) | |
794 | { | |
795 | if (e->size != 0) | |
796 | { | |
797 | /* stop when we get to today's files */ | |
798 | if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0) break; | |
799 | ||
800 | if (dst->rotate_dir != NULL) | |
801 | { | |
802 | str = NULL; | |
803 | asprintf(&str, "%s/%s", dst->rotate_dir, e->name); | |
804 | if (str == NULL) return -1; | |
805 | ||
806 | /* syslog -x [str] -f [e->name] */ | |
807 | filesystem_copy(dst, e->name, str, 0); | |
808 | free(str); | |
809 | } | |
810 | ||
811 | filesystem_unlink(e->name); | |
812 | store_size -= e->size; | |
813 | e->size = 0; | |
814 | } | |
815 | ||
816 | e = e->next; | |
817 | } | |
818 | ||
819 | /* if data store is over dst->all_max, delete/archive more BB files */ | |
820 | if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n"); | |
821 | ||
822 | e = bb_list; | |
823 | while ((e != NULL) && (store_size > dst->all_max)) | |
824 | { | |
825 | if (e->size != 0) | |
826 | { | |
827 | if (dst->rotate_dir != NULL) | |
828 | { | |
829 | str = NULL; | |
830 | asprintf(&str, "%s/%s", dst->rotate_dir, e->name); | |
831 | if (str == NULL) return -1; | |
832 | ||
833 | /* syslog -x [str] -f [e->name] */ | |
834 | filesystem_copy(dst, e->name, str, 0); | |
835 | free(str); | |
836 | } | |
837 | ||
838 | filesystem_unlink(e->name); | |
839 | store_size -= e->size; | |
840 | e->size = 0; | |
841 | } | |
842 | ||
843 | e = e->next; | |
844 | } | |
845 | } | |
846 | ||
847 | free_name_list(ymd_list); | |
848 | free_name_list(bb_list); | |
849 | free_name_list(aux_list); | |
850 | free_name_list(bb_aux_list); | |
851 | ||
852 | debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); | |
853 | ||
854 | return 0; | |
855 | } | |
856 | ||
857 | /* move sequenced source files to dst dir, renaming as we go */ | |
858 | static int | |
859 | module_copy_rename(asl_out_dst_data_t *dst) | |
860 | { | |
861 | asl_out_file_list_t *src_list, *dst_list, *f, *dst_last; | |
862 | char *base, *dst_dir; | |
863 | char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN]; | |
864 | uint32_t src_count, dst_count; | |
865 | int32_t x, moved; | |
866 | ||
867 | if (dst == NULL) return -1; | |
868 | if (dst->path == NULL) return -1; | |
869 | ||
870 | base = strrchr(dst->path, '/'); | |
871 | if (base == NULL) return -1; | |
872 | ||
873 | src_list = asl_list_src_files(dst); | |
874 | if (src_list == 0) | |
c4fdb7d1 | 875 | { |
81582353 A |
876 | debug_log(ASL_LEVEL_INFO, " no src files\n"); |
877 | return 0; | |
878 | } | |
879 | ||
880 | debug_log(ASL_LEVEL_INFO, " src files\n"); | |
881 | ||
882 | src_count = 0; | |
883 | for (f = src_list; f != NULL; f = f->next) | |
884 | { | |
885 | debug_log(ASL_LEVEL_INFO, " %s\n", f->name); | |
886 | src_count++; | |
887 | } | |
888 | ||
889 | dst_list = asl_list_dst_files(dst); | |
890 | ||
891 | *base = '\0'; | |
892 | base++; | |
893 | ||
894 | dst_dir = dst->rotate_dir; | |
895 | if (dst_dir == NULL) dst_dir = dst->path; | |
896 | ||
897 | dst_count = 0; | |
898 | dst_last = dst_list; | |
899 | ||
900 | if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n"); | |
901 | else debug_log(ASL_LEVEL_INFO, " dst files\n"); | |
902 | ||
903 | for (f = dst_list; f != NULL; f = f->next) | |
904 | { | |
905 | debug_log(ASL_LEVEL_INFO, " %s\n", f->name); | |
906 | dst_last = f; | |
907 | dst_count++; | |
908 | } | |
909 | ||
910 | if (dst->flags & MODULE_FLAG_STYLE_SEQ) | |
911 | { | |
912 | for (f = dst_last; f != NULL; f = f->prev) | |
c4fdb7d1 | 913 | { |
81582353 A |
914 | int is_gz = 0; |
915 | char *dot = strrchr(f->name, '.'); | |
916 | if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1; | |
917 | ||
918 | snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name); | |
919 | snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, base, f->seq+src_count, (is_gz == 1) ? ".gz" : ""); | |
920 | filesystem_rename(fpathsrc, fpathdst); | |
921 | } | |
57b0aad2 | 922 | |
81582353 A |
923 | for (f = src_list, x = 0; f != NULL; f = f->next, x++) |
924 | { | |
925 | snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name); | |
926 | snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, base, x); | |
927 | moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); | |
928 | if (moved != 0) filesystem_unlink(fpathsrc); | |
929 | } | |
930 | } | |
931 | else | |
932 | { | |
933 | for (f = src_list; f != NULL; f = f->next) | |
934 | { | |
935 | /* final / active base stamped file looks like a checkpointed file - ignore it */ | |
936 | if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break; | |
937 | ||
938 | snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name); | |
939 | ||
940 | /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */ | |
941 | if (dst->flags & MODULE_FLAG_EXTERNAL) | |
c4fdb7d1 | 942 | { |
81582353 A |
943 | char tstamp[32]; |
944 | ||
945 | asl_make_timestamp(f->ftime, dst->flags, tstamp, sizeof(tstamp)); | |
946 | snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, base, tstamp); | |
947 | } | |
948 | else | |
949 | { | |
950 | snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name); | |
c4fdb7d1 | 951 | } |
57b0aad2 | 952 | |
81582353 A |
953 | moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); |
954 | if (moved != 0) filesystem_unlink(fpathsrc); | |
955 | } | |
956 | } | |
57b0aad2 | 957 | |
81582353 A |
958 | asl_out_file_list_free(src_list); |
959 | asl_out_file_list_free(dst_list); | |
960 | ||
961 | if (base != NULL) *--base = '/'; | |
962 | ||
963 | return 0; | |
964 | } | |
965 | ||
966 | /* delete expired files */ | |
967 | static int | |
968 | module_expire(asl_out_dst_data_t *dst) | |
969 | { | |
970 | asl_out_file_list_t *dst_list, *f; | |
971 | char *base, *dst_dir, fpath[MAXPATHLEN]; | |
972 | time_t now, ttl, cutoff; | |
973 | ||
974 | if (dst == NULL) return -1; | |
975 | if (dst->path == NULL) return -1; | |
976 | if (dst->ttl == 0) return 0; | |
977 | ||
978 | ttl = 0; | |
979 | if (module_ttl > 0) ttl = module_ttl; | |
980 | else ttl = dst->ttl; | |
981 | ||
982 | ttl *= SECONDS_PER_DAY; | |
983 | ||
984 | now = time(NULL); | |
985 | if (ttl > now) return 0; | |
986 | ||
987 | cutoff = now - ttl; | |
988 | ||
989 | base = strrchr(dst->path, '/'); | |
990 | if (base == NULL) return -1; | |
991 | ||
992 | dst_list = asl_list_dst_files(dst); | |
993 | ||
994 | *base = '\0'; | |
995 | ||
996 | dst_dir = dst->rotate_dir; | |
997 | if (dst_dir == NULL) dst_dir = dst->path; | |
998 | ||
999 | if (dst_list == NULL) | |
1000 | { | |
1001 | debug_log(ASL_LEVEL_INFO, " no dst files\n"); | |
1002 | } | |
1003 | else | |
1004 | { | |
1005 | debug_log(ASL_LEVEL_INFO, " dst files\n"); | |
1006 | for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, " %s\n", f->name); | |
1007 | } | |
1008 | ||
1009 | for (f = dst_list; f != NULL; f = f->next) | |
1010 | { | |
1011 | if (f->ftime <= cutoff) | |
1012 | { | |
1013 | snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); | |
1014 | filesystem_unlink(fpath); | |
c4fdb7d1 | 1015 | } |
81582353 | 1016 | } |
57b0aad2 | 1017 | |
81582353 A |
1018 | asl_out_file_list_free(dst_list); |
1019 | ||
1020 | if (base != NULL) *base = '/'; | |
1021 | ||
1022 | return 0; | |
1023 | } | |
1024 | ||
1025 | /* check all_max size and delete files (oldest first) to stay within size limit */ | |
1026 | static int | |
1027 | module_check_size(asl_out_dst_data_t *dst) | |
1028 | { | |
1029 | asl_out_file_list_t *dst_list, *f; | |
1030 | char *base, *dst_dir, fpath[MAXPATHLEN]; | |
1031 | size_t total; | |
1032 | ||
1033 | if (dst == NULL) return -1; | |
1034 | if (dst->path == NULL) return -1; | |
1035 | ||
1036 | if (dst->all_max == 0) return 0; | |
1037 | ||
1038 | base = NULL; | |
1039 | dst_dir = dst->rotate_dir; | |
1040 | if (dst_dir == NULL) | |
1041 | { | |
1042 | dst_dir = dst->path; | |
1043 | base = strrchr(dst->path, '/'); | |
1044 | if (base == NULL) return -1; | |
1045 | *base = '\0'; | |
57b0aad2 A |
1046 | } |
1047 | ||
81582353 | 1048 | dst_list = asl_list_dst_files(dst); |
57b0aad2 | 1049 | |
81582353 | 1050 | if (dst_list == NULL) |
57b0aad2 | 1051 | { |
81582353 A |
1052 | debug_log(ASL_LEVEL_INFO, " no dst files\n"); |
1053 | } | |
1054 | else | |
1055 | { | |
1056 | debug_log(ASL_LEVEL_INFO, " dst files\n"); | |
1057 | for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size); | |
1058 | } | |
1059 | ||
1060 | total = 0; | |
1061 | for (f = dst_list; f != NULL; f = f->next) total += f->size; | |
1062 | ||
1063 | for (f = dst_list; (total > dst->all_max) && (f != NULL); f = f->next) | |
1064 | { | |
1065 | snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); | |
1066 | filesystem_unlink(fpath); | |
1067 | total -= f->size; | |
1068 | } | |
1069 | ||
1070 | asl_out_file_list_free(dst_list); | |
1071 | ||
1072 | if (base != NULL) *base = '/'; | |
1073 | ||
1074 | return 0; | |
1075 | } | |
1076 | ||
1077 | ||
1078 | static int | |
1079 | process_module(asl_out_module_t *mod) | |
1080 | { | |
1081 | asl_out_rule_t *r; | |
1082 | ||
1083 | if (mod == NULL) return -1; | |
1084 | ||
1085 | debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); | |
1086 | debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); | |
1087 | ||
1088 | for (r = mod->ruleset; r != NULL; r = r->next) | |
1089 | { | |
1090 | if (r->action == ACTION_OUT_DEST) | |
57b0aad2 | 1091 | { |
81582353 | 1092 | if (r->dst == NULL) |
c4fdb7d1 | 1093 | { |
81582353 | 1094 | debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n"); |
c4fdb7d1 | 1095 | } |
81582353 A |
1096 | else if (r->dst->flags & MODULE_FLAG_ROTATE) |
1097 | { | |
1098 | debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", r->dst->path); | |
1099 | debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n"); | |
c4fdb7d1 | 1100 | |
81582353 | 1101 | module_copy_rename(r->dst); |
c4fdb7d1 | 1102 | |
81582353 A |
1103 | if (r->dst->ttl > 0) |
1104 | { | |
1105 | debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl); | |
1106 | module_expire(r->dst); | |
1107 | } | |
1108 | ||
1109 | if (r->dst->all_max > 0) | |
1110 | { | |
1111 | debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", r->dst->all_max); | |
1112 | module_check_size(r->dst); | |
1113 | } | |
1114 | } | |
1115 | else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl > 0)) | |
1116 | { | |
1117 | process_asl_data_store(r->dst); | |
1118 | } | |
57b0aad2 | 1119 | } |
81582353 | 1120 | } |
57b0aad2 | 1121 | |
81582353 A |
1122 | debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); |
1123 | return 0; | |
1124 | } | |
1125 | ||
1126 | aslresponse | |
1127 | control_query(aslmsg a) | |
1128 | { | |
1129 | asl_search_result_t *out; | |
1130 | char *qstr, *str, *res; | |
1131 | uint32_t len, reslen, status; | |
1132 | uint64_t cmax, qmin; | |
1133 | kern_return_t kstatus; | |
1134 | caddr_t vmstr; | |
1135 | security_token_t sec; | |
1136 | ||
1137 | if (asl_server_port == MACH_PORT_NULL) | |
1138 | { | |
1139 | bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); | |
1140 | if (asl_server_port == MACH_PORT_NULL) return NULL; | |
57b0aad2 A |
1141 | } |
1142 | ||
81582353 | 1143 | qstr = asl_msg_to_string((asl_msg_t *)a, &len); |
57b0aad2 | 1144 | |
81582353 A |
1145 | str = NULL; |
1146 | if (qstr == NULL) | |
1147 | { | |
1148 | asprintf(&str, "1\nQ [= ASLOption control]\n"); | |
1149 | } | |
1150 | else | |
c4fdb7d1 | 1151 | { |
81582353 A |
1152 | asprintf(&str, "1\n%s [= ASLOption control]\n", qstr); |
1153 | free(qstr); | |
c4fdb7d1 | 1154 | } |
57b0aad2 | 1155 | |
81582353 A |
1156 | if (str == NULL) return NULL; |
1157 | ||
1158 | /* length includes trailing nul */ | |
1159 | len = strlen(str) + 1; | |
1160 | out = NULL; | |
1161 | qmin = 0; | |
1162 | cmax = 0; | |
1163 | sec.val[0] = -1; | |
1164 | sec.val[1] = -1; | |
1165 | ||
1166 | res = NULL; | |
1167 | reslen = 0; | |
1168 | status = ASL_STATUS_OK; | |
1169 | ||
1170 | kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); | |
1171 | if (kstatus != KERN_SUCCESS) return NULL; | |
1172 | ||
1173 | memmove(vmstr, str, len); | |
1174 | free(str); | |
1175 | ||
1176 | status = 0; | |
1177 | kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec); | |
1178 | if (kstatus != KERN_SUCCESS) return NULL; | |
1179 | ||
1180 | if (res == NULL) return NULL; | |
1181 | ||
1182 | out = asl_list_from_string(res); | |
1183 | vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); | |
1184 | ||
1185 | return out; | |
1186 | } | |
1187 | ||
1188 | int | |
1189 | checkpoint(const char *name) | |
1190 | { | |
1191 | /* send checkpoint message to syslogd */ | |
1192 | debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name); | |
1193 | if (dryrun != 0) return 0; | |
1194 | ||
1195 | aslmsg qmsg = asl_new(ASL_TYPE_QUERY); | |
1196 | char *tmp = NULL; | |
1197 | aslresponse res; | |
1198 | ||
1199 | asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name); | |
1200 | asl_set_query(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL); | |
1201 | free(tmp); | |
1202 | ||
1203 | res = control_query(qmsg); | |
1204 | ||
1205 | aslresponse_free(res); | |
57b0aad2 A |
1206 | return 0; |
1207 | } | |
1208 | ||
81582353 A |
1209 | int |
1210 | cli_main(int argc, char *argv[]) | |
1211 | { | |
1212 | int i, work; | |
1213 | asl_out_module_t *mod, *m; | |
1214 | asl_out_rule_t *r; | |
1215 | asl_out_dst_data_t store; | |
1216 | const char *mname = NULL; | |
1217 | ||
1218 | if (geteuid() != 0) | |
1219 | { | |
1220 | if (argc == 0) debug = DEBUG_ASL; | |
1221 | else debug = DEBUG_STDERR; | |
1222 | ||
1223 | debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n"); | |
1224 | exit(1); | |
1225 | } | |
1226 | ||
1227 | module_ttl = DEFAULT_TTL; | |
1228 | ||
1229 | /* cobble up a dst_data for the main asl_store */ | |
1230 | memset(&store, 0, sizeof(store)); | |
1231 | store.ttl = DEFAULT_TTL; | |
1232 | store.all_max = DEFAULT_MAX_SIZE; | |
1233 | ||
1234 | /* get parameters from asl.conf */ | |
1235 | mod = asl_out_module_init(); | |
1236 | ||
1237 | if (mod != NULL) | |
1238 | { | |
1239 | for (r = mod->ruleset; r != NULL; r = r->next) | |
1240 | { | |
1241 | if (r->action == ACTION_SET_PARAM) | |
1242 | { | |
1243 | if (r->query == NULL) _aslmanager_set_param(&store, r->options); | |
1244 | } | |
1245 | } | |
1246 | } | |
1247 | ||
1248 | work = DO_ASLDB | DO_MODULE; | |
1249 | ||
1250 | for (i = 1; i < argc; i++) | |
1251 | { | |
1252 | if (!strcmp(argv[i], "-a")) | |
1253 | { | |
1254 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.rotate_dir = strdup(argv[++i]); | |
1255 | else store.rotate_dir = strdup(PATH_ASL_ARCHIVE); | |
1256 | store.mode = 0400; | |
1257 | } | |
1258 | else if (!strcmp(argv[i], "-s")) | |
1259 | { | |
1260 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.path = strdup(argv[++i]); | |
1261 | } | |
1262 | else if (!strcmp(argv[i], "-store_ttl")) | |
1263 | { | |
1264 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.ttl = atoi(argv[++i]); | |
1265 | } | |
1266 | else if (!strcmp(argv[i], "-module_ttl")) | |
1267 | { | |
1268 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = atoi(argv[++i]); | |
1269 | } | |
1270 | else if (!strcmp(argv[i], "-ttl")) | |
1271 | { | |
1272 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = store.ttl = atoi(argv[++i]); | |
1273 | } | |
1274 | else if (!strcmp(argv[i], "-size")) | |
1275 | { | |
1276 | if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.all_max = asl_str_to_size(argv[++i]); | |
1277 | } | |
1278 | else if (!strcmp(argv[i], "-checkpoint")) | |
1279 | { | |
1280 | work |= DO_CHECKPT; | |
1281 | } | |
1282 | else if (!strcmp(argv[i], "-module")) | |
1283 | { | |
1284 | work &= ~DO_ASLDB; | |
1285 | ||
1286 | /* optional name follows -module */ | |
1287 | if ((i +1) < argc) | |
1288 | { | |
1289 | if (argv[i + 1][0] != '-') mname = argv[++i]; | |
1290 | } | |
1291 | } | |
1292 | else if (!strcmp(argv[i], "-asldb")) | |
1293 | { | |
1294 | work = DO_ASLDB; | |
1295 | } | |
1296 | else if (!strcmp(argv[i], "-d")) | |
1297 | { | |
1298 | if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); | |
1299 | else set_debug(DEBUG_STDERR, NULL); | |
1300 | } | |
1301 | else if (!strcmp(argv[i], "-dd")) | |
1302 | { | |
1303 | dryrun = 1; | |
1304 | ||
1305 | if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); | |
1306 | else set_debug(DEBUG_STDERR, NULL); | |
1307 | } | |
1308 | } | |
1309 | ||
1310 | if (store.path == NULL) store.path = strdup(PATH_ASL_STORE); | |
1311 | ||
1312 | debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", (dryrun == 1) ? " dryrun" : ""); | |
1313 | ||
1314 | if (work & DO_ASLDB) process_asl_data_store(&store); | |
1315 | ||
1316 | free(store.path); | |
1317 | free(store.rotate_dir); | |
1318 | ||
1319 | if (work & DO_MODULE) | |
1320 | { | |
1321 | if (work & DO_CHECKPT) checkpoint(mname); | |
1322 | ||
1323 | if (mod != NULL) | |
1324 | { | |
1325 | for (m = mod; m != NULL; m = m->next) | |
1326 | { | |
1327 | if ((mname == NULL) || ((m->name != NULL) && (!strcmp(m->name, mname)))) | |
1328 | { | |
1329 | process_module(m); | |
1330 | } | |
1331 | } | |
1332 | } | |
1333 | } | |
1334 | ||
1335 | asl_out_module_free(mod); | |
1336 | ||
1337 | debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); | |
1338 | debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", (dryrun == 1) ? " dryrun" : ""); | |
1339 | if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd); | |
1340 | ||
1341 | return 0; | |
1342 | } | |
1343 | ||
1344 | static void | |
1345 | accept_connection(xpc_connection_t peer) | |
1346 | { | |
1347 | xpc_connection_set_event_handler(peer, ^(xpc_object_t request) { | |
1348 | if (xpc_get_type(request) == XPC_TYPE_DICTIONARY) | |
1349 | { | |
1350 | uid_t uid = xpc_connection_get_euid(peer); | |
1351 | ||
1352 | /* send a reply immediately */ | |
1353 | xpc_object_t reply = xpc_dictionary_create_reply(request); | |
1354 | xpc_connection_send_message(peer, reply); | |
1355 | xpc_release(reply); | |
1356 | ||
1357 | /* | |
1358 | * Some day, we may use the dictionary to pass parameters | |
1359 | * to aslmanager, but for now, we ignore the input. | |
1360 | */ | |
1361 | if (uid == 0) cli_main(0, NULL); | |
1362 | } | |
1363 | else if (xpc_get_type(request) == XPC_TYPE_ERROR) | |
1364 | { | |
1365 | /* disconnect */ | |
1366 | } | |
1367 | ||
1368 | dispatch_async(serverq, ^__attribute__((noreturn)) { xpc_server_exit(0); }); | |
1369 | }); | |
1370 | ||
1371 | xpc_connection_resume(peer); | |
1372 | } | |
1373 | ||
1374 | int | |
1375 | main(int argc, char *argv[]) | |
1376 | { | |
1377 | int64_t is_managed = 0; | |
1378 | ||
1379 | vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &is_managed); | |
1380 | ||
1381 | if (is_managed == 0) return cli_main(argc, argv); | |
1382 | ||
1383 | /* XPC server */ | |
1384 | serverq = dispatch_queue_create("aslmanager", NULL); | |
1385 | xpc_track_activity(); | |
1386 | ||
1387 | /* Handle incoming messages. */ | |
1388 | listener = xpc_connection_create_mach_service("com.apple.aslmanager", serverq, XPC_CONNECTION_MACH_SERVICE_LISTENER); | |
1389 | xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) { | |
1390 | if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer); | |
1391 | }); | |
1392 | xpc_connection_resume(listener); | |
1393 | ||
1394 | dispatch_main(); | |
1395 | } |