]> git.saurik.com Git - apple/syslog.git/blob - aslmanager.tproj/daemon.c
syslog-377.60.2.tar.gz
[apple/syslog.git] / aslmanager.tproj / daemon.c
1 /*
2 * Copyright (c) 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 <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <asl.h>
28 #include <asl_private.h>
29 #include <asl_core.h>
30 #include <asl_file.h>
31 #include <asl_store.h>
32 #include <copyfile.h>
33 #include <time.h>
34 #include <sys/time.h>
35 #include <sys/stat.h>
36 #include <sys/param.h>
37 #include <zlib.h>
38 #include <dirent.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stdint.h>
42 #include <servers/bootstrap.h>
43 #include <bootstrap_priv.h>
44 #include <mach/mach.h>
45 #include <fcntl.h>
46 #include <sys/attr.h>
47 #include <dispatch/dispatch.h>
48 #include <xpc/xpc.h>
49 #include <xpc/private.h>
50 #include <os/assumes.h>
51 #include <vproc_priv.h>
52 #include <libkern/OSAtomic.h>
53 #include "daemon.h"
54 #include "asl_ipc.h"
55
56 /* global */
57 extern bool dryrun;
58 extern uint32_t debug;
59 extern FILE *debugfp;
60 extern dispatch_queue_t work_queue;
61
62 static mach_port_t asl_server_port;
63 static aslclient aslc;
64 static int asl_aux_fd = -1;
65
66 const char *
67 keep_str(uint8_t mask)
68 {
69 static char str[9];
70 uint32_t x = 0;
71
72 memset(str, 0, sizeof(str));
73 if (mask & 0x01) str[x++] = '0';
74 if (mask & 0x02) str[x++] = '1';
75 if (mask & 0x04) str[x++] = '2';
76 if (mask & 0x08) str[x++] = '3';
77 if (mask & 0x10) str[x++] = '4';
78 if (mask & 0x20) str[x++] = '5';
79 if (mask & 0x40) str[x++] = '6';
80 if (mask & 0x80) str[x++] = '7';
81 if (x == 0) str[x++] = '-';
82 return str;
83 }
84
85 void
86 set_debug(int flag, const char *str)
87 {
88 int level, x;
89
90 if (str == NULL) x = ASL_LEVEL_ERR;
91 else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1);
92 else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str);
93 else x = ASL_LEVEL_ERR;
94
95 if (x <= 0) x = 0;
96 else if (x > 7) x = 7;
97
98 level = debug & DEBUG_LEVEL_MASK;
99 if (x > level) level = x;
100
101 debug = debug & DEBUG_FLAG_MASK;
102 debug |= flag;
103 debug |= level;
104 }
105
106 void
107 debug_log(int level, char *str, ...)
108 {
109 va_list v;
110 char ts[32];
111
112 time_t now = time(NULL);
113 memset(ts, 0, sizeof(ts));
114 strftime(ts, sizeof(ts), "%b %e %T", localtime(&now));
115
116 if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK)))
117 {
118 fprintf(stderr, "%s: ", ts);
119 va_start(v, str);
120 vfprintf(stderr, str, v);
121 va_end(v);
122 }
123
124 if ((debug & DEBUG_FILE) && (debugfp != NULL))
125 {
126 fprintf(debugfp, "%s: ", ts);
127 va_start(v, str);
128 vfprintf(debugfp, str, v);
129 va_end(v);
130 }
131
132 if (debug & DEBUG_ASL)
133 {
134 char *line = NULL;
135
136 if (aslc == NULL)
137 {
138 aslc = asl_open("aslmanager", "syslog", 0);
139 asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG);
140
141 asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report");
142 asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
143 asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd);
144 asl_msg_release(msg);
145 }
146
147 va_start(v, str);
148 vasprintf(&line, str, v);
149 va_end(v);
150
151 if (line != NULL)
152 {
153 write(asl_aux_fd, ts, strlen(ts));
154 write(asl_aux_fd, line, strlen(line));
155 }
156
157 free(line);
158 }
159 }
160
161 void
162 debug_close()
163 {
164 if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd);
165 if (debugfp != NULL) fclose(debugfp);
166 }
167
168 name_list_t *
169 add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags)
170 {
171 name_list_t *e, *x;
172
173 if (name == NULL) return l;
174
175 e = (name_list_t *)calloc(1, sizeof(name_list_t));
176 if (e == NULL) return NULL;
177
178 e->name = strdup(name);
179 if (e->name == NULL)
180 {
181 free(e);
182 return NULL;
183 }
184
185 e->size = size;
186 e->flags = flags;
187
188 /* list is sorted by name (i.e. primarily by timestamp) */
189 if (l == NULL) return e;
190
191 if (strcmp(e->name, l->name) <= 0)
192 {
193 e->next = l;
194 return e;
195 }
196
197 for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next);
198
199 e->next = x->next;
200 x->next = e;
201 return l;
202 }
203
204 void
205 free_name_list(name_list_t *l)
206 {
207 name_list_t *e;
208
209 while (l != NULL)
210 {
211 e = l;
212 l = l->next;
213 free(e->name);
214 free(e);
215 }
216
217 free(l);
218 }
219
220 int
221 copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst)
222 {
223 int in, out;
224 size_t n;
225 gzFile gz;
226 char buf[IOBUFSIZE];
227
228 in = open(src, O_RDONLY, 0);
229 if (in < 0) return -1;
230
231 out = open(dst, O_WRONLY | O_CREAT, asldst->mode & 0666);
232 if (out >= 0) out = asl_out_dst_set_access(out, asldst);
233 if (out < 0)
234 {
235 close(in);
236 return -1;
237 }
238
239 gz = gzdopen(out, "w");
240 if (gz == NULL)
241 {
242 close(in);
243 close(out);
244 return -1;
245 }
246
247 do {
248 n = read(in, buf, sizeof(buf));
249 if (n > 0) gzwrite(gz, buf, n);
250 } while (n == IOBUFSIZE);
251
252 gzclose(gz);
253 close(in);
254 close(out);
255
256 return 0;
257 }
258
259 void
260 filesystem_rename(const char *src, const char *dst)
261 {
262 int status = 0;
263
264 debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst);
265 if (dryrun) return;
266
267 status = rename(src, dst);
268 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst);
269 }
270
271 void
272 filesystem_unlink(const char *path)
273 {
274 int status = 0;
275
276 debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path);
277 if (dryrun) return;
278
279 status = unlink(path);
280 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
281 }
282
283 void
284 filesystem_truncate(const char *path)
285 {
286 int status = 0;
287
288 debug_log(ASL_LEVEL_NOTICE, " truncate %s\n", path);
289 if (dryrun) return;
290
291 status = truncate(path, 0);
292 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
293 }
294
295 void
296 filesystem_rmdir(const char *path)
297 {
298 int status = 0;
299
300 debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path);
301 if (dryrun) return;
302
303 status = rmdir(path);
304 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path);
305 }
306
307 /*
308 * Copy ASL files by reading and writing each record.
309 */
310 static uint32_t
311 copy_asl_file(const char *src, const char *dst, mode_t mode)
312 {
313 asl_file_t *fin, *fout;
314 uint32_t status;
315
316 if (src == NULL) return ASL_STATUS_INVALID_ARG;
317 if (dst == NULL) return ASL_STATUS_INVALID_ARG;
318
319 fin = NULL;
320 status = asl_file_open_read(src, &fin);
321 if (status != ASL_STATUS_OK) return status;
322
323 fout = NULL;
324 status = asl_file_open_write(dst, mode, -1, -1, &fout);
325 if (status != ASL_STATUS_OK)
326 {
327 asl_file_close(fin);
328 return status;
329 }
330
331 if (fout == NULL)
332 {
333 asl_file_close(fin);
334 return ASL_STATUS_FAILED;
335 }
336
337 fout->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;
338
339 status = asl_file_read_set_position(fin, ASL_FILE_POSITION_FIRST);
340 if (status != ASL_STATUS_OK)
341 {
342 asl_file_close(fin);
343 asl_file_close(fout);
344 return ASL_STATUS_READ_FAILED;
345 }
346
347 while (status == ASL_STATUS_OK)
348 {
349 uint64_t mid = 0;
350 asl_msg_t *msg = NULL;
351
352 status = asl_file_fetch_next(fin, &msg);
353 if (msg == NULL)
354 {
355 status = ASL_STATUS_OK;
356 break;
357 }
358
359 if (status != ASL_STATUS_OK) break;
360
361 status = asl_file_save(fout, msg, &mid);
362 asl_msg_release(msg);
363 }
364
365 asl_file_close(fin);
366 asl_file_close(fout);
367
368 return status;
369 }
370
371 int32_t
372 filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags)
373 {
374 char *dot;
375
376 if ((src == NULL) || (dst == NULL)) return 0;
377
378 dot = strrchr(src, '.');
379 if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS;
380
381 if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0;
382
383 if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst);
384 else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst);
385 else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst);
386
387 if (dryrun) return 0;
388
389 if (flags & MODULE_FLAG_TYPE_ASL)
390 {
391 uint32_t status = copy_asl_file(src, dst, asldst->mode);
392 if (status != 0)
393 {
394 debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst);
395 return 0;
396 }
397 }
398 else if (flags & MODULE_FLAG_COMPRESS)
399 {
400 char gzdst[MAXPATHLEN];
401
402 snprintf(gzdst, sizeof(gzdst), "%s.gz", dst);
403
404 int status = copy_compress_file(asldst, src, gzdst);
405 if (status != 0)
406 {
407 debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst);
408 return 0;
409 }
410 }
411 else
412 {
413 int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
414 if (status != 0)
415 {
416 debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst);
417 return 0;
418 }
419 }
420
421 return 1;
422 }
423
424 int32_t
425 filesystem_reset_ctime(const char *path)
426 {
427 struct attrlist attr_list;
428 struct timespec now;
429
430 debug_log(ASL_LEVEL_NOTICE, " reset ctime %s\n", path);
431
432 memset(&attr_list, 0, sizeof(attr_list));
433 attr_list.bitmapcount = ATTR_BIT_MAP_COUNT;
434 attr_list.commonattr = ATTR_CMN_CRTIME;
435
436 memset(&now, 0, sizeof(now));
437 now.tv_sec = time(NULL);
438
439 return setattrlist(path, &attr_list, &now, sizeof(now), 0);
440 }
441
442 int
443 remove_directory(const char *path)
444 {
445 DIR *dp;
446 struct dirent *dent;
447 char *str;
448
449 dp = opendir(path);
450 if (dp == NULL) return 0;
451
452 while ((dent = readdir(dp)) != NULL)
453 {
454 if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
455 asprintf(&str, "%s/%s", path, dent->d_name);
456 if (str != NULL)
457 {
458 filesystem_unlink(str);
459 free(str);
460 str = NULL;
461 }
462 }
463
464 closedir(dp);
465 filesystem_rmdir(path);
466
467 return 0;
468 }
469
470 size_t
471 directory_size(const char *path)
472 {
473 DIR *dp;
474 struct dirent *dent;
475 struct stat sb;
476 size_t size;
477 char *str;
478
479 dp = opendir(path);
480 if (dp == NULL) return 0;
481
482 size = 0;
483 while ((dent = readdir(dp)) != NULL)
484 {
485 if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
486
487 memset(&sb, 0, sizeof(struct stat));
488 str = NULL;
489 asprintf(&str, "%s/%s", path, dent->d_name);
490
491 if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
492 {
493 size += sb.st_size;
494 free(str);
495 }
496 }
497
498 closedir(dp);
499 return size;
500 }
501
502 time_t
503 parse_ymd_name(const char *name)
504 {
505 struct tm ftime;
506 time_t created;
507 int32_t tzh, tzm, sign = -1;
508 const char *x;
509 bool legacy = false;
510
511 if (name == NULL) return -1;
512
513 x = name;
514
515 if ((*x == 'T') || (*x == 't'))
516 {
517 x++;
518 created = atol(x);
519 if ((created == 0) && (*x != '0')) return -1;
520
521 x = strchr(x, '.');
522 if (x == NULL) return -1;
523
524 return created;
525 }
526
527 memset(&ftime, 0, sizeof(ftime));
528
529 if ((*x < '0') || (*x > '9')) return 1;
530 ftime.tm_year = 1000 * (*x++ - '0');
531
532 if ((*x < '0') || (*x > '9')) return 1;
533 ftime.tm_year += 100 * (*x++ - '0');
534
535 if ((*x < '0') || (*x > '9')) return 1;
536 ftime.tm_year += 10 * (*x++ - '0');
537
538 if ((*x < '0') || (*x > '9')) return 1;
539 ftime.tm_year += *x++ - '0';
540 ftime.tm_year -= 1900;
541
542 if (*x == '-') x++;
543 else if (*x == '.')
544 {
545 x++;
546 legacy = true;
547 }
548
549 if ((*x < '0') || (*x > '9')) return 1;
550 ftime.tm_mon = 10 * (*x++ - '0');
551
552 if ((*x < '0') || (*x > '9')) return 1;
553 ftime.tm_mon += *x++ - '0';
554 ftime.tm_mon -= 1;
555
556 if ((*x == '-') || (*x == '.')) x++;
557
558 if ((*x < '0') || (*x > '9')) return 1;
559 ftime.tm_mday = 10 * (*x++ - '0');
560
561 if ((*x < '0') || (*x > '9')) return 1;
562 ftime.tm_mday += *x++ - '0';
563
564 if (legacy)
565 {
566 if ((*x != '.') && (*x != '\0')) return -1;
567
568 /* assume the file was created at midnight */
569 ftime.tm_hour = 24;
570 ftime.tm_min = 0;
571 ftime.tm_sec = 0;
572 ftime.tm_isdst = -1;
573
574 created = mktime(&ftime);
575 return created;
576 }
577
578 if ((*x != 'T') && (*x != 't')) return 1;
579 x++;
580
581 if ((*x < '0') || (*x > '9')) return 1;
582 ftime.tm_hour = 10 * (*x++ - '0');
583
584 if ((*x < '0') || (*x > '9')) return 1;
585 ftime.tm_hour += *x++ - '0';
586
587 if (*x == ':') x++;
588
589 if ((*x < '0') || (*x > '9')) return 1;
590 ftime.tm_min = 10 * (*x++ - '0');
591
592 if ((*x < '0') || (*x > '9')) return 1;
593 ftime.tm_min += *x++ - '0';
594
595 if (*x == ':') x++;
596
597 if ((*x < '0') || (*x > '9')) return 1;
598 ftime.tm_sec = 10 * (*x++ - '0');
599
600 if ((*x < '0') || (*x > '9')) return 1;
601 ftime.tm_sec += *x++ - '0';
602
603 if ((*x == 'Z') || (*x == 'z'))
604 {
605 created = timegm(&ftime);
606 return created;
607 }
608
609 if ((*x != '+') && (*x != '-')) return 1;
610
611 if (*x == '-') sign = 1;
612 x++;
613
614 if ((*x < '0') || (*x > '9')) return 1;
615 tzh = 10 * (*x++ - '0');
616
617 if ((*x < '0') || (*x > '9')) tzh /= 10;
618 else tzh += *x++ - '0';
619
620 if (tzh > 23) return 1;
621
622 tzm = 0;
623 if ((*x == ':') || ((*x >= '0') && (*x <= '9')))
624 {
625 if (*x != ':') tzm = 10 * (*x - '0');
626 x++;
627
628 if ((*x < '0') || (*x > '9'))return -1;
629 tzm += *x++ - '0';
630
631 if (tzm > 59) return -1;
632 }
633
634 ftime.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzm * SECONDS_PER_MINUTE));
635
636 if ((*x != '.') && (*x != '\0')) return -1;
637
638 created = timegm(&ftime);
639 return created;
640 }
641
642
643 /*
644 * Determine the age (in seconds) of a YMD file from its name.
645 * Also determines UID and GID from ".Unnn.Gnnn" part of file name.
646 */
647 uint32_t
648 ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g)
649 {
650 struct tm ftime;
651 time_t created;
652 uint32_t seconds;
653 const char *p;
654
655 if (name == NULL) return 0;
656
657 if (now == 0) now = time(NULL);
658
659 memset(&ftime, 0, sizeof(struct tm));
660
661 created = parse_ymd_name(name);
662 if (created < 0) return 0;
663 if (created > now) return 0;
664 seconds = now - created;
665
666 if (u != NULL)
667 {
668 *u = -1;
669 p = strchr(name, 'U');
670 if (p != NULL) *u = atoi(p+1);
671 }
672
673 if (g != NULL)
674 {
675 *g = -1;
676 p = strchr(name, 'G');
677 if (p != NULL) *g = atoi(p+1);
678 }
679
680 return seconds;
681 }
682
683
684 static void
685 aux_url_callback(const char *url)
686 {
687 if (url == NULL) return;
688 if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET);
689 }
690
691 uint32_t
692 ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid)
693 {
694 asl_file_t *f = NULL;
695 uint8_t km = keep_mask;
696 uint32_t status, len, dstcount = 0;
697 char src[MAXPATHLEN];
698 char dst[MAXPATHLEN];
699
700 if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
701 if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
702 len = strlen(src) - 3;
703 snprintf(dst + len, 4, "tmp");
704
705 //TODO: check if src file is already filtered
706 debug_log(ASL_LEVEL_NOTICE, " filter %s %s ---> %s\n", src, keep_str(km), dst);
707
708 status = ASL_STATUS_OK;
709
710 if (!dryrun)
711 {
712 status = asl_file_open_read(name, &f);
713 if (status != ASL_STATUS_OK) return status;
714
715 status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback);
716 asl_file_close(f);
717 }
718
719 filesystem_unlink(src);
720 if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst);
721 else filesystem_rename(dst, src);
722
723 return status;
724 }
725
726 int
727 process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
728 {
729 time_t now, midnight, since_midnight;
730 char *str;
731 DIR *dp;
732 struct dirent *dent;
733 name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e;
734 size_t file_size, store_size;
735 struct stat sb;
736 char tstr[128];
737 struct tm t_tmp;
738 uint32_t ttl = 0;
739
740 ymd_list = NULL;
741 bb_list = NULL;
742 aux_list = NULL;
743 bb_aux_list = NULL;
744 store_size = 0;
745
746 if (dst == NULL) return 0;
747 if (dst->path == NULL) return 0;
748
749 ttl = dst->ttl[LEVEL_ALL];
750 if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
751
752 size_t all_max = dst->all_max;
753 if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
754
755 debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
756 debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path);
757
758 if (dst->rotate_dir != NULL)
759 {
760 /* check archive */
761 memset(&sb, 0, sizeof(struct stat));
762 if (stat(dst->rotate_dir, &sb) == 0)
763 {
764 /* must be a directory */
765 if (!S_ISDIR(sb.st_mode))
766 {
767 debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir);
768 return -1;
769 }
770 }
771 else
772 {
773 if (errno == ENOENT)
774 {
775 /* archive doesn't exist - create it */
776 if (mkdir(dst->rotate_dir, 0755) != 0)
777 {
778 debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno));
779 return -1;
780 }
781 }
782 else
783 {
784 /* stat failed for some other reason */
785 debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno));
786 return -1;
787 }
788 }
789 }
790
791 chdir(dst->path);
792
793 /* determine current time */
794 now = time(NULL);
795
796 localtime_r(&now, &t_tmp);
797
798 t_tmp.tm_sec = 0;
799 t_tmp.tm_min = 0;
800 t_tmp.tm_hour = 0;
801
802 midnight = mktime(&t_tmp);
803 since_midnight = now - midnight;
804
805 dp = opendir(dst->path);
806 if (dp == NULL) return -1;
807
808 /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */
809 while ((dent = readdir(dp)) != NULL)
810 {
811 uint32_t file_flags = 0;
812 char *dot = NULL;
813
814 memset(&sb, 0, sizeof(struct stat));
815 file_size = 0;
816 if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size;
817
818 dot = strrchr(dent->d_name, '.');
819 if ((dot != NULL) && !strcmp(dot, ".gz")) file_flags |= NAME_LIST_FLAG_COMPRESSED;
820
821 if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9'))
822 {
823 ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags);
824 store_size += file_size;
825 }
826 else if (((dent->d_name[0] == 'T') || (dent->d_name[0] == 't')) && (dent->d_name[1] >= '0') && (dent->d_name[1] <= '9'))
827 {
828 ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags);
829 store_size += file_size;
830 }
831 else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
832 {
833 file_size = directory_size(dent->d_name);
834 aux_list = add_to_name_list(aux_list, dent->d_name, file_size, file_flags);
835 store_size += file_size;
836 }
837 else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
838 {
839 file_size = directory_size(dent->d_name);
840 bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size, file_flags);
841 store_size += file_size;
842 }
843 else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
844 {
845 bb_list = add_to_name_list(bb_list, dent->d_name, file_size, file_flags);
846 store_size += file_size;
847 }
848 else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
849 {}
850 else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
851 {}
852 else if (!strcmp(dent->d_name, ASL_INTERNAL_LOGS_DIR))
853 {}
854 else
855 {
856 debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
857 }
858 }
859
860 closedir(dp);
861
862 debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
863 asl_core_time_to_str(ttl, tstr, sizeof(tstr));
864 debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files (TTL = %s)\n", tstr);
865 for (e = ymd_list; e != NULL; e = e->next)
866 {
867 uint32_t age = ymd_file_age(e->name, now, NULL, NULL);
868 asl_core_time_to_str(age, tstr, sizeof(tstr));
869 debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s%s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : "");
870 }
871
872 debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n");
873 for (e = aux_list; e != NULL; e = e->next)
874 {
875 uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL) / SECONDS_PER_DAY;
876 asl_core_time_to_str(age, tstr, sizeof(tstr));
877 debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : "");
878 }
879
880 debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n");
881 for (e = bb_aux_list; e != NULL; e = e->next)
882 {
883 uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL);
884 asl_core_time_to_str(age, tstr, sizeof(tstr));
885 debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : "");
886 }
887
888 debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n");
889 for (e = bb_list; e != NULL; e = e->next)
890 {
891 uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL) / SECONDS_PER_DAY;
892 asl_core_time_to_str(age, tstr, sizeof(tstr));
893 debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : "");
894 }
895
896 /* Delete/achive expired YMD files */
897 debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n");
898
899 e = ymd_list;
900 while (e != NULL)
901 {
902 uid_t ymd_uid = -1;
903 gid_t ymd_gid = -1;
904 uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid);
905
906 if (age > ttl)
907 {
908 /* file has expired, archive it if required, then unlink it */
909 if (dst->rotate_dir != NULL)
910 {
911 str = NULL;
912 asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
913 if (str == NULL) return -1;
914
915 filesystem_copy(dst, e->name, str, 0);
916 free(str);
917 }
918
919 filesystem_unlink(e->name);
920 store_size -= e->size;
921 e->size = 0;
922 }
923 else if ((e->flags & NAME_LIST_FLAG_COMPRESSED) == 0)
924 {
925 uint32_t i, bit, keep_mask;
926 mode_t ymd_mode = 0600;
927
928 /* check if there are any per-level TTLs and filter the file if required */
929 if (age > 0)
930 {
931 keep_mask = 0x000000ff;
932 bit = 1;
933 for (i = 0; i <= 7; i++)
934 {
935 if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit;
936 bit *= 2;
937 }
938
939 memset(&sb, 0, sizeof(struct stat));
940 if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777;
941
942 if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid);
943 }
944
945 if ((age > since_midnight) && (dst->flags & MODULE_FLAG_COMPRESS))
946 {
947 char gzdst[MAXPATHLEN];
948
949 snprintf(gzdst, sizeof(gzdst), "%s.gz", e->name);
950 debug_log(ASL_LEVEL_NOTICE, " compress %s ---> %s\n", e->name, gzdst);
951
952 if (!dryrun)
953 {
954 int status = copy_compress_file(dst, e->name, gzdst);
955 if (status == 0)
956 {
957 filesystem_unlink(e->name);
958 }
959 else
960 {
961 debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] compress %s ---> %s\n", status, errno, strerror(errno), e->name, gzdst);
962 return 0;
963 }
964 }
965 }
966 }
967
968 e = e->next;
969 }
970
971 debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n");
972
973 /* Delete/achive expired YMD AUX directories */
974 debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n");
975
976 e = aux_list;
977 while (e != NULL)
978 {
979 uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL);
980
981 if (age > ttl)
982 {
983 if (dst->rotate_dir != NULL)
984 {
985 str = NULL;
986 asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
987 if (str == NULL) return -1;
988
989 filesystem_copy(dst, e->name, str, 0);
990 free(str);
991 }
992
993 remove_directory(e->name);
994 store_size -= e->size;
995 e->size = 0;
996 }
997
998 e = e->next;
999 }
1000
1001 debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n");
1002
1003 /* Delete/achive expired BB.AUX directories */
1004 debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n");
1005
1006 e = bb_aux_list;
1007 while (e != NULL)
1008 {
1009 uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL);
1010
1011 if (age > 0)
1012 {
1013 if (dst->rotate_dir != NULL)
1014 {
1015 str = NULL;
1016 asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
1017 if (str == NULL) return -1;
1018
1019 filesystem_copy(dst, e->name, str, 0);
1020 free(str);
1021 }
1022
1023 remove_directory(e->name);
1024 store_size -= e->size;
1025 e->size = 0;
1026 }
1027
1028 e = e->next;
1029 }
1030
1031 debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n");
1032
1033 /* Delete/achive expired BB files */
1034 debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n");
1035
1036 e = bb_list;
1037 while (e != NULL)
1038 {
1039 uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL);
1040
1041 if (age > 0)
1042 {
1043 if (dst->rotate_dir != NULL)
1044 {
1045 str = NULL;
1046 asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
1047 if (str == NULL) return -1;
1048
1049 /* syslog -x [str] -f [e->name] */
1050 filesystem_copy(dst, e->name, str, 0);
1051 free(str);
1052 }
1053
1054 filesystem_unlink(e->name);
1055 store_size -= e->size;
1056 e->size = 0;
1057 }
1058
1059 e = e->next;
1060 }
1061
1062 debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n");
1063
1064 if (all_max > 0)
1065 {
1066 /* if data store is over max_size, delete/archive more YMD files */
1067 if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n");
1068
1069 e = ymd_list;
1070 while ((e != NULL) && (store_size > all_max))
1071 {
1072 if (e->size != 0)
1073 {
1074 uint32_t age = ymd_file_age(e->name, now, NULL, NULL);
1075 if (age == 0)
1076 {
1077 /* do not touch active file YYYY.MM.DD.asl */
1078 e = e->next;
1079 continue;
1080 }
1081
1082 if (dst->rotate_dir != NULL)
1083 {
1084 str = NULL;
1085 asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
1086 if (str == NULL) return -1;
1087
1088 /* syslog -x [str] -f [e->name] */
1089 filesystem_copy(dst, e->name, str, 0);
1090 free(str);
1091 }
1092
1093 filesystem_unlink(e->name);
1094 store_size -= e->size;
1095 e->size = 0;
1096 }
1097
1098 e = e->next;
1099 }
1100
1101 /* if data store is over all_max, delete/archive more BB files */
1102 if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n");
1103
1104 e = bb_list;
1105 while ((e != NULL) && (store_size > all_max))
1106 {
1107 if (e->size != 0)
1108 {
1109 if (dst->rotate_dir != NULL)
1110 {
1111 str = NULL;
1112 asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
1113 if (str == NULL) return -1;
1114
1115 /* syslog -x [str] -f [e->name] */
1116 filesystem_copy(dst, e->name, str, 0);
1117 free(str);
1118 }
1119
1120 filesystem_unlink(e->name);
1121 store_size -= e->size;
1122 e->size = 0;
1123 }
1124
1125 e = e->next;
1126 }
1127 }
1128
1129 free_name_list(ymd_list);
1130 free_name_list(bb_list);
1131 free_name_list(aux_list);
1132 free_name_list(bb_aux_list);
1133
1134 debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
1135
1136 return 0;
1137 }
1138
1139 /* move sequenced source files to dst dir, renaming as we go */
1140 int
1141 module_copy_rename(asl_out_dst_data_t *dst)
1142 {
1143 asl_out_file_list_t *src_list, *dst_list, *f;
1144 char *dst_dir;
1145 char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN];
1146 uint32_t src_count, dst_count;
1147 int32_t x, moved;
1148
1149 if (dst == NULL) return -1;
1150 if (dst->path == NULL) return -1;
1151
1152 src_list = asl_list_src_files(dst);
1153
1154 /*
1155 * Note: the unmarked file (e.g. system.log) is included in src_list.
1156 * If it is from a MODULE_FLAG_EXTERNAL dst and it is less than 24 hours old,
1157 * we ignore it. If it is not external, we also ignore it since syslogd will
1158 * checkpoint it to create system.log.Tnnnnnnnnnn.
1159 */
1160 if ((src_list != NULL) && (src_list->stamp == STAMP_STYLE_NULL))
1161 {
1162 bool ignore_it = false;
1163
1164 if (dst->flags & MODULE_FLAG_EXTERNAL)
1165 {
1166 if ((time(NULL) - src_list->ftime) < SECONDS_PER_DAY)
1167 {
1168 debug_log(ASL_LEVEL_INFO, " ignore src file %s since it is external and less than a day old\n", src_list->name);
1169 ignore_it = true;
1170 }
1171 }
1172 else
1173 {
1174 debug_log(ASL_LEVEL_INFO, " ignore src file %s since it is internal and syslogd will checkpoint it when it needs to be renamed\n", src_list->name);
1175 ignore_it = true;
1176 }
1177
1178 if (ignore_it)
1179 {
1180 asl_out_file_list_t *first = src_list;
1181 src_list = src_list->next;
1182 first->next = NULL;
1183 asl_out_file_list_free(first);
1184 }
1185 }
1186
1187 if (src_list == NULL)
1188 {
1189 debug_log(ASL_LEVEL_INFO, " no src files\n");
1190 return 0;
1191 }
1192
1193 debug_log(ASL_LEVEL_INFO, " src files\n");
1194
1195 src_count = 0;
1196 for (f = src_list; f != NULL; f = f->next)
1197 {
1198 debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
1199 src_count++;
1200 }
1201
1202 dst_list = asl_list_dst_files(dst);
1203
1204 dst_dir = dst->rotate_dir;
1205 if (dst_dir == NULL) dst_dir = dst->dir;
1206
1207 dst_count = 0;
1208
1209 if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n");
1210 else debug_log(ASL_LEVEL_INFO, " dst files\n");
1211
1212 for (f = dst_list; f != NULL; f = f->next)
1213 {
1214 debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
1215 dst_count++;
1216 }
1217
1218 if (dst->style_flags & MODULE_NAME_STYLE_STAMP_SEQ)
1219 {
1220 for (f = dst_list; f != NULL; f = f->next)
1221 {
1222 int is_gz = 0;
1223 char *dot = strrchr(f->name, '.');
1224 if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1;
1225
1226 snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name);
1227
1228 if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
1229 {
1230 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, dst->base, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
1231 }
1232 else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
1233 {
1234 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d%s", dst_dir, dst->base, dst->ext, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
1235 }
1236 else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
1237 {
1238 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s%s", dst_dir, dst->base, f->seq+src_count, dst->ext, (is_gz == 1) ? ".gz" : "");
1239 }
1240
1241 filesystem_rename(fpathsrc, fpathdst);
1242 }
1243
1244 for (f = src_list, x = 0; f != NULL; f = f->next, x++)
1245 {
1246 snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name);
1247
1248 if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
1249 {
1250 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, dst->base, x);
1251 }
1252 else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
1253 {
1254 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d", dst_dir, dst->base, dst->ext, x);
1255 }
1256 else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
1257 {
1258 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s", dst_dir, dst->base, x, dst->ext);
1259 }
1260
1261 moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
1262 if (moved != 0)
1263 {
1264 if (dst->flags & MODULE_FLAG_TRUNCATE)
1265 {
1266 filesystem_truncate(fpathsrc);
1267 filesystem_reset_ctime(fpathsrc);
1268 }
1269 else
1270 {
1271 filesystem_unlink(fpathsrc);
1272 }
1273 }
1274 }
1275 }
1276 else
1277 {
1278 for (f = src_list; f != NULL; f = f->next)
1279 {
1280 /* final / active base stamped file looks like a checkpointed file - ignore it */
1281 if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break;
1282
1283 snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name);
1284
1285 /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */
1286 if (dst->flags & MODULE_FLAG_EXTERNAL)
1287 {
1288 char tstamp[32];
1289
1290 asl_make_timestamp(f->ftime, dst->style_flags, tstamp, sizeof(tstamp));
1291
1292 if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
1293 {
1294 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, dst->base, tstamp);
1295 }
1296 else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
1297 {
1298 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, dst->ext, tstamp);
1299 }
1300 else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
1301 {
1302 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, tstamp, dst->ext);
1303 }
1304
1305 }
1306 else
1307 {
1308 snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name);
1309 }
1310
1311 moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
1312 if (moved != 0)
1313 {
1314 if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
1315 else filesystem_unlink(fpathsrc);
1316 }
1317 }
1318 }
1319
1320 asl_out_file_list_free(src_list);
1321 asl_out_file_list_free(dst_list);
1322
1323 return 0;
1324 }
1325
1326 /* delete expired files */
1327 int
1328 module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
1329 {
1330 asl_out_file_list_t *dst_list, *f;
1331 char *base, *dst_dir, fpath[MAXPATHLEN];
1332 time_t now, ttl, age;
1333
1334 if (dst == NULL) return -1;
1335 if (dst->path == NULL) return -1;
1336 if (dst->ttl[LEVEL_ALL] == 0) return 0;
1337
1338 ttl = dst->ttl[LEVEL_ALL];
1339 if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
1340
1341 now = time(NULL);
1342 if (ttl > now) return 0;
1343
1344 base = strrchr(dst->path, '/');
1345 if (base == NULL) return -1;
1346
1347 dst_list = asl_list_dst_files(dst);
1348
1349 *base = '\0';
1350
1351 dst_dir = dst->rotate_dir;
1352 if (dst_dir == NULL) dst_dir = dst->dir;
1353
1354 if (dst_list == NULL)
1355 {
1356 debug_log(ASL_LEVEL_INFO, " no dst files\n");
1357 }
1358 else
1359 {
1360 debug_log(ASL_LEVEL_INFO, " dst files\n");
1361 for (f = dst_list; f != NULL; f = f->next)
1362 {
1363 char tstr[150];
1364 age = now - f->ftime;
1365
1366 asl_core_time_to_str(age, tstr, sizeof(tstr));
1367 debug_log(ASL_LEVEL_INFO, " %s (age %s%s)\n", f->name, tstr, (age > ttl) ? " - expired" : "");
1368 }
1369 }
1370
1371 for (f = dst_list; f != NULL; f = f->next)
1372 {
1373 age = now - f->ftime;
1374 if (age > ttl)
1375 {
1376 snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
1377 filesystem_unlink(fpath);
1378 }
1379 }
1380
1381 asl_out_file_list_free(dst_list);
1382
1383 if (base != NULL) *base = '/';
1384
1385 return 0;
1386 }
1387
1388 /*
1389 * Check all_max size and delete files (oldest first) to stay within size limit.
1390 * If query is true, then just report total size.
1391 */
1392 int
1393 module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool query, size_t *msize)
1394 {
1395 asl_out_file_list_t *dst_list, *f, *dst_end;
1396 char *dst_dir, fpath[MAXPATHLEN];
1397 size_t total;
1398
1399 size_t all_max = dst->all_max;
1400 if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
1401
1402 if (dst == NULL) return -1;
1403 if (dst->path == NULL) return -1;
1404
1405 if (all_max == 0) return 0;
1406
1407 dst_list = asl_list_dst_files(dst);
1408 if (dst_list == NULL)
1409 {
1410 debug_log(ASL_LEVEL_INFO, " no dst files\n");
1411 return 0;
1412 }
1413
1414 dst_dir = dst->rotate_dir;
1415 if (dst_dir == NULL) dst_dir = dst->dir;
1416
1417 debug_log(ASL_LEVEL_INFO, " dst files\n");
1418 dst_end = dst_list;
1419 for (f = dst_list; f != NULL; f = f->next)
1420 {
1421 dst_end = f;
1422 debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size);
1423 }
1424
1425 total = 0;
1426 for (f = dst_list; f != NULL; f = f->next) total += f->size;
1427
1428 if (!query)
1429 {
1430 for (f = dst_list; (total > all_max) && (f != NULL); f = f->next)
1431 {
1432 snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
1433 filesystem_unlink(fpath);
1434 total -= f->size;
1435 }
1436 }
1437
1438 if (msize != NULL) *msize = total;
1439
1440 asl_out_file_list_free(dst_list);
1441
1442 return 0;
1443 }
1444
1445 int
1446 process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
1447 {
1448 uint32_t ttl = dst->ttl[LEVEL_ALL];
1449 if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
1450
1451 size_t all_max = dst->all_max;
1452 if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
1453
1454 if (dst == NULL)
1455 {
1456 debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n");
1457 }
1458 else if (dst->flags & MODULE_FLAG_ROTATE)
1459 {
1460 debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", dst->path);
1461 debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n");
1462
1463 module_copy_rename(dst);
1464
1465 if ((ttl > 0) && !(dst->flags & MODULE_FLAG_SIZE_ONLY))
1466 {
1467 char tstr[150];
1468
1469 asl_core_time_to_str(ttl, tstr, sizeof(tstr));
1470 debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %s\n", tstr);
1471 module_expire(dst, opts);
1472 }
1473
1474 if (all_max > 0)
1475 {
1476 debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", all_max);
1477 module_check_size(dst, opts, false, NULL);
1478 }
1479 }
1480 else if ((dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (ttl > 0))
1481 {
1482 process_asl_data_store(dst, opts);
1483 }
1484
1485 return 0;
1486 }
1487
1488 int
1489 process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts)
1490 {
1491 asl_out_rule_t *r;
1492 uint32_t flags = 0;
1493
1494 if (mod == NULL) return -1;
1495
1496 if (opts != NULL) flags = opts->flags;
1497
1498 debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
1499 debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
1500
1501 for (r = mod->ruleset; r != NULL; r = r->next)
1502 {
1503 if (r->action == ACTION_OUT_DEST)
1504 {
1505 if ((flags == 0) || ((flags & r->dst->flags) != 0)) process_dst(r->dst, opts);
1506 }
1507 }
1508
1509 debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
1510 return 0;
1511 }
1512
1513 asl_msg_list_t *
1514 control_query(asl_msg_t *a)
1515 {
1516 asl_msg_list_t *out;
1517 char *qstr, *str, *res;
1518 uint32_t len, reslen, status;
1519 uint64_t cmax, qmin;
1520 kern_return_t kstatus;
1521 caddr_t vmstr;
1522
1523 if (asl_server_port == MACH_PORT_NULL)
1524 {
1525 kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
1526 if (asl_server_port == MACH_PORT_NULL) return NULL;
1527 }
1528
1529 qstr = asl_msg_to_string((asl_msg_t *)a, &len);
1530
1531 str = NULL;
1532 if (qstr == NULL)
1533 {
1534 asprintf(&str, "1\nQ [= ASLOption control]\n");
1535 }
1536 else
1537 {
1538 asprintf(&str, "1\n%s [= ASLOption control]\n", qstr);
1539 free(qstr);
1540 }
1541
1542 if (str == NULL) return NULL;
1543
1544 /* length includes trailing nul */
1545 len = strlen(str) + 1;
1546 out = NULL;
1547 qmin = 0;
1548 cmax = 0;
1549
1550 res = NULL;
1551 reslen = 0;
1552 status = ASL_STATUS_OK;
1553
1554 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1555 if (kstatus != KERN_SUCCESS) return NULL;
1556
1557 memmove(vmstr, str, len);
1558 free(str);
1559
1560 status = 0;
1561 kstatus = _asl_server_query_2(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1562 if (kstatus != KERN_SUCCESS) return NULL;
1563
1564 if (res == NULL) return NULL;
1565
1566 out = asl_msg_list_from_string(res);
1567 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1568
1569 return out;
1570 }
1571
1572 int
1573 checkpoint(const char *name)
1574 {
1575 /* send checkpoint message to syslogd */
1576 debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name);
1577 if (dryrun) return 0;
1578
1579 asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY);
1580 char *tmp = NULL;
1581 asl_msg_list_t *res;
1582
1583 asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name);
1584 asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL);
1585 free(tmp);
1586
1587 res = control_query(qmsg);
1588
1589 asl_msg_list_release(res);
1590 return 0;
1591 }