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
[] =
56 static char *asl_filesystem_path_database
= NULL
;
57 static char *asl_filesystem_path_archive
= NULL
;
60 * Message ID generation
62 static uint64_t _asl_core_msg_next_id
= 1;
63 static pthread_mutex_t core_lock
= PTHREAD_MUTEX_INITIALIZER
;
65 #define mix(a, b, c) \
67 a -= b; a -= c; a ^= (c>>13); \
68 b -= c; b -= a; b ^= (a<< 8); \
69 c -= a; c -= b; c ^= (b>>13); \
70 a -= b; a -= c; a ^= (c>>12); \
71 b -= c; b -= a; b ^= (a<<16); \
72 c -= a; c -= b; c ^= (b>> 5); \
73 a -= b; a -= c; a ^= (c>> 3); \
74 b -= c; b -= a; b ^= (a<<10); \
75 c -= a; c -= b; c ^= (b>>15); \
79 * Get ASL server mach port.
80 * reset != 0 flushes cached port.
81 * reset < 0 returns MACH_PORT_NULL
84 asl_core_get_service_port(int reset
)
86 static mach_port_t server_port
= MACH_PORT_NULL
;
88 kern_return_t kstatus
;
90 if ((reset
!= 0) && (server_port
!= MACH_PORT_NULL
))
92 mach_port_t tmp
= server_port
;
93 server_port
= MACH_PORT_NULL
;
94 mach_port_deallocate(mach_task_self(), tmp
);
97 if (reset
< 0) return MACH_PORT_NULL
;
99 if (server_port
!= MACH_PORT_NULL
) return server_port
;
101 tmp
= MACH_PORT_NULL
;
102 char *str
= getenv("ASL_DISABLE");
103 if ((str
!= NULL
) && (!strcmp(str
, "1"))) return MACH_PORT_NULL
;
105 kstatus
= bootstrap_look_up2(bootstrap_port
, ASL_SERVICE_NAME
, &tmp
, 0, BOOTSTRAP_PRIVILEGED_SERVER
);
106 if ((kstatus
!= KERN_SUCCESS
) || (tmp
== MACH_PORT_NULL
)) return MACH_PORT_NULL
;
108 if (!OSAtomicCompareAndSwap32Barrier(MACH_PORT_NULL
, tmp
, (int32_t *)&server_port
))
110 mach_port_deallocate(mach_task_self(), tmp
);
117 * Hash is used to improve string search.
120 asl_core_string_hash(const char *s
, uint32_t inlen
)
122 uint32_t a
, b
, c
, l
, len
;
124 if (s
== NULL
) return 0;
129 if (s
[0] == '\0') return 0;
139 a
+= (s
[0] + ((uint32_t)s
[1]<<8) + ((uint32_t)s
[ 2]<<16) + ((uint32_t)s
[ 3]<<24));
140 b
+= (s
[4] + ((uint32_t)s
[5]<<8) + ((uint32_t)s
[ 6]<<16) + ((uint32_t)s
[ 7]<<24));
141 c
+= (s
[8] + ((uint32_t)s
[9]<<8) + ((uint32_t)s
[10]<<16) + ((uint32_t)s
[11]<<24));
152 case 11: c
+= ((uint32_t)s
[10]<<24);
153 case 10: c
+= ((uint32_t)s
[9]<<16);
154 case 9 : c
+= ((uint32_t)s
[8]<<8);
156 case 8 : b
+= ((uint32_t)s
[7]<<24);
157 case 7 : b
+= ((uint32_t)s
[6]<<16);
158 case 6 : b
+= ((uint32_t)s
[5]<<8);
161 case 4 : a
+= ((uint32_t)s
[3]<<24);
162 case 3 : a
+= ((uint32_t)s
[2]<<16);
163 case 2 : a
+= ((uint32_t)s
[1]<<8);
174 asl_core_error(uint32_t code
)
178 case ASL_STATUS_OK
: return "Operation Succeeded";
179 case ASL_STATUS_INVALID_ARG
: return "Invalid Argument";
180 case ASL_STATUS_INVALID_STORE
: return "Invalid Data Store";
181 case ASL_STATUS_INVALID_STRING
: return "Invalid String";
182 case ASL_STATUS_INVALID_ID
: return "Invalid ID Number";
183 case ASL_STATUS_INVALID_MESSAGE
: return "Invalid Message";
184 case ASL_STATUS_NOT_FOUND
: return "Not Found";
185 case ASL_STATUS_READ_FAILED
: return "Read Operation Failed";
186 case ASL_STATUS_WRITE_FAILED
: return "Write Operation Failed";
187 case ASL_STATUS_NO_MEMORY
: return "System Memory Allocation Failed";
188 case ASL_STATUS_ACCESS_DENIED
: return "Access Denied";
189 case ASL_STATUS_READ_ONLY
: return "Read Only Access";
190 case ASL_STATUS_WRITE_ONLY
: return "Write Only Access";
191 case ASL_STATUS_MATCH_FAILED
: return "Match Failed";
192 case ASL_STATUS_NO_RECORDS
: return "No More Records";
195 return "Operation Failed";
199 asl_core_level_to_string(uint32_t level
)
201 if (level
> ASL_LEVEL_DEBUG
) return "invalid";
202 return ASL_LEVEL_TO_STRING
[level
];
206 asl_core_check_user_access(int32_t msgu
, int32_t readu
)
208 /* -1 means anyone may read */
209 if (msgu
== -1) return ASL_STATUS_OK
;
211 /* Check for exact match */
212 if (msgu
== readu
) return ASL_STATUS_OK
;
214 return ASL_STATUS_ACCESS_DENIED
;
218 asl_core_check_group_access(int32_t msgg
, int32_t readu
, int32_t readg
)
223 /* -1 means anyone may read */
224 if (msgg
== -1) return ASL_STATUS_OK
;
226 /* Check for exact match */
227 if (msgg
== readg
) return ASL_STATUS_OK
;
229 /* Check if user (u) is in read group (msgg) */
230 mbr_uid_to_uuid(readu
, uu
);
231 mbr_gid_to_uuid(msgg
, gu
);
234 mbr_check_membership(uu
, gu
, &check
);
235 if (check
!= 0) return ASL_STATUS_OK
;
237 return ASL_STATUS_ACCESS_DENIED
;
241 asl_core_check_access(int32_t msgu
, int32_t msgg
, int32_t readu
, int32_t readg
, uint16_t flags
)
245 /* root (uid 0) may always read */
246 if (readu
== 0) return ASL_STATUS_OK
;
248 uset
= flags
& ASL_MSG_FLAG_READ_UID_SET
;
249 gset
= flags
& ASL_MSG_FLAG_READ_GID_SET
;
251 /* if no access controls are set, anyone may read */
252 if ((uset
| gset
) == 0) return ASL_STATUS_OK
;
254 /* if only uid is set, then access is only by uid match */
255 if ((uset
!= 0) && (gset
== 0)) return asl_core_check_user_access(msgu
, readu
);
257 /* if only gid is set, then access is only by gid match */
258 if ((uset
== 0) && (gset
!= 0)) return asl_core_check_group_access(msgg
, readu
, readg
);
260 /* both uid and gid are set - check user, then group */
261 if ((asl_core_check_user_access(msgu
, readu
)) == ASL_STATUS_OK
) return ASL_STATUS_OK
;
262 return asl_core_check_group_access(msgg
, readu
, readg
);
266 asl_core_htonq(uint64_t n
)
268 #ifdef __BIG_ENDIAN__
280 x
.l
[0] = htonl(x
.l
[1]);
288 asl_core_ntohq(uint64_t n
)
290 #ifdef __BIG_ENDIAN__
302 x
.l
[0] = ntohl(x
.l
[1]);
310 asl_core_new_msg_id(uint64_t start
)
314 pthread_mutex_lock(&core_lock
);
316 if (start
!= 0) _asl_core_msg_next_id
= start
;
318 out
= _asl_core_msg_next_id
;
319 _asl_core_msg_next_id
++;
321 pthread_mutex_unlock(&core_lock
);
327 asl_filesystem_path(uint32_t place
)
329 static dispatch_once_t once
;
331 dispatch_once(&once
, ^{
332 char *asl_var_log
= NULL
;
333 const char *const_asl_var_log
= "/var/log";
335 #if TARGET_IPHONE_SIMULATOR
336 asl_var_log
= getenv("SIMULATOR_LOG_ROOT");
339 if (asl_var_log
!= NULL
) const_asl_var_log
= (const char *)asl_var_log
;
341 asprintf(&asl_filesystem_path_database
, "%s/asl", const_asl_var_log
);
342 asprintf(&asl_filesystem_path_archive
, "%s/asl.archive", const_asl_var_log
);
347 case ASL_PLACE_DATABASE
:
349 if (asl_filesystem_path_database
== NULL
) return ASL_PLACE_DATABASE_DEFAULT
;
350 return asl_filesystem_path_database
;
352 case ASL_PLACE_ARCHIVE
:
354 if (asl_filesystem_path_archive
== NULL
) return ASL_PLACE_ARCHIVE_DEFAULT
;
355 return asl_filesystem_path_archive
;
367 #pragma mark data buffer encoding
370 * asl_core_encode_buffer
371 * encode arbitrary data as a C string without embedded zero (nul) characters
373 * The routine computes a histogram of the input buffer and finds
374 * the two least frequently used non-nul chars (L[0] and L[1]).
376 * L[0] is used to stand in for nul.
377 * L[1] is used as the escape character.
378 * Occurrences of nul in the data are encoded as L[0]
379 * Occurrences of L[0] in the data are encoded as the sequence L[1] 1.
380 * Occurrences of L[1] in the data are encoded as the sequence L[1] 2.
382 * The output string is preceded by L[0] L[1], and is nul terminated.
383 * The output length is 2 + n + N(L[0]) + N(L[1]) + 1
384 * where N(x) is the number of occurrences of x in the input string.
385 * The worst case occurs when all characters are equally frequent,
386 * In that case the output size will less that 1% larger than the input.
389 asl_core_encode_buffer(const char *in
, uint32_t len
)
392 uint32_t i
, j
, k
, outlen
, breakit
, min
, hist
[256];
393 uint32_t lfu
[2], save
[2];
396 if (in
== NULL
) return NULL
;
397 if (len
== 0) return NULL
;
399 memset(hist
, 0, sizeof(hist
));
403 for (i
= 0; i
< len
; i
++)
409 for (j
= 0; j
< 2; j
++)
414 for (i
= 2; i
< 256; i
++)
422 * Stop if there are no occurances or character i in the input.
423 * The minimum will never be less than zero.
428 * When looking for the second least frequently used character,
429 * stop scanning if we hit the same minimum as we saw in the first
430 * pass. There will be no smaller values.
432 if ((j
== 1) && (min
== save
[0])) break;
436 save
[j
] = hist
[lfu
[j
]];
437 hist
[lfu
[j
]] = (uint32_t)-1;
440 outlen
= 2 + len
+ save
[0] + save
[1] + 1;
442 str
= malloc(outlen
);
443 if (str
== NULL
) return NULL
;
445 str
[outlen
- 1] = '\0';
452 for (i
= 0; i
< len
; i
++)
462 for (k
= 0; (k
< 2) && (breakit
== 0); k
++)
472 if (breakit
== 1) continue;
481 * asl_core_decode_buffer
482 * decode a string produced by asl_encode_buffer to recreate the original data
485 asl_core_decode_buffer(const char *in
, char **buf
, uint32_t *len
)
488 uint32_t i
, j
, n
, outlen
;
492 if (buf
== NULL
) return -1;
493 if (len
== NULL
) return -1;
500 /* strip trailing nul */
503 /* determine output length and check for invalid input */
504 for (i
= 2; i
< n
; i
++)
510 if (i
== n
) return -1;
513 if ((v
< 1) || (v
> 2)) return -1;
520 if (outlen
== 0) return -1;
522 out
= malloc(outlen
);
523 if (out
== NULL
) return -1;
526 for (i
= 2; i
< n
; i
++)
533 else if (v
== lfu
[1])
537 out
[j
++] = lfu
[v
- 1];
548 #pragma mark time parsing
551 * utility for converting a time string into a time_t
552 * we only deal with the following formats:
553 * dotted form YYYY.MM.DD hh:mm:ss UTC
554 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
555 * absolute form - # seconds since the epoch (e.g. 1095789191)
556 * relative time - seconds before or after now (e.g. -300, +43200)
557 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
558 * ISO8601 - YYYY[-]MM[-]DDTHH[:]MM[:]SS optionally followed by Z or +/-HH[[:]MM]
562 * light(er)-weight replcaement (in place of regex) for asl_core_parse_time
565 #define MFLAG_INCLUDE 0x00000001
566 #define MFLAG_EXCLUDE 0x00000002
568 #define DIGITS "0123456789"
569 #define WHITESPACE " "
571 #define SECONDS_PER_MINUTE 60
572 #define SECONDS_PER_HOUR 3600
573 #define SECONDS_PER_DAY 86400
574 #define SECONDS_PER_WEEK 604800
577 * Match between mincount and maxcount characters in or not in mset.
578 * maxcount == 0 means no limit.
582 asl_core_str_match(const char *target
, const char *mset
, uint32_t mincount
, uint32_t maxcount
, uint32_t flags
, uint32_t *length
)
587 if (length
== NULL
) length
= &n
;
589 if (target
== NULL
) return (mincount
== 0);
591 for (x
= target
, *length
= 0; *x
!= '\0'; x
++, *length
= *length
+ 1)
595 if ((*length
== maxcount
) && (maxcount
> 0)) return true;
596 if (mset
== NULL
) continue;
598 s
= strchr(mset
, *x
);
599 if ((s
== NULL
) && (flags
& MFLAG_EXCLUDE
)) continue;
600 if ((s
!= NULL
) && (flags
& MFLAG_INCLUDE
)) continue;
605 return (*length
>= mincount
);
609 asl_core_str_match_char(const char *target
, const char c
, uint32_t mincount
, uint32_t flags
, uint32_t *length
)
613 if (length
== NULL
) length
= &n
;
616 if (target
== NULL
) return (mincount
== 0);
618 if ((*target
== c
) && (flags
& MFLAG_INCLUDE
)) *length
= 1;
619 if ((*target
!= c
) && (flags
& MFLAG_EXCLUDE
)) *length
= 1;
621 return (*length
>= mincount
);
625 asl_core_str_to_uint32(const char *target
, uint32_t length
)
627 uint32_t i
, d
, out
= 0;
629 for (i
= 0; i
< length
; i
++)
632 out
= (out
* 10) + d
;
639 asl_core_str_match_absolute_or_relative_time(const char *target
, time_t *tval
, uint32_t *tlen
)
642 int32_t val
, sign
= 1;
647 if (target
== NULL
) return false;
651 test
= asl_core_str_match(p
, "+-", 0, 1, MFLAG_INCLUDE
, &len
);
652 if (!test
) return false;
658 if (*p
== '-') sign
= -1;
663 test
= asl_core_str_match(p
, DIGITS
, 1, 0, MFLAG_INCLUDE
, &len
);
664 if (!test
) return false;
665 val
= asl_core_str_to_uint32(p
, len
);
669 test
= asl_core_str_match(p
, "SsMmHhDdWw", 0, 1, MFLAG_INCLUDE
, &len
);
670 if (!test
) return false;
672 if ((*p
== 'M') || (*p
== 'm')) val
*= SECONDS_PER_MINUTE
;
673 else if ((*p
== 'H') || (*p
== 'h')) val
*= SECONDS_PER_HOUR
;
674 else if ((*p
== 'D') || (*p
== 'd')) val
*= SECONDS_PER_DAY
;
675 else if ((*p
== 'W') || (*p
== 'w')) val
*= SECONDS_PER_WEEK
;
677 /* matched string must be followed by space, tab, newline (not counted in length) */
681 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
682 if (!test
) return false;
685 if (tlen
!= NULL
) *tlen
= p
- target
;
686 if (tval
!= NULL
) *tval
= start
+ (sign
* val
);
692 _month_num(const char *s
)
694 if (!strncasecmp(s
, "jan", 3)) return 0;
695 if (!strncasecmp(s
, "feb", 3)) return 1;
696 if (!strncasecmp(s
, "mar", 3)) return 2;
697 if (!strncasecmp(s
, "apr", 3)) return 3;
698 if (!strncasecmp(s
, "may", 3)) return 4;
699 if (!strncasecmp(s
, "jun", 3)) return 5;
700 if (!strncasecmp(s
, "jul", 3)) return 6;
701 if (!strncasecmp(s
, "aug", 3)) return 7;
702 if (!strncasecmp(s
, "sep", 3)) return 8;
703 if (!strncasecmp(s
, "oct", 3)) return 9;
704 if (!strncasecmp(s
, "nov", 3)) return 10;
705 if (!strncasecmp(s
, "dec", 3)) return 11;
711 * Match ctime() format - Mth [D]D [h]h:mm:ss
714 asl_core_str_match_c_time(const char *target
, time_t *tval
, uint32_t *tlen
)
722 if (target
== NULL
) return false;
723 memset(&t
, 0, sizeof(t
));
725 /* determine current date */
727 localtime_r(&now
, &t
);
729 memset(&t
, 0, sizeof(t
));
734 t
.tm_mon
= _month_num(p
);
736 if (t
.tm_mon
== -1) return false;
740 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
741 if (!test
) return false;
745 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
746 if (!test
) return false;
747 t
.tm_mday
= asl_core_str_to_uint32(p
, len
);
748 if (t
.tm_mday
> 31) return false;
752 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
753 if (!test
) return false;
757 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
758 if (!test
) return false;
759 t
.tm_hour
= asl_core_str_to_uint32(p
, len
);
760 if (t
.tm_hour
> 23) return false;
764 if (*p
!= ':') return false;
769 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
770 if (!test
) return false;
771 t
.tm_min
= asl_core_str_to_uint32(p
, len
);
772 if (t
.tm_min
> 59) return false;
776 if (*p
!= ':') return false;
781 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
782 if (!test
) return false;
783 t
.tm_sec
= asl_core_str_to_uint32(p
, len
);
784 if (t
.tm_sec
> 59) return false;
786 /* matched string must be followed by space, tab, newline (not counted in length) */
790 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
791 if (!test
) return false;
796 if (tlen
!= NULL
) *tlen
= p
- target
;
797 if (tval
!= NULL
) *tval
= mktime(&t
);
803 * Match YYYY.[M]M.[D]D [h]h:mm:ss UTC
806 asl_core_str_match_dotted_time(const char *target
, time_t *tval
, uint32_t *tlen
)
813 if (target
== NULL
) return false;
814 memset(&t
, 0, sizeof(t
));
818 test
= asl_core_str_match(p
, DIGITS
, 4, 4, MFLAG_INCLUDE
, &len
);
819 if (!test
) return false;
820 t
.tm_year
= asl_core_str_to_uint32(p
, len
) - 1900;
824 if (*p
!= '.') return false;
829 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
830 if (!test
) return false;
831 t
.tm_mon
= asl_core_str_to_uint32(p
, len
);
832 if (t
.tm_mon
< 1) return false;
833 if (t
.tm_mon
> 12) return false;
838 if (*p
!= '.') return false;
843 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
844 if (!test
) return false;
845 t
.tm_mday
= asl_core_str_to_uint32(p
, len
);
846 if (t
.tm_mday
> 31) return false;
850 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
851 if (!test
) return false;
855 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
856 if (!test
) return false;
857 t
.tm_hour
= asl_core_str_to_uint32(p
, len
);
858 if (t
.tm_hour
> 23) return false;
862 if (*p
!= ':') return false;
867 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
868 if (!test
) return false;
869 t
.tm_min
= asl_core_str_to_uint32(p
, len
);
870 if (t
.tm_min
> 59) return false;
874 if (*p
!= ':') return false;
879 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
880 if (!test
) return false;
881 t
.tm_sec
= asl_core_str_to_uint32(p
, len
);
882 if (t
.tm_sec
> 59) return false;
886 test
= asl_core_str_match(p
, WHITESPACE
, 1, 0, MFLAG_INCLUDE
, &len
);
887 if (!test
) return false;
891 if (strncmp(p
, "UTC", 3)) return false;
894 /* matched string must be followed by space, tab, newline (not counted in length) */
898 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
899 if (!test
) return false;
902 if (tlen
!= NULL
) *tlen
= p
- target
;
903 if (tval
!= NULL
) *tval
= timegm(&t
);
909 * Match YYYY[-]MM[-]DD[Tt]hh[:]hh[:]ss[Zz] or YYYY[-]MM[-]DD[Tt]hh[:]hh[:]ss[+-][H]H[[:]MM]
912 asl_core_str_match_iso_8601_time(const char *target
, time_t *tval
, uint32_t *tlen
)
918 int32_t tzh
, tzs
, sign
= -1;
920 if (target
== NULL
) return false;
921 memset(&t
, 0, sizeof(t
));
925 test
= asl_core_str_match(p
, DIGITS
, 4, 4, MFLAG_INCLUDE
, &len
);
926 if (!test
) return false;
927 t
.tm_year
= asl_core_str_to_uint32(p
, len
) - 1900;
931 test
= asl_core_str_match_char(p
, '-', 0, MFLAG_INCLUDE
, &len
);
932 if (!test
) return false;
936 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
937 if (!test
) return false;
938 t
.tm_mon
= asl_core_str_to_uint32(p
, len
);
939 if (t
.tm_mon
< 1) return false;
940 if (t
.tm_mon
> 12) return false;
945 test
= asl_core_str_match_char(p
, '-', 0, MFLAG_INCLUDE
, &len
);
946 if (!test
) return false;
950 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
951 if (!test
) return false;
952 t
.tm_mday
= asl_core_str_to_uint32(p
, len
);
953 if (t
.tm_mday
> 31) return false;
957 test
= asl_core_str_match(p
, "Tt", 1, 1, MFLAG_INCLUDE
, &len
);
958 if (!test
) return false;
962 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
963 if (!test
) return false;
964 t
.tm_hour
= asl_core_str_to_uint32(p
, len
);
965 if (t
.tm_hour
> 23) return false;
969 test
= asl_core_str_match_char(p
, ':', 0, MFLAG_INCLUDE
, &len
);
970 if (!test
) return false;
974 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
975 if (!test
) return false;
976 t
.tm_min
= asl_core_str_to_uint32(p
, len
);
977 if (t
.tm_min
> 59) return false;
981 test
= asl_core_str_match_char(p
, ':', 0, MFLAG_INCLUDE
, &len
);
982 if (!test
) return false;
986 test
= asl_core_str_match(p
, DIGITS
, 2, 2, MFLAG_INCLUDE
, &len
);
987 if (!test
) return false;
988 t
.tm_sec
= asl_core_str_to_uint32(p
, len
);
989 if (t
.tm_sec
> 59) return false;
993 /* default to local time if we hit the end of the string */
994 if ((*p
== '\0') || (*p
== ' ') || (*p
== '\t') || (*p
== '\n'))
998 if (tlen
!= NULL
) *tlen
= p
- target
;
999 if (tval
!= NULL
) *tval
= mktime(&t
);
1005 test
= asl_core_str_match(p
, "Zz+-", 1, 1, MFLAG_INCLUDE
, &len
);
1006 if (!test
) return false;
1008 if ((*p
== 'Z') || (*p
== 'z'))
1010 /* matched string must be followed by space, tab, newline (not counted in length) */
1014 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
1015 if (!test
) return false;
1018 if (tlen
!= NULL
) *tlen
= p
- target
;
1019 if (tval
!= NULL
) *tval
= timegm(&t
);
1024 if (*p
== '-') sign
= 1;
1028 test
= asl_core_str_match(p
, DIGITS
, 1, 2, MFLAG_INCLUDE
, &len
);
1029 if (!test
) return false;
1030 tzh
= asl_core_str_to_uint32(p
, len
);
1031 if (tzh
> 23) return false;
1035 test
= asl_core_str_match_char(p
, ':', 0, MFLAG_INCLUDE
, &len
);
1036 if (!test
) return false;
1040 test
= asl_core_str_match(p
, DIGITS
, 0, 2, MFLAG_INCLUDE
, &len
);
1041 if (!test
) return false;
1042 tzs
= asl_core_str_to_uint32(p
, len
);
1043 if (tzs
> 59) return false;
1045 t
.tm_sec
+= (sign
* (tzh
* SECONDS_PER_HOUR
) + (tzs
* SECONDS_PER_MINUTE
));
1047 /* matched string must be followed by space, tab, newline (not counted in length) */
1051 test
= asl_core_str_match(p
, " \t\n", 1, 1, MFLAG_INCLUDE
, &len
);
1052 if (!test
) return false;
1055 if (tlen
!= NULL
) *tlen
= p
- target
;
1056 if (tval
!= NULL
) *tval
= timegm(&t
);
1062 asl_core_parse_time(const char *in
, uint32_t *tlen
)
1067 if (tlen
!= NULL
) *tlen
= 0;
1069 if (in
== NULL
) return -1;
1072 * Heuristics to determine the string format.
1073 * Warning: this code must be checked and may need to be adjusted if new formats are added.
1076 if (inlen
== 0) return -1;
1078 /* leading plus or minus means it must be a relative time */
1079 if ((in
[0] == '+') || (in
[0] == '-'))
1081 if (asl_core_str_match_absolute_or_relative_time(in
, &tval
, tlen
)) return tval
;
1085 /* leading alphabetic char means it must be ctime() format */
1086 if (((in
[0] >= 'a') && (in
[0] <= 'z')) || ((in
[0] >= 'A') && (in
[0] <= 'Z')))
1088 if (asl_core_str_match_c_time(in
, &tval
, tlen
)) return tval
;
1092 /* only absolute, dotted, or iso8601 formats at this point */
1094 /* one to for chars means it must be absolute */
1097 if (asl_core_str_match_absolute_or_relative_time(in
, &tval
, tlen
)) return tval
;
1104 if (asl_core_str_match_dotted_time(in
, &tval
, tlen
)) return tval
;
1108 /* only absolute or iso8601 at this point */
1110 /* check for absolute first, since that's quicker */
1111 if (asl_core_str_match_absolute_or_relative_time(in
, &tval
, tlen
)) return tval
;
1113 if (asl_core_str_match_iso_8601_time(in
, &tval
, tlen
)) return tval
;
1119 * asl_parse_time is old SPI used all over the place.
1122 asl_parse_time(const char *in
)
1124 return asl_core_parse_time(in
, NULL
);