2 * Copyright (c) 2007-2013 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@
28 #include <asl_string.h>
30 #include <asl_private.h>
32 #include <membership.h>
34 #include <libkern/OSAtomic.h>
35 #include <servers/bootstrap.h>
36 #include <bootstrap_priv.h>
37 #include <mach/kern_return.h>
38 #include <mach/mach_init.h>
39 #include <mach/mach_vm.h>
40 #include <mach/vm_map.h>
41 #include <mach/vm_param.h>
42 #include <dispatch/dispatch.h>
44 const char *ASL_LEVEL_TO_STRING
[] =
57 * Message ID generation
59 static uint64_t _asl_core_msg_next_id
= 1;
60 static pthread_mutex_t core_lock
= PTHREAD_MUTEX_INITIALIZER
;
62 #define mix(a, b, c) \
64 a -= b; a -= c; a ^= (c>>13); \
65 b -= c; b -= a; b ^= (a<< 8); \
66 c -= a; c -= b; c ^= (b>>13); \
67 a -= b; a -= c; a ^= (c>>12); \
68 b -= c; b -= a; b ^= (a<<16); \
69 c -= a; c -= b; c ^= (b>> 5); \
70 a -= b; a -= c; a ^= (c>> 3); \
71 b -= c; b -= a; b ^= (a<<10); \
72 c -= a; c -= b; c ^= (b>>15); \
76 * Hash is used to improve string search.
79 asl_core_string_hash(const char *s
, uint32_t inlen
)
81 uint32_t a
, b
, c
, l
, len
;
83 if (s
== NULL
) return 0;
88 if (s
[0] == '\0') return 0;
98 a
+= (s
[0] + ((uint32_t)s
[1]<<8) + ((uint32_t)s
[ 2]<<16) + ((uint32_t)s
[ 3]<<24));
99 b
+= (s
[4] + ((uint32_t)s
[5]<<8) + ((uint32_t)s
[ 6]<<16) + ((uint32_t)s
[ 7]<<24));
100 c
+= (s
[8] + ((uint32_t)s
[9]<<8) + ((uint32_t)s
[10]<<16) + ((uint32_t)s
[11]<<24));
111 case 11: c
+= ((uint32_t)s
[10]<<24);
112 case 10: c
+= ((uint32_t)s
[9]<<16);
113 case 9 : c
+= ((uint32_t)s
[8]<<8);
115 case 8 : b
+= ((uint32_t)s
[7]<<24);
116 case 7 : b
+= ((uint32_t)s
[6]<<16);
117 case 6 : b
+= ((uint32_t)s
[5]<<8);
120 case 4 : a
+= ((uint32_t)s
[3]<<24);
121 case 3 : a
+= ((uint32_t)s
[2]<<16);
122 case 2 : a
+= ((uint32_t)s
[1]<<8);
133 asl_core_error(uint32_t code
)
137 case ASL_STATUS_OK
: return "Operation Succeeded";
138 case ASL_STATUS_INVALID_ARG
: return "Invalid Argument";
139 case ASL_STATUS_INVALID_STORE
: return "Invalid Data Store";
140 case ASL_STATUS_INVALID_STRING
: return "Invalid String";
141 case ASL_STATUS_INVALID_ID
: return "Invalid ID Number";
142 case ASL_STATUS_INVALID_MESSAGE
: return "Invalid Message";
143 case ASL_STATUS_NOT_FOUND
: return "Not Found";
144 case ASL_STATUS_READ_FAILED
: return "Read Operation Failed";
145 case ASL_STATUS_WRITE_FAILED
: return "Write Operation Failed";
146 case ASL_STATUS_NO_MEMORY
: return "System Memory Allocation Failed";
147 case ASL_STATUS_ACCESS_DENIED
: return "Access Denied";
148 case ASL_STATUS_READ_ONLY
: return "Read Only Access";
149 case ASL_STATUS_WRITE_ONLY
: return "Write Only Access";
150 case ASL_STATUS_MATCH_FAILED
: return "Match Failed";
151 case ASL_STATUS_NO_RECORDS
: return "No More Records";
154 return "Operation Failed";
158 asl_core_level_to_string(uint32_t level
)
160 if (level
> ASL_LEVEL_DEBUG
) return "invalid";
161 return ASL_LEVEL_TO_STRING
[level
];
165 asl_core_check_user_access(int32_t msgu
, int32_t readu
)
167 /* -1 means anyone may read */
168 if (msgu
== -1) return ASL_STATUS_OK
;
170 /* Check for exact match */
171 if (msgu
== readu
) return ASL_STATUS_OK
;
173 return ASL_STATUS_ACCESS_DENIED
;
177 asl_core_check_group_access(int32_t msgg
, int32_t readu
, int32_t readg
)
182 /* -1 means anyone may read */
183 if (msgg
== -1) return ASL_STATUS_OK
;
185 /* Check for exact match */
186 if (msgg
== readg
) return ASL_STATUS_OK
;
188 /* Check if user (u) is in read group (msgg) */
189 mbr_uid_to_uuid(readu
, uu
);
190 mbr_gid_to_uuid(msgg
, gu
);
193 mbr_check_membership(uu
, gu
, &check
);
194 if (check
!= 0) return ASL_STATUS_OK
;
196 return ASL_STATUS_ACCESS_DENIED
;
200 asl_core_check_access(int32_t msgu
, int32_t msgg
, int32_t readu
, int32_t readg
, uint16_t flags
)
204 /* root (uid 0) may always read */
205 if (readu
== 0) return ASL_STATUS_OK
;
207 uset
= flags
& ASL_MSG_FLAG_READ_UID_SET
;
208 gset
= flags
& ASL_MSG_FLAG_READ_GID_SET
;
210 /* if no access controls are set, anyone may read */
211 if ((uset
| gset
) == 0) return ASL_STATUS_OK
;
213 /* if only uid is set, then access is only by uid match */
214 if ((uset
!= 0) && (gset
== 0)) return asl_core_check_user_access(msgu
, readu
);
216 /* if only gid is set, then access is only by gid match */
217 if ((uset
== 0) && (gset
!= 0)) return asl_core_check_group_access(msgg
, readu
, readg
);
219 /* both uid and gid are set - check user, then group */
220 if ((asl_core_check_user_access(msgu
, readu
)) == ASL_STATUS_OK
) return ASL_STATUS_OK
;
221 return asl_core_check_group_access(msgg
, readu
, readg
);
225 asl_core_htonq(uint64_t n
)
227 #ifdef __BIG_ENDIAN__
239 x
.l
[0] = htonl(x
.l
[1]);
247 asl_core_ntohq(uint64_t n
)
249 #ifdef __BIG_ENDIAN__
261 x
.l
[0] = ntohl(x
.l
[1]);
269 asl_core_new_msg_id(uint64_t start
)
273 pthread_mutex_lock(&core_lock
);
275 if (start
!= 0) _asl_core_msg_next_id
= start
;
277 out
= _asl_core_msg_next_id
;
278 _asl_core_msg_next_id
++;
280 pthread_mutex_unlock(&core_lock
);
286 asl_filesystem_path(uint32_t place
)
288 static dispatch_once_t once
;
289 static char *asl_filesystem_path_database
= NULL
;
290 static char *asl_filesystem_path_archive
= NULL
;
292 dispatch_once(&once
, ^{
293 char *asl_var_log
= NULL
;
294 const char *const_asl_var_log
= "/var/log";
296 #if TARGET_OS_SIMULATOR
297 asl_var_log
= getenv("SIMULATOR_LOG_ROOT");
300 if (asl_var_log
!= NULL
) const_asl_var_log
= (const char *)asl_var_log
;
302 asprintf(&asl_filesystem_path_database
, "%s/asl", const_asl_var_log
);
303 asprintf(&asl_filesystem_path_archive
, "%s/asl.archive", const_asl_var_log
);
308 case ASL_PLACE_DATABASE
:
310 return asl_filesystem_path_database
;
312 case ASL_PLACE_ARCHIVE
:
314 return asl_filesystem_path_archive
;
326 #pragma mark data buffer encoding
329 * asl_core_encode_buffer
330 * encode arbitrary data as a C string without embedded zero (nul) characters
332 * The routine computes a histogram of the input buffer and finds
333 * the two least frequently used non-nul chars (L[0] and L[1]).
335 * L[0] is used to stand in for nul.
336 * L[1] is used as the escape character.
337 * Occurrences of nul in the data are encoded as L[0]
338 * Occurrences of L[0] in the data are encoded as the sequence L[1] 1.
339 * Occurrences of L[1] in the data are encoded as the sequence L[1] 2.
341 * The output string is preceded by L[0] L[1], and is nul terminated.
342 * The output length is 2 + n + N(L[0]) + N(L[1]) + 1
343 * where N(x) is the number of occurrences of x in the input string.
344 * The worst case occurs when all characters are equally frequent,
345 * In that case the output size will less that 1% larger than the input.
348 asl_core_encode_buffer(const char *in
, uint32_t len
)
351 uint32_t i
, j
, k
, outlen
, breakit
, min
, hist
[256];
352 uint32_t lfu
[2], save
[2];
355 if (in
== NULL
) return NULL
;
356 if (len
== 0) return NULL
;
358 memset(hist
, 0, sizeof(hist
));
362 for (i
= 0; i
< len
; i
++)
368 for (j
= 0; j
< 2; j
++)
373 for (i
= 2; i
< 256; i
++)
381 * Stop if there are no occurances or character i in the input.
382 * The minimum will never be less than zero.
387 * When looking for the second least frequently used character,
388 * stop scanning if we hit the same minimum as we saw in the first
389 * pass. There will be no smaller values.
391 if ((j
== 1) && (min
== save
[0])) break;
395 save
[j
] = hist
[lfu
[j
]];
396 hist
[lfu
[j
]] = (uint32_t)-1;
399 outlen
= 2 + len
+ save
[0] + save
[1] + 1;
401 str
= malloc(outlen
);
402 if (str
== NULL
) return NULL
;
404 str
[outlen
- 1] = '\0';
411 for (i
= 0; i
< len
; i
++)
421 for (k
= 0; (k
< 2) && (breakit
== 0); k
++)
431 if (breakit
== 1) continue;
440 * asl_core_decode_buffer
441 * decode a string produced by asl_encode_buffer to recreate the original data
444 asl_core_decode_buffer(const char *in
, char **buf
, uint32_t *len
)
447 uint32_t i
, j
, n
, outlen
;
451 if (buf
== NULL
) return -1;
452 if (len
== NULL
) return -1;
459 /* strip trailing nul */
462 /* determine output length and check for invalid input */
463 for (i
= 2; i
< n
; i
++)
469 if (i
== n
) return -1;
472 if ((v
< 1) || (v
> 2)) return -1;
479 if (outlen
== 0) return -1;
481 out
= malloc(outlen
);
482 if (out
== NULL
) return -1;
485 for (i
= 2; i
< n
; i
++)
492 else if (v
== lfu
[1])
496 out
[j
++] = lfu
[v
- 1];
507 #pragma mark time parsing
510 * utility for converting a time string into a time_t
511 * we only deal with the following formats:
512 * dotted form YYYY.MM.DD hh:mm:ss UTC
513 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
514 * absolute form - # seconds since the epoch (e.g. 1095789191)
515 * relative time - seconds before or after now (e.g. -300, +43200)
516 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
517 * ISO8601 - YYYY[-]MM[-]DDTHH[:]MM[:]SS optionally followed by Z or +/-HH[[:]MM]
521 * light(er)-weight replcaement (in place of regex) for asl_core_parse_time
524 #define MFLAG_INCLUDE 0x00000001
525 #define MFLAG_EXCLUDE 0x00000002
527 #define DIGITS "0123456789"
528 #define WHITESPACE " "
530 #define SECONDS_PER_MINUTE 60
531 #define SECONDS_PER_HOUR 3600
532 #define SECONDS_PER_DAY 86400
533 #define SECONDS_PER_WEEK 604800
536 * Match between mincount and maxcount characters in or not in mset.
537 * maxcount == 0 means no limit.
541 asl_core_str_match(const char *target
, const char *mset
, uint32_t mincount
, uint32_t maxcount
, uint32_t flags
, uint32_t *length
)
546 if (length
== NULL
) length
= &n
;
548 if (target
== NULL
) return (mincount
== 0);
550 for (x
= target
, *length
= 0; *x
!= '\0'; x
++, *length
= *length
+ 1)
554 if ((*length
== maxcount
) && (maxcount
> 0)) return true;
555 if (mset
== NULL
) continue;
557 s
= strchr(mset
, *x
);
558 if ((s
== NULL
) && (flags
& MFLAG_EXCLUDE
)) continue;
559 if ((s
!= NULL
) && (flags
& MFLAG_INCLUDE
)) continue;
564 return (*length
>= mincount
);
568 asl_core_str_match_char(const char *target
, const char c
, uint32_t mincount
, uint32_t flags
, uint32_t *length
)
572 if (length
== NULL
) length
= &n
;
575 if (target
== NULL
) return (mincount
== 0);
577 if ((*target
== c
) && (flags
& MFLAG_INCLUDE
)) *length
= 1;
578 if ((*target
!= c
) && (flags
& MFLAG_EXCLUDE
)) *length
= 1;
580 return (*length
>= mincount
);
584 asl_core_str_to_uint32(const char *target
, uint32_t length
)
586 uint32_t i
, d
, out
= 0;
588 for (i
= 0; i
< length
; i
++)
591 out
= (out
* 10) + d
;
598 asl_core_str_to_size(char *s
)
603 if (s
== NULL
) return 0;
606 if (len
== 0) return 0;
611 if (x
== 'K') n
= 1ll << 10;
612 else if (x
== 'M') n
= 1ll << 20;
613 else if (x
== 'G') n
= 1ll << 30;
620 asl_core_str_to_time(char *s
, uint32_t def_n
)
626 if (s
== NULL
) return 0;
629 if (len
== 0) return 0;
637 else if (x
== 'M') n
= SECONDS_PER_MINUTE
;
638 else if (x
== 'H') n
= SECONDS_PER_HOUR
;
639 else if (x
== 'D') n
= SECONDS_PER_DAY
;
646 asl_core_time_to_str(time_t s
, char *str
, size_t len
)
648 char days
[32], hms
[32];
651 d
= s
/ SECONDS_PER_DAY
;
652 s
%= SECONDS_PER_DAY
;
654 h
= s
/ SECONDS_PER_HOUR
;
655 s
%= SECONDS_PER_HOUR
;
657 m
= s
/ SECONDS_PER_MINUTE
;
658 s
%= SECONDS_PER_MINUTE
;
660 memset(days
, 0, sizeof(days
));
661 if (d
> 0) snprintf(days
, sizeof(days
), "%u day%s", d
, (d
== 1) ? "" : "s");
663 memset(hms
, 0, sizeof(hms
));
664 snprintf(hms
, sizeof(hms
), "%02u:%02u:%02lld", h
, m
, (long long) s
);
666 if ((h
+ m
+ s
) == 0)
668 if (d
== 0) snprintf(str
, len
, "0");
669 else snprintf(str
, len
, "%s", days
);
673 if (d
== 0) snprintf(str
, len
, "%s", hms
);
674 else snprintf(str
, len
, "%s %s", days
, hms
);
678 asl_core_str_match_absolute_or_relative_time(const char *target
, time_t *tval
, uint32_t *tlen
)
681 int32_t val
, sign
= 1;
686 if (target
== NULL
) return false;
690 test
= asl_core_str_match(p
, "+-", 0, 1, MFLAG_INCLUDE
, &len
);
691 if (!test
) return false;
697 if (*p
== '-') sign
= -1;
702 test
= asl_core_str_match(p
, DIGITS
, 1, 0, MFLAG_INCLUDE
, &len
);
703 if (!test
) return false;
704 val
= asl_core_str_to_uint32(p
, len
);
708 test
= asl_core_str_match(p
, "SsMmHhDdWw", 0, 1, MFLAG_INCLUDE
, &len
);
709 if (!test
) return false;
711 if ((*p
== 'M') || (*p
== 'm')) val
*= SECONDS_PER_MINUTE
;
712 else if ((*p
== 'H') || (*p
== 'h')) val
*= SECONDS_PER_HOUR
;
713 else if ((*p
== 'D') || (*p
== 'd')) val
*= SECONDS_PER_DAY
;
714 else if ((*p
== 'W') || (*p
== 'w')) val
*= SECONDS_PER_WEEK
;
716 /* matched string must be followed by space, tab, newline (not counted in length) */
720 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
721 if (!test
) return false;
724 if (tlen
!= NULL
) *tlen
= p
- target
;
725 if (tval
!= NULL
) *tval
= start
+ (sign
* val
);
731 _month_num(const char *s
)
733 if (!strncasecmp(s
, "jan", 3)) return 0;
734 if (!strncasecmp(s
, "feb", 3)) return 1;
735 if (!strncasecmp(s
, "mar", 3)) return 2;
736 if (!strncasecmp(s
, "apr", 3)) return 3;
737 if (!strncasecmp(s
, "may", 3)) return 4;
738 if (!strncasecmp(s
, "jun", 3)) return 5;
739 if (!strncasecmp(s
, "jul", 3)) return 6;
740 if (!strncasecmp(s
, "aug", 3)) return 7;
741 if (!strncasecmp(s
, "sep", 3)) return 8;
742 if (!strncasecmp(s
, "oct", 3)) return 9;
743 if (!strncasecmp(s
, "nov", 3)) return 10;
744 if (!strncasecmp(s
, "dec", 3)) return 11;
750 * Match ctime() format - Mth [D]D [h]h:mm:ss
753 asl_core_str_match_c_time(const char *target
, time_t *tval
, uint32_t *tlen
)
761 if (target
== NULL
) return false;
762 memset(&t
, 0, sizeof(t
));
764 /* determine current date */
766 localtime_r(&now
, &t
);
768 memset(&t
, 0, sizeof(t
));
773 t
.tm_mon
= _month_num(p
);
775 if (t
.tm_mon
== -1) return false;
779 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
780 if (!test
) return false;
784 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
785 if (!test
) return false;
786 t
.tm_mday
= asl_core_str_to_uint32(p
, len
);
787 if (t
.tm_mday
> 31) return false;
791 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
792 if (!test
) return false;
796 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
797 if (!test
) return false;
798 t
.tm_hour
= asl_core_str_to_uint32(p
, len
);
799 if (t
.tm_hour
> 23) return false;
803 if (*p
!= ':') return false;
808 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
809 if (!test
) return false;
810 t
.tm_min
= asl_core_str_to_uint32(p
, len
);
811 if (t
.tm_min
> 59) return false;
815 if (*p
!= ':') return false;
820 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
821 if (!test
) return false;
822 t
.tm_sec
= asl_core_str_to_uint32(p
, len
);
823 if (t
.tm_sec
> 59) return false;
825 /* matched string must be followed by space, tab, newline (not counted in length) */
829 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
830 if (!test
) return false;
835 if (tlen
!= NULL
) *tlen
= p
- target
;
836 if (tval
!= NULL
) *tval
= mktime(&t
);
842 * Match YYYY.[M]M.[D]D [h]h:mm:ss UTC
845 asl_core_str_match_dotted_time(const char *target
, time_t *tval
, uint32_t *tlen
)
852 if (target
== NULL
) return false;
853 memset(&t
, 0, sizeof(t
));
857 test
= asl_core_str_match(p
, DIGITS
, 4, 4, MFLAG_INCLUDE
, &len
);
858 if (!test
) return false;
859 t
.tm_year
= asl_core_str_to_uint32(p
, len
) - 1900;
863 if (*p
!= '.') return false;
868 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
869 if (!test
) return false;
870 t
.tm_mon
= asl_core_str_to_uint32(p
, len
);
871 if (t
.tm_mon
< 1) return false;
872 if (t
.tm_mon
> 12) return false;
877 if (*p
!= '.') return false;
882 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
883 if (!test
) return false;
884 t
.tm_mday
= asl_core_str_to_uint32(p
, len
);
885 if (t
.tm_mday
> 31) return false;
889 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
890 if (!test
) return false;
894 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
895 if (!test
) return false;
896 t
.tm_hour
= asl_core_str_to_uint32(p
, len
);
897 if (t
.tm_hour
> 23) return false;
901 if (*p
!= ':') return false;
906 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
907 if (!test
) return false;
908 t
.tm_min
= asl_core_str_to_uint32(p
, len
);
909 if (t
.tm_min
> 59) return false;
913 if (*p
!= ':') return false;
918 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
919 if (!test
) return false;
920 t
.tm_sec
= asl_core_str_to_uint32(p
, len
);
921 if (t
.tm_sec
> 59) return false;
925 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
926 if (!test
) return false;
930 if (strncmp(p
, "UTC", 3)) return false;
933 /* matched string must be followed by space, tab, newline (not counted in length) */
937 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
938 if (!test
) return false;
941 if (tlen
!= NULL
) *tlen
= p
- target
;
942 if (tval
!= NULL
) *tval
= timegm(&t
);
948 * Match YYYY[-]MM[-]DD[Tt]hh[:]hh[:]ss[Zz] or YYYY[-]MM[-]DD[Tt]hh[:]hh[:]ss[+-][H]H[[:]MM]
951 asl_core_str_match_iso_8601_time(const char *target
, time_t *tval
, uint32_t *tlen
)
957 int32_t tzh
, tzs
, sign
= -1;
959 if (target
== NULL
) return false;
960 memset(&t
, 0, sizeof(t
));
964 test
= asl_core_str_match(p
, DIGITS
, 4, 4, MFLAG_INCLUDE
, &len
);
965 if (!test
) return false;
966 t
.tm_year
= asl_core_str_to_uint32(p
, len
) - 1900;
970 test
= asl_core_str_match_char(p
, '-', 0, MFLAG_INCLUDE
, &len
);
971 if (!test
) return false;
975 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
976 if (!test
) return false;
977 t
.tm_mon
= asl_core_str_to_uint32(p
, len
);
978 if (t
.tm_mon
< 1) return false;
979 if (t
.tm_mon
> 12) return false;
984 test
= asl_core_str_match_char(p
, '-', 0, MFLAG_INCLUDE
, &len
);
985 if (!test
) return false;
989 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
990 if (!test
) return false;
991 t
.tm_mday
= asl_core_str_to_uint32(p
, len
);
992 if (t
.tm_mday
> 31) return false;
996 test
= asl_core_str_match(p
, "Tt", 1, 1, MFLAG_INCLUDE
, &len
);
997 if (!test
) return false;
1001 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
1002 if (!test
) return false;
1003 t
.tm_hour
= asl_core_str_to_uint32(p
, len
);
1004 if (t
.tm_hour
> 23) return false;
1008 test
= asl_core_str_match_char(p
, ':', 0, MFLAG_INCLUDE
, &len
);
1009 if (!test
) return false;
1013 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
1014 if (!test
) return false;
1015 t
.tm_min
= asl_core_str_to_uint32(p
, len
);
1016 if (t
.tm_min
> 59) return false;
1020 test
= asl_core_str_match_char(p
, ':', 0, MFLAG_INCLUDE
, &len
);
1021 if (!test
) return false;
1025 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
1026 if (!test
) return false;
1027 t
.tm_sec
= asl_core_str_to_uint32(p
, len
);
1028 if (t
.tm_sec
> 59) return false;
1032 /* default to local time if we hit the end of the string */
1033 if ((*p
== '\0') || (*p
== ' ') || (*p
== '\t') || (*p
== '\n'))
1037 if (tlen
!= NULL
) *tlen
= p
- target
;
1038 if (tval
!= NULL
) *tval
= mktime(&t
);
1044 test
= asl_core_str_match(p
, "Zz+-", 1, 1, MFLAG_INCLUDE
, &len
);
1045 if (!test
) return false;
1047 if ((*p
== 'Z') || (*p
== 'z'))
1049 /* matched string must be followed by space, tab, newline (not counted in length) */
1053 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
1054 if (!test
) return false;
1057 if (tlen
!= NULL
) *tlen
= p
- target
;
1058 if (tval
!= NULL
) *tval
= timegm(&t
);
1063 if (*p
== '-') sign
= 1;
1067 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
1068 if (!test
) return false;
1069 tzh
= asl_core_str_to_uint32(p
, len
);
1070 if (tzh
> 23) return false;
1074 test
= asl_core_str_match_char(p
, ':', 0, MFLAG_INCLUDE
, &len
);
1075 if (!test
) return false;
1079 test
= asl_core_str_match(p
, DIGITS
, 0, 2, MFLAG_INCLUDE
, &len
);
1080 if (!test
) return false;
1081 tzs
= asl_core_str_to_uint32(p
, len
);
1082 if (tzs
> 59) return false;
1084 t
.tm_sec
+= (sign
* (tzh
* SECONDS_PER_HOUR
) + (tzs
* SECONDS_PER_MINUTE
));
1086 /* matched string must be followed by space, tab, newline (not counted in length) */
1090 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
1091 if (!test
) return false;
1094 if (tlen
!= NULL
) *tlen
= p
- target
;
1095 if (tval
!= NULL
) *tval
= timegm(&t
);
1101 asl_core_parse_time(const char *in
, uint32_t *tlen
)
1106 if (tlen
!= NULL
) *tlen
= 0;
1108 if (in
== NULL
) return -1;
1111 * Heuristics to determine the string format.
1112 * Warning: this code must be checked and may need to be adjusted if new formats are added.
1115 if (inlen
== 0) return -1;
1117 /* leading plus or minus means it must be a relative time */
1118 if ((in
[0] == '+') || (in
[0] == '-'))
1120 if (asl_core_str_match_absolute_or_relative_time(in
, &tval
, tlen
)) return tval
;
1124 /* leading alphabetic char means it must be ctime() format */
1125 if (((in
[0] >= 'a') && (in
[0] <= 'z')) || ((in
[0] >= 'A') && (in
[0] <= 'Z')))
1127 if (asl_core_str_match_c_time(in
, &tval
, tlen
)) return tval
;
1131 /* only absolute, dotted, or iso8601 formats at this point */
1133 /* one to for chars means it must be absolute */
1136 if (asl_core_str_match_absolute_or_relative_time(in
, &tval
, tlen
)) return tval
;
1143 if (asl_core_str_match_dotted_time(in
, &tval
, tlen
)) return tval
;
1147 /* only absolute or iso8601 at this point */
1149 /* check for absolute first, since that's quicker */
1150 if (asl_core_str_match_absolute_or_relative_time(in
, &tval
, tlen
)) return tval
;
1152 if (asl_core_str_match_iso_8601_time(in
, &tval
, tlen
)) return tval
;
1158 * asl_parse_time is old SPI used all over the place.
1161 asl_parse_time(const char *in
)
1163 return asl_core_parse_time(in
, NULL
);