]> git.saurik.com Git - apple/syslog.git/blob - aslmanager.tproj/aslmanager.c
syslog-148.8.tar.gz
[apple/syslog.git] / aslmanager.tproj / aslmanager.c
1 /*
2 * Copyright (c) 2007-2009 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 <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>
34 #include <copyfile.h>
35 #include <asl.h>
36 #include <asl_private.h>
37 #include <asl_core.h>
38 #include <asl_file.h>
39 #include <asl_store.h>
40
41 #define SECONDS_PER_DAY 86400
42 #define DEFAULT_MAX_SIZE 150000000
43 #define DEFAULT_TTL 7
44
45 #define _PATH_ASL_CONF "/etc/asl.conf"
46
47 /* global */
48 static char *archive = NULL;
49 static char *store_dir = PATH_ASL_STORE;
50 static time_t ttl;
51 static size_t max_size;
52 static mode_t archive_mode = 0400;
53 static int debug;
54
55 typedef struct name_list_s
56 {
57 char *name;
58 size_t size;
59 struct name_list_s *next;
60 } name_list_t;
61
62 name_list_t *
63 add_to_list(name_list_t *l, const char *name, size_t size)
64 {
65 name_list_t *e, *x;
66
67 if (name == NULL) return l;
68
69 e = (name_list_t *)calloc(1, sizeof(name_list_t));
70 if (e == NULL) return NULL;
71
72 e->name = strdup(name);
73 if (e->name == NULL)
74 {
75 free(e);
76 return NULL;
77 }
78
79 e->size = size;
80
81 /* list is sorted by name (i.e. primarily by timestamp) */
82 if (l == NULL) return e;
83
84 if (strcmp(e->name, l->name) <= 0)
85 {
86 e->next = l;
87 return e;
88 }
89
90 for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next);
91
92 e->next = x->next;
93 x->next = e;
94 return l;
95 }
96
97 void
98 free_list(name_list_t *l)
99 {
100 name_list_t *e;
101
102 while (l != NULL)
103 {
104 e = l;
105 l = l->next;
106 free(e->name);
107 free(e);
108 }
109
110 free(l);
111 }
112
113 uint32_t
114 do_copy(const char *infile, const char *outfile, mode_t mode)
115 {
116 asl_search_result_t *res;
117 asl_file_t *f;
118 uint32_t status, i;
119 uint64_t mid;
120
121 if (infile == NULL) return ASL_STATUS_INVALID_ARG;
122 if (outfile == NULL) return ASL_STATUS_INVALID_ARG;
123
124 f = NULL;
125 status = asl_file_open_read(infile, &f);
126 if (status != ASL_STATUS_OK) return status;
127
128 res = NULL;
129 mid = 0;
130
131 status = asl_file_match(f, NULL, &res, &mid, 0, 0, 1);
132 asl_file_close(f);
133
134 if (status != ASL_STATUS_OK) return status;
135 if (res->count == 0)
136 {
137 aslresponse_free(res);
138 return ASL_STATUS_OK;
139 }
140
141 f = NULL;
142 status = asl_file_open_write(outfile, mode, -1, -1, &f);
143 if (status != ASL_STATUS_OK) return status;
144 if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED;
145
146 f->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID;
147
148 for (i = 0; i < res->count; i++)
149 {
150 mid = 0;
151 status = asl_file_save(f, (aslmsg)(res->msg[i]), &mid);
152 if (status != ASL_STATUS_OK) break;
153 }
154
155 asl_file_close(f);
156 return status;
157 }
158
159 int
160 do_dir_archive(const char *indir, const char *outdir)
161 {
162 return copyfile(indir, outdir, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
163 }
164
165 int
166 remove_directory(const char *path)
167 {
168 DIR *dp;
169 struct dirent *dent;
170 char *str;
171 int status;
172
173 dp = opendir(path);
174 if (dp == NULL) return 0;
175
176 while ((dent = readdir(dp)) != NULL)
177 {
178 if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
179 asprintf(&str, "%s/%s", path, dent->d_name);
180 if (str != NULL)
181 {
182 status = unlink(str);
183 free(str);
184 str = NULL;
185 }
186 }
187
188 closedir(dp);
189 status = rmdir(path);
190
191 return status;
192 }
193
194
195 static char **
196 _insertString(char *s, char **l, uint32_t x)
197 {
198 int i, len;
199
200 if (s == NULL) return l;
201 if (l == NULL)
202 {
203 l = (char **)malloc(2 * sizeof(char *));
204 if (l == NULL) return NULL;
205
206 l[0] = strdup(s);
207 if (l[0] == NULL)
208 {
209 free(l);
210 return NULL;
211 }
212
213 l[1] = NULL;
214 return l;
215 }
216
217 for (i = 0; l[i] != NULL; i++);
218 len = i + 1; /* count the NULL on the end of the list too! */
219
220 l = (char **)reallocf(l, (len + 1) * sizeof(char *));
221 if (l == NULL) return NULL;
222
223 if ((x >= (len - 1)) || (x == IndexNull))
224 {
225 l[len - 1] = strdup(s);
226 if (l[len - 1] == NULL)
227 {
228 free(l);
229 return NULL;
230 }
231
232 l[len] = NULL;
233 return l;
234 }
235
236 for (i = len; i > x; i--) l[i] = l[i - 1];
237 l[x] = strdup(s);
238 if (l[x] == NULL) return NULL;
239
240 return l;
241 }
242
243 char **
244 explode(const char *s, const char *delim)
245 {
246 char **l = NULL;
247 const char *p;
248 char *t, quote;
249 int i, n;
250
251 if (s == NULL) return NULL;
252
253 quote = '\0';
254
255 p = s;
256 while (p[0] != '\0')
257 {
258 /* scan forward */
259 for (i = 0; p[i] != '\0'; i++)
260 {
261 if (quote == '\0')
262 {
263 /* not inside a quoted string: check for delimiters and quotes */
264 if (strchr(delim, p[i]) != NULL) break;
265 else if (p[i] == '\'') quote = p[i];
266 else if (p[i] == '"') quote = p[i];
267 }
268 else
269 {
270 /* inside a quoted string - look for matching quote */
271 if (p[i] == quote) quote = '\0';
272 }
273 }
274
275 n = i;
276 t = malloc(n + 1);
277 if (t == NULL) return NULL;
278
279 for (i = 0; i < n; i++) t[i] = p[i];
280 t[n] = '\0';
281 l = _insertString(t, l, IndexNull);
282 free(t);
283 t = NULL;
284 if (p[i] == '\0') return l;
285 if (p[i + 1] == '\0') l = _insertString("", l, IndexNull);
286 p = p + i + 1;
287 }
288
289 return l;
290 }
291
292 void
293 freeList(char **l)
294 {
295 int i;
296
297 if (l == NULL) return;
298 for (i = 0; l[i] != NULL; i++) free(l[i]);
299 free(l);
300 }
301
302 /*
303 * Used to sed config parameters.
304 * Line format "= name value"
305 */
306 static void
307 _parse_set_param(char *s)
308 {
309 char **l;
310 uint32_t count;
311
312 if (s == NULL) return;
313 if (s[0] == '\0') return;
314
315 /* skip '=' and whitespace */
316 s++;
317 while ((*s == ' ') || (*s == '\t')) s++;
318
319 l = explode(s, " \t");
320 if (l == NULL) return;
321
322 for (count = 0; l[count] != NULL; count++);
323
324 /* name is required */
325 if (count == 0)
326 {
327 freeList(l);
328 return;
329 }
330
331 /* value is required */
332 if (count == 1)
333 {
334 freeList(l);
335 return;
336 }
337
338 if (!strcasecmp(l[0], "aslmanager_debug"))
339 {
340 /* = debug {0|1} */
341 debug = atoi(l[1]);
342 }
343 else if (!strcasecmp(l[0], "store_ttl"))
344 {
345 /* = store_ttl days */
346 ttl = SECONDS_PER_DAY * (time_t)atoll(l[1]);
347 }
348 else if (!strcasecmp(l[0], "max_store_size"))
349 {
350 /* = max_file_size bytes */
351 max_size = atoi(l[1]);
352 }
353 else if (!strcasecmp(l[0], "archive"))
354 {
355 /* = archive {0|1} path */
356 if (!strcmp(l[1], "1"))
357 {
358 if (l[2] == NULL) archive = PATH_ASL_ARCHIVE;
359 else archive = strdup(l[2]); /* never freed */
360 }
361 else archive = NULL;
362 }
363 else if (!strcasecmp(l[0], "store_path"))
364 {
365 /* = archive path */
366 store_dir = strdup(l[1]); /* never freed */
367 }
368 else if (!strcasecmp(l[0], "archive_mode"))
369 {
370 archive_mode = strtol(l[1], NULL, 0);
371 if ((archive_mode == 0) && (errno == EINVAL)) archive_mode = 0400;
372 }
373
374 freeList(l);
375 }
376
377 static void
378 _parse_line(char *s)
379 {
380 if (s == NULL) return;
381 while ((*s == ' ') || (*s == '\t')) s++;
382
383 /*
384 * First non-whitespace char is the rule type.
385 * aslmanager only checks "=" (set parameter) rules.
386 */
387 if (*s == '=') _parse_set_param(s);
388 }
389
390 char *
391 get_line_from_file(FILE *f)
392 {
393 char *s, *out;
394 size_t len;
395
396 out = fgetln(f, &len);
397 if (out == NULL) return NULL;
398 if (len == 0) return NULL;
399
400 s = malloc(len + 1);
401 if (s == NULL) return NULL;
402
403 memcpy(s, out, len);
404
405 if (s[len - 1] != '\n') len++;
406 s[len - 1] = '\0';
407 return s;
408 }
409
410 static int
411 _parse_config_file(const char *name)
412 {
413 FILE *cf;
414 char *line;
415
416 cf = fopen(name, "r");
417 if (cf == NULL) return 1;
418
419 while (NULL != (line = get_line_from_file(cf)))
420 {
421 _parse_line(line);
422 free(line);
423 }
424
425 fclose(cf);
426
427 return 0;
428 }
429
430 size_t
431 directory_size(const char *path)
432 {
433 DIR *dp;
434 struct dirent *dent;
435 struct stat sb;
436 size_t size;
437 char *str;
438
439 dp = opendir(path);
440 if (dp == NULL) return 0;
441
442 size = 0;
443 while ((dent = readdir(dp)) != NULL)
444 {
445 if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
446
447 memset(&sb, 0, sizeof(struct stat));
448 str = NULL;
449 asprintf(&str, "%s/%s", path, dent->d_name);
450
451 if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
452 {
453 size += sb.st_size;
454 free(str);
455 }
456 }
457
458 closedir(dp);
459 return size;
460 }
461
462 int
463 main(int argc, const char *argv[])
464 {
465 int i, today_ymd_stringlen, expire_ymd_stringlen;
466 time_t now, ymd_expire;
467 struct tm ctm;
468 char today_ymd_string[32], expire_ymd_string[32], *str;
469 DIR *dp;
470 struct dirent *dent;
471 name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e;
472 uint32_t status;
473 size_t file_size, store_size;
474 struct stat sb;
475
476 ymd_list = NULL;
477 bb_list = NULL;
478 aux_list = NULL;
479 bb_aux_list = NULL;
480
481 ttl = DEFAULT_TTL * SECONDS_PER_DAY;
482 max_size = DEFAULT_MAX_SIZE;
483 store_size = 0;
484 debug = 0;
485
486 for (i = 1; i < argc; i++)
487 {
488 if (!strcmp(argv[i], "-a"))
489 {
490 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) archive = (char *)argv[++i];
491 else archive = PATH_ASL_ARCHIVE;
492 }
493 else if (!strcmp(argv[i], "-s"))
494 {
495 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store_dir = (char *)argv[++i];
496 }
497 else if (!strcmp(argv[i], "-ttl"))
498 {
499 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) ttl = atoi(argv[++i]) * SECONDS_PER_DAY;
500 }
501 else if (!strcmp(argv[i], "-size"))
502 {
503 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) max_size = atoi(argv[++i]);
504 }
505 else if (!strcmp(argv[i], "-d"))
506 {
507 debug = 1;
508 }
509 }
510
511 _parse_config_file(_PATH_ASL_CONF);
512
513 if (debug == 1) printf("aslmanager starting\n");
514
515 /* check archive */
516 if (archive != NULL)
517 {
518 memset(&sb, 0, sizeof(struct stat));
519 if (stat(archive, &sb) == 0)
520 {
521 /* must be a directory */
522 if (!S_ISDIR(sb.st_mode))
523 {
524 fprintf(stderr, "aslmanager error: archive %s is not a directory", archive);
525 return -1;
526 }
527 }
528 else
529 {
530 if (errno == ENOENT)
531 {
532 /* archive doesn't exist - create it */
533 if (mkdir(archive, 0755) != 0)
534 {
535 fprintf(stderr, "aslmanager error: can't create archive %s: %s\n", archive, strerror(errno));
536 return -1;
537 }
538 }
539 else
540 {
541 /* stat failed for some other reason */
542 fprintf(stderr, "aslmanager error: can't stat archive %s: %s\n", archive, strerror(errno));
543 return -1;
544 }
545 }
546 }
547
548 chdir(store_dir);
549
550 /* determine current time */
551 now = time(NULL);
552
553 /* ttl 0 means files never expire */
554 ymd_expire = 0;
555 if (ttl > 0) ymd_expire = now - ttl;
556
557 /* construct today's date as YYYY.MM.DD */
558 memset(&ctm, 0, sizeof(struct tm));
559 if (localtime_r((const time_t *)&now, &ctm) == NULL) return -1;
560
561 snprintf(today_ymd_string, sizeof(today_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
562 today_ymd_stringlen = strlen(today_ymd_string);
563
564 /* construct regular file expiry date as YYYY.MM.DD */
565 memset(&ctm, 0, sizeof(struct tm));
566 if (localtime_r((const time_t *)&ymd_expire, &ctm) == NULL) return -1;
567
568 snprintf(expire_ymd_string, sizeof(expire_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
569 expire_ymd_stringlen = strlen(expire_ymd_string);
570
571 if (debug == 1) printf("Expiry Date %s\n", expire_ymd_string);
572
573 dp = opendir(store_dir);
574 if (dp == NULL) return -1;
575
576 /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */
577 while ((dent = readdir(dp)) != NULL)
578 {
579 memset(&sb, 0, sizeof(struct stat));
580 file_size = 0;
581 if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size;
582
583 if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9'))
584 {
585 ymd_list = add_to_list(ymd_list, dent->d_name, file_size);
586 store_size += file_size;
587 }
588 else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
589 {
590 file_size = directory_size(dent->d_name);
591 aux_list = add_to_list(aux_list, dent->d_name, file_size);
592 store_size += file_size;
593 }
594 else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
595 {
596 file_size = directory_size(dent->d_name);
597 bb_aux_list = add_to_list(bb_aux_list, dent->d_name, file_size);
598 store_size += file_size;
599 }
600 else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
601 {
602 bb_list = add_to_list(bb_list, dent->d_name, file_size);
603 store_size += file_size;
604 }
605 else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
606 {}
607 else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
608 {}
609 else
610 {
611 fprintf(stderr, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
612 }
613 }
614
615 closedir(dp);
616
617 if (debug == 1)
618 {
619 printf("Data Store Size = %lu\n", store_size);
620 printf("Data Store YMD Files\n");
621 for (e = ymd_list; e != NULL; e = e->next) printf(" %s %lu\n", e->name, e->size);
622 printf("Data Store AUX Directories\n");
623 for (e = aux_list; e != NULL; e = e->next) printf(" %s %lu\n", e->name, e->size);
624 printf("Data Store BB.AUX Directories\n");
625 for (e = bb_aux_list; e != NULL; e = e->next) printf(" %s %lu\n", e->name, e->size);
626 printf("Data Store BB Files\n");
627 for (e = bb_list; e != NULL; e = e->next) printf(" %s %lu\n", e->name, e->size);
628 }
629
630 /* Delete/achive expired YMD files */
631 if (debug == 1) printf("Start YMD File Scan\n");
632
633 e = ymd_list;
634 while (e != NULL)
635 {
636 /* stop when a file name/date is after the expire date */
637 if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) > 0) break;
638
639 if (archive != NULL)
640 {
641 str = NULL;
642 asprintf(&str, "%s/%s", archive, e->name);
643 if (str == NULL) return -1;
644
645 if (debug == 1) printf(" copy %s ---> %s\n", e->name, str);
646 status = do_copy(e->name, str, archive_mode);
647 free(str);
648 }
649
650 if (debug == 1) printf(" unlink %s\n", e->name);
651 unlink(e->name);
652
653 store_size -= e->size;
654 e->size = 0;
655
656 e = e->next;
657 }
658
659 if (debug == 1) printf("Finished YMD FILE Scan\n");
660
661 /* Delete/achive expired YMD AUX directories */
662 if (debug == 1) printf("Start AUX Directory Scan\n");
663
664 e = aux_list;
665 while (e != NULL)
666 {
667 /* stop when a file name/date is after the expire date */
668 if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break;
669
670 if (archive != NULL)
671 {
672 str = NULL;
673 asprintf(&str, "%s/%s", archive, e->name);
674 if (str == NULL) return -1;
675
676 if (debug == 1) printf(" copy %s ---> %s\n", e->name, str);
677 do_dir_archive(e->name, str);
678 free(str);
679 }
680
681 if (debug == 1) printf(" Remove %s\n", e->name);
682 remove_directory(e->name);
683
684 store_size -= e->size;
685 e->size = 0;
686
687 e = e->next;
688 }
689
690 if (debug == 1) printf("Finished AUX Directory Scan\n");
691
692 /* Delete/achive expired BB.AUX directories */
693 if (debug == 1) printf("Start BB.AUX Directory Scan\n");
694
695 e = bb_aux_list;
696 while (e != NULL)
697 {
698 /* stop when a file name/date is after the expire date */
699 if (strncmp(e->name + 7, today_ymd_string, today_ymd_stringlen) > 0) break;
700
701 if (archive != NULL)
702 {
703 str = NULL;
704 asprintf(&str, "%s/%s", archive, e->name);
705 if (str == NULL) return -1;
706
707 if (debug == 1) printf(" copy %s ---> %s\n", e->name, str);
708 do_dir_archive(e->name, str);
709 free(str);
710 }
711
712 if (debug == 1) printf(" remove %s\n", e->name);
713 remove_directory(e->name);
714
715 store_size -= e->size;
716 e->size = 0;
717
718 e = e->next;
719 }
720
721 if (debug == 1) printf("Finished BB.AUX Directory Scan\n");
722
723 /* Delete/achive expired BB files */
724 if (debug == 1) printf("Start BB Scan\n");
725
726 e = bb_list;
727 while (e != NULL)
728 {
729 /* stop when a file name/date is after the expire date */
730 if (strncmp(e->name + 3, today_ymd_string, today_ymd_stringlen) > 0) break;
731
732 if (archive != NULL)
733 {
734 str = NULL;
735 asprintf(&str, "%s/%s", archive, e->name);
736 if (str == NULL) return -1;
737
738 /* syslog -x [str] -f [e->name] */
739 if (debug == 1) printf(" copy %s ---> %s\n", e->name, str);
740 status = do_copy(e->name, str, archive_mode);
741 free(str);
742 }
743
744 if (debug == 1) printf(" unlink %s\n", e->name);
745 unlink(e->name);
746
747 store_size -= e->size;
748 e->size = 0;
749
750 e = e->next;
751 }
752
753 if (debug == 1) printf("Finished BB Scan\n");
754
755 /* if data store is over max_size, delete/archive more YMD files */
756 if ((debug == 1) && (store_size > max_size)) printf("Additional YMD Scan\n");
757
758 e = ymd_list;
759 while ((e != NULL) && (store_size > max_size))
760 {
761 if (e->size != 0)
762 {
763 /* stop when we get to today's files */
764 if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0) break;
765
766 if (archive != NULL)
767 {
768 str = NULL;
769 asprintf(&str, "%s/%s", archive, e->name);
770 if (str == NULL) return -1;
771
772 /* syslog -x [str] -f [e->name] */
773 if (debug == 1) printf(" copy %s ---> %s\n", e->name, str);
774 status = do_copy(e->name, str, archive_mode);
775 free(str);
776 }
777
778 if (debug == 1) printf(" unlink %s\n", e->name);
779 unlink(e->name);
780
781 store_size -= e->size;
782 e->size = 0;
783 }
784
785 e = e->next;
786 }
787
788 /* if data store is over max_size, delete/archive more BB files */
789 if ((debug == 1) && (store_size > max_size)) printf("Additional BB Scan\n");
790
791 e = bb_list;
792 while ((e != NULL) && (store_size > max_size))
793 {
794 if (e->size != 0)
795 {
796 if (archive != NULL)
797 {
798 str = NULL;
799 asprintf(&str, "%s/%s", archive, e->name);
800 if (str == NULL) return -1;
801
802 /* syslog -x [str] -f [e->name] */
803 if (debug == 1) printf(" copy %s ---> %s\n", e->name, str);
804 status = do_copy(e->name, str, archive_mode);
805 free(str);
806 }
807
808 if (debug == 1) printf(" unlink %s\n", e->name);
809 unlink(e->name);
810
811 store_size -= e->size;
812 e->size = 0;
813 }
814
815 e = e->next;
816 }
817
818 free_list(ymd_list);
819 free_list(bb_list);
820
821 if (debug == 1)
822 {
823 printf("Data Store Size = %lu\n", store_size);
824 printf("aslmanager finished\n");
825 }
826
827 return 0;
828 }
829