]>
git.saurik.com Git - apple/syslog.git/blob - aslcommon/asl_common.c
a4c21d36bd8e5e8a64634f2d6ccfa8003d582896
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
34 #include <sys/param.h>
37 #include <membership.h>
39 #include <TargetConditionals.h>
40 #include <configuration_profile.h>
43 #include "asl_common.h"
45 #define _PATH_ASL_CONF "/etc/asl.conf"
46 #define _PATH_ASL_CONF_DIR "/etc/asl"
48 #if !TARGET_IPHONE_SIMULATOR
49 #define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl"
52 static const char *asl_out_action_name
[] =
74 static time_t start_today
;
76 extern asl_msg_t
*asl_msg_from_string(const char *buf
);
78 #define forever for(;;)
79 #define KEYMATCH(S,K) ((strncasecmp(S, K, strlen(K)) == 0))
82 xpc_object_to_asl_msg(xpc_object_t xobj
)
84 __block asl_msg_t
*out
;
86 if (xobj
== NULL
) return NULL
;
87 if (xpc_get_type(xobj
) != XPC_TYPE_DICTIONARY
) return NULL
;
89 out
= asl_msg_new(ASL_TYPE_MSG
);
90 xpc_dictionary_apply(xobj
, ^bool(const char *key
, xpc_object_t xval
) {
93 if (xpc_get_type(xval
) == XPC_TYPE_NULL
)
95 asl_msg_set_key_val_op(out
, key
, NULL
, 0);
97 else if (xpc_get_type(xval
) == XPC_TYPE_BOOL
)
99 if (xpc_bool_get_value(xval
)) asl_msg_set_key_val_op(out
, key
, "1", 0);
100 else asl_msg_set_key_val_op(out
, key
, "0", 0);
102 else if (xpc_get_type(xval
) == XPC_TYPE_INT64
)
104 snprintf(tmp
, sizeof(tmp
), "%lld", xpc_int64_get_value(xval
));
105 asl_msg_set_key_val_op(out
, key
, tmp
, 0);
107 else if (xpc_get_type(xval
) == XPC_TYPE_UINT64
)
109 snprintf(tmp
, sizeof(tmp
), "%llu", xpc_uint64_get_value(xval
));
110 asl_msg_set_key_val_op(out
, key
, tmp
, 0);
112 else if (xpc_get_type(xval
) == XPC_TYPE_DOUBLE
)
114 snprintf(tmp
, sizeof(tmp
), "%f", xpc_double_get_value(xval
));
115 asl_msg_set_key_val_op(out
, key
, tmp
, 0);
117 else if (xpc_get_type(xval
) == XPC_TYPE_DATE
)
119 snprintf(tmp
, sizeof(tmp
), "%lld", xpc_date_get_value(xval
));
120 asl_msg_set_key_val_op(out
, key
, tmp
, 0);
122 else if (xpc_get_type(xval
) == XPC_TYPE_DATA
)
124 size_t len
= xpc_data_get_length(xval
);
125 char *encoded
= asl_core_encode_buffer(xpc_data_get_bytes_ptr(xval
), len
);
126 asl_msg_set_key_val_op(out
, key
, encoded
, 0);
129 else if (xpc_get_type(xval
) == XPC_TYPE_STRING
)
131 asl_msg_set_key_val_op(out
, key
, xpc_string_get_string_ptr(xval
), 0);
133 else if (xpc_get_type(xval
) == XPC_TYPE_UUID
)
136 uuid_unparse(xpc_uuid_get_bytes(xval
), us
);
137 asl_msg_set_key_val_op(out
, key
, us
, 0);
139 else if (xpc_get_type(xval
) == XPC_TYPE_FD
)
141 /* XPC_TYPE_FD is not supported */
142 asl_msg_set_key_val_op(out
, key
, "{XPC_TYPE_FD}", 0);
144 else if (xpc_get_type(xval
) == XPC_TYPE_SHMEM
)
146 /* XPC_TYPE_SHMEM is not supported */
147 asl_msg_set_key_val_op(out
, key
, "{XPC_TYPE_SHMEM}", 0);
149 else if (xpc_get_type(xval
) == XPC_TYPE_ARRAY
)
151 /* XPC_TYPE_ARRAY is not supported */
152 asl_msg_set_key_val_op(out
, key
, "{XPC_TYPE_ARRAY}", 0);
154 else if (xpc_get_type(xval
) == XPC_TYPE_DICTIONARY
)
156 /* XPC_TYPE_DICTIONARY is not supported */
157 asl_msg_set_key_val_op(out
, key
, "{XPC_TYPE_DICTIONARY}", 0);
159 else if (xpc_get_type(xval
) == XPC_TYPE_ERROR
)
161 /* XPC_TYPE_ERROR is not supported */
162 asl_msg_set_key_val_op(out
, key
, "{XPC_TYPE_ERROR}", 0);
167 asl_msg_set_key_val_op(out
, key
, "{XPC_TYPE_???}", 0);
177 configuration_profile_to_asl_msg(const char *ident
)
179 xpc_object_t xobj
= configuration_profile_copy_property_list(ident
);
180 asl_msg_t
*out
= xpc_object_to_asl_msg(xobj
);
181 if (xobj
!= NULL
) xpc_release(xobj
);
185 /* strdup + skip leading and trailing whitespace */
187 _strdup_clean(const char *s
)
190 const char *first
, *last
;
193 if (s
== NULL
) return NULL
;
196 while ((*first
== ' ') || (*first
== '\t')) first
++;
198 if (len
== 0) return NULL
;
200 last
= first
+ len
- 1;
201 while ((len
> 0) && ((*last
== ' ') || (*last
== '\t')))
207 if (len
== 0) return NULL
;
209 out
= malloc(len
+ 1);
210 if (out
== NULL
) return NULL
;
212 memcpy(out
, first
, len
);
218 _insert_string(char *s
, char **l
, uint32_t x
)
222 if (s
== NULL
) return l
;
225 l
= (char **)malloc(2 * sizeof(char *));
226 if (l
== NULL
) return NULL
;
239 for (i
= 0; l
[i
] != NULL
; i
++);
241 /* len includes the NULL at the end of the list */
244 l
= (char **)reallocf(l
, (len
+ 1) * sizeof(char *));
245 if (l
== NULL
) return NULL
;
247 if ((x
>= (len
- 1)) || (x
== IndexNull
))
249 l
[len
- 1] = strdup(s
);
250 if (l
[len
- 1] == NULL
)
260 for (i
= len
; i
> x
; i
--) l
[i
] = l
[i
- 1];
262 if (l
[x
] == NULL
) return NULL
;
268 explode(const char *s
, const char *delim
)
275 if (s
== NULL
) return NULL
;
283 for (i
= 0; p
[i
] != '\0'; i
++)
287 /* not inside a quoted string: check for delimiters and quotes */
288 if (strchr(delim
, p
[i
]) != NULL
) break;
289 else if (p
[i
] == '\'') quote
= p
[i
];
290 else if (p
[i
] == '"') quote
= p
[i
];
294 /* inside a quoted string - look for matching quote */
295 if (p
[i
] == quote
) quote
= '\0';
301 if (t
== NULL
) return NULL
;
303 for (i
= 0; i
< n
; i
++) t
[i
] = p
[i
];
305 l
= _insert_string(t
, l
, IndexNull
);
308 if (p
[i
] == '\0') return l
;
309 if (p
[i
+ 1] == '\0') l
= _insert_string("", l
, IndexNull
);
317 free_string_list(char **l
)
321 if (l
== NULL
) return;
322 for (i
= 0; l
[i
] != NULL
; i
++) free(l
[i
]);
327 get_line_from_file(FILE *f
)
332 out
= fgetln(f
, &len
);
333 if (out
== NULL
) return NULL
;
334 if (len
== 0) return NULL
;
337 if (s
== NULL
) return NULL
;
341 if (s
[len
- 1] != '\n') len
++;
347 next_word_from_string(char **s
)
349 char *a
, *p
, *e
, *out
, s0
;
350 int quote1
, quote2
, len
;
352 if (s
== NULL
) return NULL
;
353 if (*s
== NULL
) return NULL
;
362 /* allow whole word to be contained in quotes */
398 if (quote1
== 0) quote1
= 1;
404 if (quote2
== 0) quote2
= 1;
408 if (((*p
== ' ') || (*p
== '\t')) && (quote1
== 0) && (quote2
== 0))
422 /* check for quoted string */
423 if (((s0
== '\'') || (s0
== '"')) && (s0
== a
[len
-1])) len
--;
425 if (len
== 0) return NULL
;
427 out
= malloc(len
+ 1);
428 if (out
== NULL
) return NULL
;
436 asl_out_mkpath(asl_out_rule_t
*r
)
438 char tmp
[MAXPATHLEN
], *p
;
442 if (r
== NULL
) return -1;
443 if (r
->dst
== NULL
) return -1;
444 if (r
->dst
->path
== NULL
) return -1;
446 snprintf(tmp
, sizeof(tmp
), "%s", r
->dst
->path
);
448 if (r
->action
!= ACTION_ASL_DIR
)
450 p
= strrchr(tmp
, '/');
451 if (p
== NULL
) return -1;
455 memset(&sb
, 0, sizeof(struct stat
));
456 status
= stat(tmp
, &sb
);
459 if (!S_ISDIR(sb
.st_mode
)) return -1;
461 else if (errno
== ENOENT
)
463 status
= mkpath_np(tmp
, 0755);
470 asl_make_timestamp(time_t stamp
, uint32_t flags
, char *buf
, size_t len
)
475 if (buf
== NULL
) return;
477 if (flags
& MODULE_FLAG_STYLE_UTC
)
479 memset(&t
, 0, sizeof(t
));
480 gmtime_r(&stamp
, &t
);
481 snprintf(buf
, len
, "%d-%02d-%02dT%02d:%02d:%02dZ", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
);
483 else if (flags
& MODULE_FLAG_STYLE_UTC_B
)
485 memset(&t
, 0, sizeof(t
));
486 gmtime_r(&stamp
, &t
);
487 snprintf(buf
, len
, "%d%02d%02dT%02d%02d%02dZ", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
);
489 else if (flags
& MODULE_FLAG_STYLE_LCL
)
492 memset(&t
, 0, sizeof(t
));
493 localtime_r(&stamp
, &t
);
495 if ((neg
= (t
.tm_gmtoff
< 0))) t
.tm_gmtoff
*= -1;
503 if (s
> 0) snprintf(buf
, len
, "%d-%02d-%02dT%02d:%02d:%02d%c%u:%02u:%02u", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
, neg
? '-' : '+', h
, m
, s
);
504 else if (m
> 0) snprintf(buf
, len
, "%d-%02d-%02dT%02d:%02d:%02d%c%u:%02u", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
, neg
? '-' : '+', h
, m
);
505 else snprintf(buf
, len
, "%d-%02d-%02dT%02d:%02d:%02d%c%u", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
, neg
? '-' : '+', h
);
507 else if (flags
& MODULE_FLAG_STYLE_LCL_B
)
510 memset(&t
, 0, sizeof(t
));
511 localtime_r(&stamp
, &t
);
513 if ((neg
= (t
.tm_gmtoff
< 0))) t
.tm_gmtoff
*= -1;
521 if (s
> 0) snprintf(buf
, len
, "%d%02d%02dT%02d%02d%02d%c%02u%02u%02u", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
, neg
? '-' : '+', h
, m
, s
);
522 else if (m
> 0) snprintf(buf
, len
, "%d%02d%02dT%02d%02d%02d%c%02u%02u", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
, neg
? '-' : '+', h
, m
);
523 else snprintf(buf
, len
, "%d%02d%02dT%02d%02d%02d%c%02u", t
.tm_year
+ 1900, t
.tm_mon
+ 1, t
.tm_mday
, t
.tm_hour
, t
.tm_min
, t
.tm_sec
, neg
? '-' : '+', h
);
527 snprintf(buf
, len
, "%c%lu", STYLE_SEC_PREFIX_CHAR
, stamp
);
532 asl_make_dst_filename(asl_out_dst_data_t
*dst
, char *buf
, size_t len
)
534 if (dst
== NULL
) return;
535 if (buf
== NULL
) return;
537 if (dst
->flags
& MODULE_FLAG_BASESTAMP
)
541 if (dst
->stamp
== 0) dst
->stamp
= time(NULL
);
542 asl_make_timestamp(dst
->stamp
, dst
->flags
, tstamp
, sizeof(tstamp
));
543 snprintf(buf
, len
, "%s.%s", dst
->path
, tstamp
);
547 snprintf(buf
, len
, "%s", dst
->path
);
552 asl_out_dst_checkpoint(asl_out_dst_data_t
*dst
, uint32_t force
)
554 char newpath
[MAXPATHLEN
];
559 /* clock went backwards - force a reset */
560 if (now
< start_today
) start_today
= 0;
562 /* check start_today and reset if required */
563 if (now
>= (start_today
+ SECONDS_PER_DAY
))
565 /* use localtime / mktime since start_today might be zero */
570 localtime_r(&start_today
, &t
);
576 start_today
= mktime(&t
);
579 /* sleep to prevent a sub-second rotation */
580 while (now
== dst
->stamp
)
586 if ((dst
->stamp
== 0) || (dst
->size
== 0))
590 memset(&sb
, 0, sizeof(struct stat
));
592 if (stat(dst
->path
, &sb
) < 0)
594 if (errno
== ENOENT
) return 0;
598 if (dst
->stamp
== 0) dst
->stamp
= sb
.st_birthtimespec
.tv_sec
;
599 if (dst
->stamp
== 0) dst
->stamp
= sb
.st_mtimespec
.tv_sec
;
600 dst
->size
= sb
.st_size
;
603 if (force
== CHECKPOINT_TEST
)
605 if ((dst
->file_max
> 0) && (dst
->size
>= dst
->file_max
)) force
|= CHECKPOINT_SIZE
;
606 if (dst
->stamp
< start_today
) force
|= CHECKPOINT_TIME
;
608 if (force
== CHECKPOINT_TEST
) return 0;
611 if (dst
->flags
& MODULE_FLAG_TYPE_ASL_DIR
)
613 if (force
& CHECKPOINT_SIZE
)
615 snprintf(newpath
, sizeof(newpath
), "%s.%c%lu", dst
->fname
, STYLE_SEC_PREFIX_CHAR
, dst
->stamp
);
616 rename(dst
->fname
, newpath
);
624 if ((dst
->flags
& MODULE_FLAG_BASESTAMP
) == 0)
628 asl_make_timestamp(dst
->stamp
, dst
->flags
, tstamp
, sizeof(tstamp
));
629 snprintf(newpath
, sizeof(newpath
), "%s.%s", dst
->path
, tstamp
);
630 rename(dst
->path
, newpath
);
640 asl_check_option(aslmsg msg
, const char *opt
)
645 if (msg
== NULL
) return 0;
646 if (opt
== NULL
) return 0;
649 if (len
== 0) return 0;
651 p
= asl_get(msg
, ASL_KEY_OPTION
);
652 if (p
== NULL
) return 0;
656 while ((*p
== ' ') || (*p
== '\t') || (*p
== ',')) p
++;
657 if (*p
== '\0') return 0;
659 if (strncasecmp(p
, opt
, len
) == 0)
662 if ((*p
== ' ') || (*p
== '\t') || (*p
== ',') || (*p
== '\0')) return 1;
665 while ((*p
!= ' ') && (*p
!= '\t') && (*p
!= ',') && (*p
!= '\0')) p
++;
672 asl_out_dst_data_release(asl_out_dst_data_t
*dst
)
674 if (dst
== NULL
) return;
676 if (dst
->refcount
> 0) dst
->refcount
--;
677 if (dst
->refcount
> 0) return;
681 free(dst
->rotate_dir
);
683 #if !TARGET_IPHONE_SIMULATOR
691 asl_out_dst_data_retain(asl_out_dst_data_t
*dst
)
693 if (dst
== NULL
) return NULL
;
698 /* set owner, group, mode, and acls for a file */
700 asl_out_dst_set_access(int fd
, asl_out_dst_data_t
*dst
)
702 #if !TARGET_IPHONE_SIMULATOR
705 #if !TARGET_OS_EMBEDDED
715 if (dst
== NULL
) return -1;
716 if (fd
< 0) return -1;
718 #if TARGET_IPHONE_SIMULATOR
722 if (dst
->nuid
> 0) fuid
= dst
->uid
[0];
723 if (dst
->ngid
> 0) fgid
= dst
->gid
[0];
725 fchown(fd
, fuid
, fgid
);
727 #if TARGET_OS_EMBEDDED
732 for (i
= 0; i
< dst
->ngid
; i
++)
734 if (dst
->gid
[i
] == -2) continue;
737 * Don't bother setting group access if this is
738 * file's group and the file is group-readable.
740 if ((dst
->gid
[i
] == fgid
) && (dst
->mode
& 0040)) continue;
742 status
= mbr_gid_to_uuid(dst
->gid
[i
], uuid
);
749 status
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
);
750 if (status
!= 0) goto asl_file_create_return
;
752 status
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
);
753 if (status
!= 0) goto asl_file_create_return
;
755 status
= acl_set_qualifier(entry
, &uuid
);
756 if (status
!= 0) goto asl_file_create_return
;
758 status
= acl_get_permset(entry
, &perms
);
759 if (status
!= 0) goto asl_file_create_return
;
761 status
= acl_add_perm(perms
, ACL_READ_DATA
);
762 if (status
!= 0) goto asl_file_create_return
;
765 for (i
= 0; i
< dst
->nuid
; i
++)
767 if (dst
->uid
[i
] == -2) continue;
770 * Don't bother setting user access if this is
771 * file's owner and the file is owner-readable.
773 if ((dst
->uid
[i
] == fuid
) && (dst
->mode
& 0400)) continue;
775 status
= mbr_uid_to_uuid(dst
->uid
[i
], uuid
);
782 status
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
);
783 if (status
!= 0) goto asl_file_create_return
;
785 status
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
);
786 if (status
!= 0) goto asl_file_create_return
;
788 status
= acl_set_qualifier(entry
, &uuid
);
789 if (status
!= 0) goto asl_file_create_return
;
791 status
= acl_get_permset(entry
, &perms
);
792 if (status
!= 0) goto asl_file_create_return
;
794 status
= acl_add_perm(perms
, ACL_READ_DATA
);
795 if (status
!= 0) goto asl_file_create_return
;
798 status
= acl_set_fd(fd
, acl
);
805 asl_file_create_return
:
809 #endif /* !TARGET_OS_EMBEDDED */
810 #endif /* !TARGET_IPHONE_SIMULATOR */
813 /* create a file with acls */
815 asl_out_dst_file_create_open(asl_out_dst_data_t
*dst
)
819 char outpath
[MAXPATHLEN
];
821 if (dst
== NULL
) return -1;
822 if (dst
->path
== NULL
) return -1;
824 asl_make_dst_filename(dst
, outpath
, sizeof(outpath
));
826 memset(&sb
, 0, sizeof(struct stat
));
827 status
= stat(outpath
, &sb
);
830 /* must be a regular file */
831 if (!S_ISREG(sb
.st_mode
)) return -1;
834 fd
= open(outpath
, O_RDWR
| O_APPEND
| O_EXCL
, 0);
836 if (dst
->stamp
== 0) dst
->stamp
= sb
.st_birthtimespec
.tv_sec
;
837 if (dst
->stamp
== 0) dst
->stamp
= sb
.st_mtimespec
.tv_sec
;
838 dst
->size
= sb
.st_size
;
842 else if (errno
!= ENOENT
)
844 /* stat error other than non-existant file */
848 fd
= open(outpath
, O_RDWR
| O_CREAT
| O_EXCL
, (dst
->mode
& 0666));
849 if (fd
< 0) return -1;
851 dst
->stamp
= time(NULL
);
853 fd
= asl_out_dst_set_access(fd
, dst
);
854 if (fd
< 0) unlink(outpath
);
860 asl_out_module_free(asl_out_module_t
*m
)
862 asl_out_rule_t
*r
, *n
;
877 if (r
->dst
!= NULL
) asl_out_dst_data_release(r
->dst
);
879 if (r
->query
!= NULL
) asl_msg_release(r
->query
);
891 asl_out_module_new(const char *name
)
893 asl_out_module_t
*out
= (asl_out_module_t
*)calloc(1, sizeof(asl_out_module_t
));
895 if (out
== NULL
) return NULL
;
896 if (name
== NULL
) return NULL
;
898 out
->name
= strdup(name
);
899 if (out
->name
== NULL
)
905 out
->flags
= MODULE_FLAG_ENABLED
;
910 /* Skip over query */
912 _asl_out_module_find_action(char *s
)
917 if (p
== NULL
) return NULL
;
919 /* Skip command character (?, Q, *, or =) */
925 while ((*p
== ' ') || (*p
== '\t')) p
++;
927 if (*p
== '\0') return NULL
;
928 if (*p
!= '[') return p
;
930 /* skip to closing ] */
944 /* skip whitespace */
945 while ((*p
== ' ') || (*p
== '\t')) p
++;
951 * Parse parameter setting line
954 * evaluated once when module is initialized
956 * = [query] param options
957 * evaluated for each message, param set if message matches query
959 * = param [File path]
960 * evaluated once when module is initialized
961 * evaluated when change notification received for path
963 * = param [Plist path] ...
964 * evaluated once when module is initialized
965 * evaluated when change notification received for path
967 * = param [Profile name] ...
968 * evaluated once when module is initialized
969 * evaluated when change notification received for profile
971 static asl_out_rule_t
*
972 _asl_out_module_parse_set_param(asl_out_module_t
*m
, char *s
)
975 asl_out_rule_t
*out
, *rule
;
977 if (m
== NULL
) return NULL
;
979 out
= (asl_out_rule_t
*)calloc(1, sizeof(asl_out_rule_t
));
980 if (out
== NULL
) return NULL
;
983 while ((*q
== ' ') || (*q
== '\'')) q
++;
984 out
->action
= ACTION_SET_PARAM
;
988 /* = [query] param options */
989 act
= _asl_out_module_find_action(s
);
996 out
->options
= _strdup_clean(act
);
999 if (*p
== ']') p
= act
;
1003 out
->query
= asl_msg_from_string(s
);
1004 if (out
->query
== NULL
)
1017 /* = param options */
1018 out
->options
= _strdup_clean(q
);
1022 /* = param [query] */
1023 if ((!strncmp(p
, "[File ", 6)) || (!strncmp(p
, "[File\t", 6))) out
->action
= ACTION_SET_FILE
;
1024 else if ((!strncmp(p
, "[Plist ", 7)) || (!strncmp(p
, "[Plist\t", 7))) out
->action
= ACTION_SET_PLIST
;
1025 else if ((!strncmp(p
, "[Profile ", 9)) || (!strncmp(p
, "[Profile\t", 9))) out
->action
= ACTION_SET_PROF
;
1029 out
->options
= _strdup_clean(q
);
1034 out
->query
= asl_msg_from_string(p
);
1035 if (out
->query
== NULL
)
1044 if (m
->ruleset
== NULL
) m
->ruleset
= out
;
1047 for (rule
= m
->ruleset
; rule
->next
!= NULL
; rule
= rule
->next
);
1054 #if !TARGET_IPHONE_SIMULATOR
1056 _dst_add_uid(asl_out_dst_data_t
*dst
, char *s
)
1061 if (dst
== NULL
) return;
1062 if (s
== NULL
) return;
1066 for (i
= 0 ; i
< dst
->nuid
; i
++)
1068 if (dst
->uid
[i
] == uid
) return;
1071 dst
->uid
= reallocf(dst
->uid
, (dst
->nuid
+ 1) * sizeof(uid_t
));
1072 if (dst
->uid
== NULL
)
1078 dst
->uid
[dst
->nuid
++] = uid
;
1082 _dst_add_gid(asl_out_dst_data_t
*dst
, char *s
)
1087 if (dst
== NULL
) return;
1088 if (s
== NULL
) return;
1092 for (i
= 0 ; i
< dst
->ngid
; i
++)
1094 if (dst
->gid
[i
] == gid
) return;
1097 dst
->gid
= reallocf(dst
->gid
, (dst
->ngid
+ 1) * sizeof(gid_t
));
1098 if (dst
->gid
== NULL
)
1104 dst
->gid
[dst
->ngid
++] = gid
;
1106 #endif /* !TARGET_IPHONE_SIMULATOR */
1109 _dst_format_string(char *s
)
1114 if (s
== NULL
) return NULL
;
1118 /* format string can be enclosed by quotes */
1119 if ((len
>= 2) && ((s
[0] == '\'') || (s
[0] == '"')) && (s
[len
-1] == s
[0]))
1126 for (i
= 0; i
< len
; i
++) if (s
[i
] == '\\') n
++;
1128 fmt
= malloc(1 + len
- n
);
1129 if (fmt
== NULL
) return NULL
;
1131 for (i
= 0, n
= 0; i
< len
; i
++) if (s
[i
] != '\\') fmt
[n
++] = s
[i
];
1137 asl_str_to_size(char *s
)
1142 if (s
== NULL
) return 0;
1145 if (len
== 0) return 0;
1149 if (x
> 90) x
-= 32;
1150 if (x
== 'K') n
= 1ll << 10;
1151 else if (x
== 'M') n
= 1ll << 20;
1152 else if (x
== 'G') n
= 1ll << 30;
1159 _dst_path_match(const char *newpath
, const char *existingpath
)
1161 if (newpath
== NULL
) return (existingpath
== NULL
);
1162 if (existingpath
== NULL
) return false;
1163 if (newpath
[0] == '/') return (strcmp(newpath
, existingpath
) == 0);
1165 const char *trailing
= strrchr(existingpath
, '/');
1166 if (trailing
== NULL
) return (strcmp(newpath
, existingpath
) == 0);
1168 return (strcmp(newpath
, trailing
) == 0);
1171 static asl_out_dst_data_t
*
1172 _asl_out_module_parse_dst(asl_out_module_t
*m
, char *s
, mode_t def_mode
)
1174 asl_out_rule_t
*out
, *rule
;
1175 asl_out_dst_data_t
*dst
;
1176 char *p
, *opts
, *path
;
1178 int has_dotdot
, recursion_limit
;
1180 if (m
== NULL
) return NULL
;
1181 if (s
== NULL
) return NULL
;
1183 /* skip whitespace */
1184 while ((*s
== ' ') || (*s
== '\t')) s
++;
1187 path
= next_word_from_string(&opts
);
1188 if (path
== NULL
) return NULL
;
1191 * Check path for ".." component (not permitted).
1192 * Also substitute environment variables.
1195 path_parts
= explode(path
, "/");
1196 asl_string_t
*processed_path
= asl_string_new(ASL_ENCODE_NONE
);
1197 recursion_limit
= 5;
1199 while ((recursion_limit
> 0) && (path_parts
!= NULL
) && (processed_path
!= NULL
))
1204 for (i
= 0; path_parts
[i
] != NULL
; i
++)
1206 if (!strncmp(path_parts
[i
], "$ENV(", 5))
1208 char *p
= strchr(path_parts
[i
], ')');
1209 if (p
!= NULL
) *p
= '\0';
1210 char *env_val
= getenv(path_parts
[i
] + 5);
1211 if (env_val
!= NULL
)
1215 if (env_val
[0] != '/') asl_string_append_char_no_encoding(processed_path
, '/');
1216 asl_string_append_no_encoding(processed_path
, env_val
);
1223 if (path_parts
[0][0] != '\0') asl_string_append_no_encoding(processed_path
, path_parts
[i
]);
1227 asl_string_append_char_no_encoding(processed_path
, '/');
1228 asl_string_append_no_encoding(processed_path
, path_parts
[i
]);
1232 if ((has_dotdot
== 0) && (!strcmp(path_parts
[i
], ".."))) has_dotdot
= 1;
1235 free_string_list(path_parts
);
1237 if ((did_sub
== 0) || (has_dotdot
== 1))
1243 /* substitution might have added a ".." so check the new path */
1245 path
= asl_string_free_return_bytes(processed_path
);
1246 processed_path
= asl_string_new(ASL_ENCODE_NONE
);
1247 path_parts
= explode(path
, "/");
1254 if ((has_dotdot
!= 0) || (recursion_limit
== 0))
1256 asl_string_free(processed_path
);
1260 path
= asl_string_free_return_bytes(processed_path
);
1262 /* check if there's already a dst for this path */
1263 for (rule
= m
->ruleset
; rule
!= NULL
; rule
= rule
->next
)
1265 if (rule
->action
!= ACTION_OUT_DEST
) continue;
1268 if (dst
== NULL
) continue;
1270 if (_dst_path_match(path
, dst
->path
))
1280 const char *log_root
= "/var/log";
1282 #if TARGET_IPHONE_SIMULATOR
1283 log_root
= getenv("IPHONE_SIMULATOR_LOG_ROOT");
1287 if (!strcmp(m
->name
, ASL_MODULE_NAME
)) asprintf(&path
, "%s/%s", log_root
, t
);
1288 else asprintf(&path
, "%s/module/%s/%s", log_root
, m
->name
, t
);
1293 out
= (asl_out_rule_t
*)calloc(1, sizeof(asl_out_rule_t
));
1294 dst
= (asl_out_dst_data_t
*)calloc(1, sizeof(asl_out_dst_data_t
));
1295 if ((out
== NULL
) || (dst
== NULL
))
1305 dst
->mode
= def_mode
;
1306 dst
->ttl
= DEFAULT_TTL
;
1307 dst
->flags
= MODULE_FLAG_COALESCE
;
1309 while (NULL
!= (p
= next_word_from_string(&opts
)))
1311 if (KEYMATCH(p
, "mode=")) dst
->mode
= strtol(p
+5, NULL
, 0);
1312 else if (KEYMATCH(p
, "ttl=")) dst
->ttl
= strtol(p
+4, NULL
, 0);
1313 #if !TARGET_IPHONE_SIMULATOR
1314 else if (KEYMATCH(p
, "uid=")) _dst_add_uid(dst
, p
+4);
1315 else if (KEYMATCH(p
, "gid=")) _dst_add_gid(dst
, p
+4);
1317 else if (KEYMATCH(p
, "fmt=")) dst
->fmt
= _dst_format_string(p
+4);
1318 else if (KEYMATCH(p
, "format=")) dst
->fmt
= _dst_format_string(p
+7);
1319 else if (KEYMATCH(p
, "dest=")) dst
->rotate_dir
= _strdup_clean(p
+5);
1320 else if (KEYMATCH(p
, "dst=")) dst
->rotate_dir
= _strdup_clean(p
+4);
1321 else if (KEYMATCH(p
, "coalesce="))
1323 if (KEYMATCH(p
+9, "0")) dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1324 else if (KEYMATCH(p
+9, "off")) dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1325 else if (KEYMATCH(p
+9, "false")) dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1327 else if (KEYMATCH(p
, "compress")) dst
->flags
|= MODULE_FLAG_COMPRESS
;
1328 else if (KEYMATCH(p
, "extern")) dst
->flags
|= MODULE_FLAG_EXTERNAL
;
1329 else if (KEYMATCH(p
, "soft")) dst
->flags
|= MODULE_FLAG_SOFT_WRITE
;
1330 else if (KEYMATCH(p
, "file_max=")) dst
->file_max
= asl_str_to_size(p
+9);
1331 else if (KEYMATCH(p
, "all_max=")) dst
->all_max
= asl_str_to_size(p
+8);
1332 else if (KEYMATCH(p
, "style=") || KEYMATCH(p
, "rotate="))
1334 const char *x
= p
+ 6;
1336 if (KEYMATCH(p
, "rotate=")) x
++;
1338 dst
->flags
|= MODULE_FLAG_ROTATE
;
1340 if (KEYMATCH(x
, "sec") || KEYMATCH(x
, "seconds"))
1342 dst
->flags
|= MODULE_FLAG_STYLE_SEC
;
1344 else if (KEYMATCH(x
, "utc") || KEYMATCH(x
, "date") || KEYMATCH(x
, "zulu"))
1346 const char *dash
= strchr(x
, '-');
1347 if ((dash
!= NULL
) && (*(dash
+ 1) == 'b')) dst
->flags
|= MODULE_FLAG_STYLE_UTC_B
;
1348 else dst
->flags
|= MODULE_FLAG_STYLE_UTC
;
1350 else if (KEYMATCH(x
, "local") || KEYMATCH(x
, "lcl"))
1352 const char *dash
= strchr(x
, '-');
1353 if ((dash
!= NULL
) && (*(dash
+ 1) == 'b')) dst
->flags
|= MODULE_FLAG_STYLE_LCL_B
;
1354 else dst
->flags
|= MODULE_FLAG_STYLE_LCL
;
1356 else if (KEYMATCH(x
, "#") || KEYMATCH(x
, "seq") || KEYMATCH(x
, "sequence"))
1358 dst
->flags
|= MODULE_FLAG_STYLE_SEQ
;
1362 dst
->flags
|= MODULE_FLAG_STYLE_SEC
;
1365 else if (KEYMATCH(p
, "rotate")) dst
->flags
|= MODULE_FLAG_ROTATE
;
1366 else if (KEYMATCH(p
, "crashlog"))
1368 /* crashlog implies rotation */
1369 dst
->flags
|= MODULE_FLAG_ROTATE
;
1370 dst
->flags
|= MODULE_FLAG_CRASHLOG
;
1371 dst
->flags
|= MODULE_FLAG_BASESTAMP
;
1372 dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1374 else if (KEYMATCH(p
, "basestamp"))
1376 dst
->flags
|= MODULE_FLAG_BASESTAMP
;
1383 #if TARGET_OS_EMBEDDED
1384 /* check for crashreporter files */
1385 if (KEYMATCH(dst
->path
, _PATH_CRASHREPORTER
))
1387 dst
->flags
|= MODULE_FLAG_ROTATE
;
1388 dst
->flags
|= MODULE_FLAG_CRASHLOG
;
1389 dst
->flags
|= MODULE_FLAG_BASESTAMP
;
1390 dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1394 /* default text file format is "std" */
1395 if (dst
->fmt
== NULL
) dst
->fmt
= strdup("std");
1397 /* duplicate compression is only possible for std and bsd formats */
1398 if (strcmp(dst
->fmt
, "std") && strcmp(dst
->fmt
, "bsd")) dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1400 /* note if format is one of std, bsd, or msg */
1401 if ((!strcmp(dst
->fmt
, "std")) || (!strcmp(dst
->fmt
, "bsd")) || (!strcmp(dst
->fmt
, "msg"))) dst
->flags
|= MODULE_FLAG_STD_BSD_MSG
;
1403 /* MODULE_FLAG_STYLE_SEQ can not be used with MODULE_FLAG_BASESTAMP */
1404 if ((dst
->flags
& MODULE_FLAG_BASESTAMP
) && (dst
->flags
& MODULE_FLAG_STYLE_SEQ
))
1406 dst
->flags
&= ~MODULE_FLAG_STYLE_SEQ
;
1407 dst
->flags
|= MODULE_FLAG_STYLE_SEC
;
1410 /* set time format for raw output */
1411 if (!strcmp(dst
->fmt
, "raw")) dst
->tfmt
= "sec";
1413 out
->action
= ACTION_OUT_DEST
;
1416 /* dst rules go first */
1417 out
->next
= m
->ruleset
;
1423 static asl_out_rule_t
*
1424 _asl_out_module_parse_query_action(asl_out_module_t
*m
, char *s
)
1427 asl_out_rule_t
*out
, *rule
;
1429 if (m
== NULL
) return NULL
;
1431 out
= (asl_out_rule_t
*)calloc(1, sizeof(asl_out_rule_t
));
1432 if (out
== NULL
) return NULL
;
1434 act
= _asl_out_module_find_action(s
);
1435 if (act
== NULL
) return NULL
;
1437 /* find whitespace delimiter */
1438 p
= strchr(act
, ' ');
1439 if (p
== NULL
) p
= strchr(act
, '\t');
1440 if (p
!= NULL
) *p
= '\0';
1442 if (!strcasecmp(act
, "ignore")) out
->action
= ACTION_IGNORE
;
1443 else if (!strcasecmp(act
, "skip")) out
->action
= ACTION_SKIP
;
1444 else if (!strcasecmp(act
, "claim")) out
->action
= ACTION_CLAIM
;
1445 else if (!strcasecmp(act
, "notify")) out
->action
= ACTION_NOTIFY
;
1446 else if (!strcasecmp(act
, "file")) out
->action
= ACTION_FILE
;
1447 else if (!strcasecmp(act
, "asl_file")) out
->action
= ACTION_ASL_FILE
;
1448 else if (!strcasecmp(act
, "directory")) out
->action
= ACTION_ASL_DIR
;
1449 else if (!strcasecmp(act
, "dir")) out
->action
= ACTION_ASL_DIR
;
1450 else if (!strcasecmp(act
, "asl_directory")) out
->action
= ACTION_ASL_DIR
;
1451 else if (!strcasecmp(act
, "asl_dir")) out
->action
= ACTION_ASL_DIR
;
1452 else if (!strcasecmp(act
, "store_dir")) out
->action
= ACTION_ASL_DIR
;
1453 else if (!strcasecmp(act
, "store_directory")) out
->action
= ACTION_ASL_DIR
;
1454 else if (!strcasecmp(act
, "control")) out
->action
= ACTION_CONTROL
;
1455 else if (!strcasecmp(act
, "save")) out
->action
= ACTION_ASL_STORE
;
1456 else if (!strcasecmp(act
, "store")) out
->action
= ACTION_ASL_STORE
;
1457 else if (!strcasecmp(act
, "access")) out
->action
= ACTION_ACCESS
;
1458 else if (!strcmp(m
->name
, ASL_MODULE_NAME
))
1460 /* actions only allowed in com.apple.asl */
1461 if (!strcasecmp(act
, "broadcast")) out
->action
= ACTION_BROADCAST
;
1462 else if (!strcasecmp(act
, "forward")) out
->action
= ACTION_FORWARD
;
1465 if (out
->action
== ACTION_NONE
)
1471 /* options follow delimited (now zero) */
1474 /* skip whitespace */
1475 while ((*p
== ' ') || (*p
== '\t')) p
++;
1477 out
->options
= _strdup_clean(p
+1);
1479 if (out
->options
== NULL
)
1492 out
->query
= asl_msg_new(ASL_TYPE_QUERY
);
1497 out
->query
= asl_msg_from_string(s
);
1500 if (out
->query
== NULL
)
1507 /* store /some/path means save to an asl file */
1508 if ((out
->action
== ACTION_ASL_STORE
) && (out
->options
!= NULL
)) out
->action
= ACTION_ASL_FILE
;
1510 if ((out
->action
== ACTION_FILE
) || (out
->action
== ACTION_ASL_FILE
) || (out
->action
== ACTION_ASL_DIR
))
1512 mode_t def_mode
= 0644;
1513 if (out
->action
== ACTION_ASL_DIR
) def_mode
= 0755;
1515 out
->dst
= asl_out_dst_data_retain(_asl_out_module_parse_dst(m
, out
->options
, def_mode
));
1516 if (out
->dst
== NULL
)
1518 out
->action
= ACTION_NONE
;
1522 if ((out
->action
== ACTION_FILE
) && (out
->dst
!= NULL
) && (out
->dst
->fmt
!= NULL
) && (!strcasecmp(out
->dst
->fmt
, "asl")))
1524 out
->action
= ACTION_ASL_FILE
;
1527 if ((out
->action
== ACTION_ASL_FILE
) && (out
->dst
!= NULL
))
1529 /* remove meaningless flags */
1530 out
->dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1531 out
->dst
->flags
&= ~MODULE_FLAG_STD_BSD_MSG
;
1532 out
->dst
->flags
|= MODULE_FLAG_TYPE_ASL
;
1535 if (out
->action
== ACTION_ASL_DIR
)
1537 /* remove meaningless flags */
1538 out
->dst
->flags
&= ~MODULE_FLAG_ROTATE
;
1539 out
->dst
->flags
&= ~MODULE_FLAG_COALESCE
;
1540 out
->dst
->flags
&= ~MODULE_FLAG_STD_BSD_MSG
;
1541 out
->dst
->flags
|= MODULE_FLAG_TYPE_ASL_DIR
;
1544 /* only ACTION_FILE and ACTION_ASL_FILE may rotate */
1545 if ((out
->action
!= ACTION_FILE
) && (out
->action
!= ACTION_ASL_FILE
))
1547 out
->dst
->flags
&= ~MODULE_FLAG_ROTATE
;
1550 #if !TARGET_IPHONE_SIMULATOR
1551 if (out
->dst
->nuid
== 0) _dst_add_uid(out
->dst
, "0");
1552 if (out
->dst
->ngid
== 0) _dst_add_gid(out
->dst
, "80");
1556 if (m
->ruleset
== NULL
) m
->ruleset
= out
;
1559 for (rule
= m
->ruleset
; rule
->next
!= NULL
; rule
= rule
->next
);
1567 asl_out_module_parse_line(asl_out_module_t
*m
, char *s
)
1569 while ((*s
== ' ') || (*s
== '\t')) s
++;
1571 if ((*s
== 'Q') || (*s
== '?') || (*s
== '*'))
1573 return _asl_out_module_parse_query_action(m
, s
);
1577 return _asl_out_module_parse_set_param(m
, s
);
1581 _asl_out_module_parse_dst(m
, s
+ 1, 0644);
1588 asl_out_module_init_from_file(const char *name
, FILE *f
)
1590 asl_out_module_t
*out
;
1593 if (f
== NULL
) return NULL
;
1595 out
= asl_out_module_new(name
);
1596 if (out
== NULL
) return NULL
;
1598 /* read and parse config file */
1599 while (NULL
!= (line
= get_line_from_file(f
)))
1601 asl_out_module_parse_line(out
, line
);
1608 static asl_out_module_t
*
1609 _asl_out_module_find(asl_out_module_t
*list
, const char *name
)
1611 asl_out_module_t
*x
;
1613 if (list
== NULL
) return NULL
;
1614 if (name
== NULL
) return NULL
;
1616 for (x
= list
; x
!= NULL
; x
= x
->next
)
1618 if ((x
->name
!= NULL
) && (!strcmp(x
->name
, name
))) return x
;
1625 _asl_out_module_read_and_merge_dir(asl_out_module_t
**list
, const char *path
, uint32_t flags
)
1630 asl_out_module_t
*last
, *x
;
1632 if (list
== NULL
) return;
1633 if (path
== NULL
) return;
1638 while (last
->next
!= NULL
) last
= last
->next
;
1644 while (NULL
!= (ent
= readdir(d
)))
1646 if ((ent
->d_name
!= NULL
) && (ent
->d_name
[0] != '.'))
1648 /* merge: skip this file if we already have a module with this name */
1649 if (_asl_out_module_find(*list
, ent
->d_name
) != NULL
) continue;
1651 char tmp
[MAXPATHLEN
];
1652 snprintf(tmp
, sizeof(tmp
), "%s/%s", path
, ent
->d_name
);
1653 f
= fopen(tmp
, "r");
1656 x
= asl_out_module_init_from_file(ent
->d_name
, f
);
1663 if (!strcmp(ent
->d_name
, ASL_MODULE_NAME
))
1665 /* com.apple.asl goes at the head of the list */
1668 if (last
== NULL
) last
= *list
;
1670 else if (*list
== NULL
)
1690 asl_out_module_init(void)
1692 asl_out_module_t
*out
= NULL
;
1694 #if TARGET_IPHONE_SIMULATOR
1695 char *sim_root_path
, *sim_resources_path
;
1696 char *asl_conf
, *asl_conf_dir
, *asl_conf_local_dir
;
1698 sim_root_path
= getenv("IPHONE_SIMULATOR_ROOT");
1699 assert(sim_root_path
);
1701 sim_resources_path
= getenv("IPHONE_SHARED_RESOURCES_DIRECTORY");
1702 assert(sim_resources_path
);
1704 asprintf(&asl_conf
, "%s%s", sim_root_path
, _PATH_ASL_CONF
);
1705 asprintf(&asl_conf_dir
, "%s%s", sim_root_path
, _PATH_ASL_CONF_DIR
);
1706 asprintf(&asl_conf_local_dir
, "%s%s", sim_resources_path
, _PATH_ASL_CONF_DIR
);
1708 _asl_out_module_read_and_merge_dir(&out
, asl_conf_local_dir
, MODULE_FLAG_LOCAL
);
1709 free(asl_conf_local_dir
);
1711 _asl_out_module_read_and_merge_dir(&out
, asl_conf_dir
, 0);
1714 _asl_out_module_read_and_merge_dir(&out
, _PATH_ASL_CONF_LOCAL_DIR
, MODULE_FLAG_LOCAL
);
1715 _asl_out_module_read_and_merge_dir(&out
, _PATH_ASL_CONF_DIR
, 0);
1718 if (_asl_out_module_find(out
, ASL_MODULE_NAME
) == NULL
)
1720 /* system just has old-style /etc/asl.conf */
1721 #if TARGET_IPHONE_SIMULATOR
1722 FILE *f
= fopen(asl_conf
, "r");
1725 FILE *f
= fopen(_PATH_ASL_CONF
, "r");
1729 asl_out_module_t
*x
= asl_out_module_init_from_file(ASL_MODULE_NAME
, f
);
1746 asl_out_module_rule_to_string(asl_out_rule_t
*r
)
1753 asprintf(&out
, "NULL rule");
1757 str
= asl_msg_to_string(r
->query
, &len
);
1759 asprintf(&out
, " %s%s%s%s%s",
1760 asl_out_action_name
[r
->action
],
1761 (r
->query
== NULL
) ? "" : " ",
1762 (r
->query
== NULL
) ? "" : str
,
1763 (r
->options
== NULL
) ? "" : " ",
1764 (r
->options
== NULL
) ? "" : r
->options
);
1774 asl_out_module_print(FILE *f
, asl_out_module_t
*m
)
1776 asl_out_rule_t
*r
, *n
;
1777 asl_out_dst_data_t
*o
;
1781 for (r
= m
->ruleset
; r
!= NULL
; r
= n
)
1784 char *str
= asl_msg_to_string(r
->query
, &len
);
1786 fprintf(f
, " %s", asl_out_action_name
[r
->action
]);
1787 if (r
->query
!= NULL
) fprintf(f
, " %s", str
);
1788 if (r
->options
!= NULL
) fprintf(f
, " %s", r
->options
);
1789 if (r
->action
== ACTION_OUT_DEST
)
1794 fprintf(f
, " data: NULL");
1798 fprintf(f
, "%s\n", o
->path
);
1799 fprintf(f
, " rules: %u\n", o
->refcount
- 1);
1800 fprintf(f
, " dest: %s\n", (o
->rotate_dir
== NULL
) ? "(none)" : o
->rotate_dir
);
1801 fprintf(f
, " format: %s\n", (o
->fmt
== NULL
) ? "std" : o
->fmt
);
1802 fprintf(f
, " time_format: %s\n", (o
->tfmt
== NULL
) ? "lcl" : o
->tfmt
);
1803 fprintf(f
, " flags: 0x%08x", o
->flags
);
1808 if (o
->flags
& MODULE_FLAG_ENABLED
)
1810 fprintf(f
, "%cenabled", c
);
1813 if (o
->flags
& MODULE_FLAG_LOCAL
)
1815 fprintf(f
, "%clocal", c
);
1818 if (o
->flags
& MODULE_FLAG_ROTATE
)
1820 fprintf(f
, "%crotate", c
);
1823 if (o
->flags
& MODULE_FLAG_COALESCE
)
1825 fprintf(f
, "%ccoalesce", c
);
1828 if (o
->flags
& MODULE_FLAG_COMPRESS
)
1830 fprintf(f
, "%ccompress", c
);
1833 if (o
->flags
& MODULE_FLAG_EXTERNAL
)
1835 fprintf(f
, "%cexternal", c
);
1838 if (o
->flags
& MODULE_FLAG_STYLE_SEC
)
1840 fprintf(f
, "%cseconds", c
);
1843 if (o
->flags
& MODULE_FLAG_STYLE_SEQ
)
1845 fprintf(f
, "%csequence", c
);
1848 if (o
->flags
& MODULE_FLAG_STYLE_UTC
)
1850 fprintf(f
, "%cutc", c
);
1853 if (o
->flags
& MODULE_FLAG_STYLE_UTC_B
)
1855 fprintf(f
, "%cutc-basic", c
);
1858 if (o
->flags
& MODULE_FLAG_STYLE_LCL
)
1860 fprintf(f
, "%clocal", c
);
1863 if (o
->flags
& MODULE_FLAG_STYLE_LCL_B
)
1865 fprintf(f
, "%clocal-basic", c
);
1868 if (o
->flags
& MODULE_FLAG_BASESTAMP
)
1870 fprintf(f
, "%cbasestamp", c
);
1873 if (o
->flags
& MODULE_FLAG_CRASHLOG
)
1875 fprintf(f
, "%ccrashlog", c
);
1878 if (o
->flags
& MODULE_FLAG_SOFT_WRITE
)
1880 fprintf(f
, "%csoft", c
);
1883 if (o
->flags
& MODULE_FLAG_TYPE_ASL
)
1885 fprintf(f
, "%casl_file", c
);
1888 if (o
->flags
& MODULE_FLAG_TYPE_ASL_DIR
)
1890 fprintf(f
, "%casl_directory", c
);
1893 if (o
->flags
& MODULE_FLAG_STD_BSD_MSG
)
1895 fprintf(f
, "%cstd/bsd/msg", c
);
1902 fprintf(f
, " ttl: %u\n", o
->ttl
);
1903 fprintf(f
, " mode: 0%o\n", o
->mode
);
1904 fprintf(f
, " file_max: %lu\n", o
->file_max
);
1905 fprintf(f
, " all_max: %lu\n", o
->all_max
);
1906 #if !TARGET_IPHONE_SIMULATOR
1907 fprintf(f
, " uid:");
1908 for (i
= 0; i
< o
->nuid
; i
++) fprintf(f
, " %d", o
->uid
[i
]);
1910 fprintf(f
, " gid:");
1911 for (i
= 0; i
< o
->ngid
; i
++) fprintf(f
, " %d", o
->gid
[i
]);
1924 asl_out_file_list_free(asl_out_file_list_t
*l
)
1926 asl_out_file_list_t
*n
;
1928 if (l
== NULL
) return;
1940 * Checks input name for the form base[.stamp][.gz]
1941 * name == base is allowed if src is true.
1942 * base.gz is not allowed.
1943 * Output parameter stamp must be freed by caller.
1946 _check_file_name(const char *name
, const char *base
, bool src
, char **stamp
)
1948 size_t baselen
, nparts
;
1949 const char *p
, *q
, *part
[2];
1952 if (name
== NULL
) return false;
1953 if (base
== NULL
) return false;
1955 baselen
= strlen(base
);
1956 if (baselen
== 0) return false;
1958 if (stamp
!= NULL
) *stamp
= NULL
;
1960 if (strncmp(name
, base
, baselen
)) return false;
1964 /* name == base not allowed (it's the "active" file) */
1965 if (*p
== '\0') return false;
1967 /* name must be base.something */
1968 if (*p
!= '.') return false;
1970 /* maximum of 2 parts (stamp and gz) */
1972 for (q
= p
; *q
!= '\0'; q
++)
1976 if (nparts
== 2) return false;
1977 part
[nparts
++] = q
+ 1;
1981 if (nparts
== 0) return false;
1983 isgz
= strcmp(part
[nparts
- 1], "gz") == 0;
1985 /* no compressed files in src */
1986 if (src
&& isgz
) return false;
1988 /* expecting base.stamp or base.stamp.gz */
1992 /* compressed files must have a stamp (base.gz is not allowed) */
1993 if (isgz
) return false;
1995 /* got base.stamp */
1996 if (stamp
!= NULL
) *stamp
= strdup(part
[0]);
2000 /* expecting base.stamp.gz */
2001 if (!isgz
) return false;
2003 /* got base.stamp.gz */
2006 *stamp
= strdup(part
[0]);
2007 char *x
= strchr(*stamp
, '.');
2008 if (x
!= NULL
) *x
= '\0';
2015 * Find files in a directory (dir) that all have a common prefix (base).
2016 * Bits in flags further control the search.
2018 * MODULE_FLAG_STYLE_SEQ means a numeric sequence number is expected, although not required.
2019 * E.g. foo.log foo.log.0
2021 * MODULE_FLAG_STYLE_SEC also means a numeric sequence number is required following an 'T' character.
2022 * The numeric value is the file's timestamp in seconds. E.g foo.log.T1335200452
2024 * MODULE_FLAG_STYLE_UTC requires a date/time component as the file's timestamp.
2025 * E.g. foo.2012-04-06T15:30:00Z
2027 * MODULE_FLAG_STYLE_UTC_B requires a date/time component as the file's timestamp.
2028 * E.g. foo.20120406T153000Z
2030 * MODULE_FLAG_STYLE_LCL requires a date/time component as the file's timestamp.
2031 * E.g. foo.2012-04-06T15:30:00-7
2033 * MODULE_FLAG_STYLE_LCL_B requires a date/time component as the file's timestamp.
2034 * E.g. foo.20120406T153000-07
2036 asl_out_file_list_t
*
2037 asl_list_log_files(const char *dir
, const char *base
, bool src
, uint32_t flags
)
2041 char path
[MAXPATHLEN
];
2046 asl_out_file_list_t
*out
, *x
, *y
;
2048 if (dir
== NULL
) return NULL
;
2049 if (base
== NULL
) return NULL
;
2054 if (d
== NULL
) return NULL
;
2056 while (NULL
!= (ent
= readdir(d
)))
2061 if (ent
->d_name
== NULL
) continue;
2063 check
= _check_file_name(ent
->d_name
, base
, src
, &stamp
);
2064 if (!check
) continue;
2066 /* exclude base from dst list */
2074 else if (flags
& MODULE_FLAG_STYLE_SEQ
)
2077 if ((seq
== 0) && strcmp(stamp
, "0"))
2083 else if (flags
& MODULE_FLAG_STYLE_SEC
)
2085 ftime
= atoi(stamp
+ 1);
2087 else if ((flags
& MODULE_FLAG_STYLE_UTC
) || (flags
& MODULE_FLAG_STYLE_UTC_B
) || (flags
& MODULE_FLAG_STYLE_LCL
) || (flags
& MODULE_FLAG_STYLE_LCL_B
))
2092 long utc_offset
= 0;
2094 memset(&t
, 0, sizeof(t
));
2098 if ((flags
& MODULE_FLAG_STYLE_UTC
) || (flags
& MODULE_FLAG_STYLE_LCL
))
2100 n
= sscanf(stamp
, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t
.tm_year
, &t
.tm_mon
, &t
.tm_mday
, &t
.tm_hour
, &t
.tm_min
, &t
.tm_sec
, &zone
, &h
, &m
, &s
);
2104 n
= sscanf(stamp
, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t
.tm_year
, &t
.tm_mon
, &t
.tm_mday
, &t
.tm_hour
, &t
.tm_min
, &t
.tm_sec
, &zone
, &h
, &m
, &s
);
2115 else if ((zone
== '-') || (zone
== '+'))
2117 if (n
>= 8) utc_offset
+= (3600 * h
);
2118 if (n
>= 9) utc_offset
+= (60 * m
);
2119 if (n
== 10) utc_offset
+= s
;
2120 if (zone
== '-') utc_offset
*= -1;
2122 else if ((zone
>= 'A') && (zone
<= 'Z'))
2124 if (zone
< 'J') utc_offset
= 3600 * ((zone
- 'A') + 1);
2125 else if ((zone
>= 'K') && (zone
<= 'M')) utc_offset
= 3600 * (zone
- 'A');
2126 else if (zone
<= 'Y') utc_offset
= -3600 * ((zone
- 'N') + 1);
2128 else if ((zone
>= 'a') && (zone
<= 'z'))
2130 if (zone
< 'j') utc_offset
= 3600 * ((zone
- 'a') + 1);
2131 else if ((zone
>= 'k') && (zone
<= 'm')) utc_offset
= 3600 * (zone
- 'a');
2132 else if (zone
<= 'y') utc_offset
= -3600 * ((zone
- 'n') + 1);
2142 t
.tm_sec
+= utc_offset
;
2145 if ((zone
== 'J') || (zone
== 'j')) ftime
= mktime(&t
);
2146 else ftime
= timegm(&t
);
2151 x
= (asl_out_file_list_t
*)calloc(1, sizeof(asl_out_file_list_t
));
2154 asl_out_file_list_free(out
);
2158 x
->name
= strdup(ent
->d_name
);
2162 memset(&sb
, 0, sizeof(sb
));
2163 snprintf(path
, sizeof(path
), "%s/%s", dir
, ent
->d_name
);
2164 if (stat(path
, &sb
) == 0)
2166 x
->size
= sb
.st_size
;
2167 if (flags
& MODULE_FLAG_STYLE_SEQ
)
2169 x
->ftime
= sb
.st_birthtimespec
.tv_sec
;
2170 if (x
->ftime
== 0) x
->ftime
= sb
.st_mtimespec
.tv_sec
;
2174 if (flags
& MODULE_FLAG_STYLE_SEQ
)
2180 else if ((x
->seq
== IndexNull
) || ((x
->seq
< out
->seq
) && (out
->seq
!= IndexNull
)))
2188 for (y
= out
; y
!= NULL
; y
= y
->next
)
2190 if (y
->next
== NULL
)
2196 else if ((x
->seq
< y
->next
->seq
) && (y
->next
->seq
!= IndexNull
))
2213 else if (x
->ftime
< out
->ftime
)
2221 for (y
= out
; y
!= NULL
; y
= y
->next
)
2223 if (y
->next
== NULL
)
2229 else if (x
->ftime
< y
->next
->ftime
)
2247 * List the source files for an output asl_out_dst_data_t
2249 asl_out_file_list_t
*
2250 asl_list_src_files(asl_out_dst_data_t
*dst
)
2253 uint32_t flags
= MODULE_FLAG_STYLE_SEC
;
2254 asl_out_file_list_t
*out
;
2256 if (dst
== NULL
) return NULL
;
2257 if (dst
->path
== NULL
) return NULL
;
2260 * MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file.
2261 * We simply check for its existence.
2263 if (dst
->flags
& MODULE_FLAG_EXTERNAL
)
2267 memset(&sb
, 0, sizeof(struct stat
));
2269 if (stat(dst
->path
, &sb
) == 0)
2271 if (S_ISREG(sb
.st_mode
))
2273 out
= (asl_out_file_list_t
*)calloc(1, sizeof(asl_out_file_list_t
));
2276 char *p
= strrchr(dst
->path
, '/');
2277 if (p
== NULL
) p
= dst
->path
;
2279 out
->name
= strdup(p
);
2280 out
->ftime
= sb
.st_birthtimespec
.tv_sec
;
2281 if (out
->ftime
== 0) out
->ftime
= sb
.st_mtimespec
.tv_sec
;
2291 * Checkpoint / source format may be one of:
2292 * MODULE_FLAG_STYLE_SEC (foo.T12345678.log),
2293 * MODULE_FLAG_STYLE_UTC (foo.20120-06-24T12:34:56Z.log)
2294 * MODULE_FLAG_STYLE_UTC_B (foo.201200624T123456Z.log)
2295 * MODULE_FLAG_STYLE_LCL (foo.20120-06-24T12:34:56-7.log)
2296 * MODULE_FLAG_STYLE_LCL_B (foo.201200624T123456-07.log)
2298 * MODULE_FLAG_STYLE_SEC format is used for sequenced (MODULE_FLAG_STYLE_SEQ) files.
2299 * aslmanager converts the file names.
2302 if (dst
->flags
& MODULE_FLAG_STYLE_UTC
) flags
= MODULE_FLAG_STYLE_UTC
;
2303 else if (dst
->flags
& MODULE_FLAG_STYLE_UTC_B
) flags
= MODULE_FLAG_STYLE_UTC_B
;
2304 else if (dst
->flags
& MODULE_FLAG_STYLE_LCL
) flags
= MODULE_FLAG_STYLE_LCL
;
2305 else if (dst
->flags
& MODULE_FLAG_STYLE_LCL_B
) flags
= MODULE_FLAG_STYLE_LCL_B
;
2307 if ((dst
->rotate_dir
== NULL
) && ((dst
->flags
& MODULE_FLAG_STYLE_SEQ
) == 0) && ((dst
->flags
& MODULE_FLAG_COMPRESS
) == 0))
2309 /* files do not move to a dest dir, get renamed, or get compressed - nothing to do */
2313 base
= strrchr(dst
->path
, '/');
2314 if (base
== NULL
) return NULL
;
2319 out
= asl_list_log_files(dst
->path
, base
, true, flags
);
2321 if (base
!= NULL
) *--base
= '/';
2327 * List the destination files for an output asl_out_dst_data_t
2329 asl_out_file_list_t
*
2330 asl_list_dst_files(asl_out_dst_data_t
*dst
)
2332 char *base
, *dst_dir
;
2333 asl_out_file_list_t
*out
;
2335 if (dst
== NULL
) return NULL
;
2336 if (dst
->path
== NULL
) return NULL
;
2338 base
= strrchr(dst
->path
, '/');
2339 if (base
== NULL
) return NULL
;
2344 dst_dir
= dst
->rotate_dir
;
2345 if (dst_dir
== NULL
) dst_dir
= dst
->path
;
2347 out
= asl_list_log_files(dst_dir
, base
, false, dst
->flags
);
2349 if (base
!= NULL
) *--base
= '/';