]> git.saurik.com Git - apple/libc.git/blob - gen/asl.c
9da93151229951a73ca5a30a2486dbf6cc04ed01
[apple/libc.git] / gen / asl.c
1 /*
2 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <string.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31 #include <syslog.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <time.h>
35 #include <sys/time.h>
36 #include <sys/fcntl.h>
37 #include <crt_externs.h>
38 #include <asl.h>
39 #include <regex.h>
40 #include <notify.h>
41 #include <mach/mach.h>
42 #include <mach/std_types.h>
43 #include <mach/mig.h>
44 #include <mach/mach_types.h>
45 #include <sys/types.h>
46 #include <servers/bootstrap.h>
47 #include <pthread.h>
48 #include <dispatch/dispatch.h>
49 #include <asl_ipc.h>
50 #include "asl_core.h"
51 #include "asl_msg.h"
52 #include "asl_store.h"
53 #include "asl_private.h"
54
55 #define streq(A, B) (strcmp(A, B) == 0)
56 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
57
58 #define forever for(;;)
59
60 #define FETCH_BATCH 256
61
62 /* forward */
63 time_t asl_parse_time(const char *);
64 const char *asl_syslog_faciliy_num_to_name(int n);
65 __private_extern__ int _asl_send_message(aslclient ac, asl_msg_t *msg, int slevel, const char *aux_message);
66 __private_extern__ asl_client_t *_asl_open_default();
67
68 /* private asl_msg SPI */
69 __private_extern__ uint32_t _asl_msg_string_length_aux(asl_msg_t *msg, asl_msg_aux_t *aux);
70 __private_extern__ uint32_t _asl_msg_to_string_buffer_aux(asl_msg_t *msg, asl_msg_aux_t *aux, char *buf, uint32_t bufsize);
71
72 /* private asl_file SPI */
73 __private_extern__ uint32_t asl_file_open_write_fd(int fd, asl_file_t **s);
74
75 /* notify SPI */
76 uint32_t notify_register_plain(const char *name, int *out_token);
77
78 /* fork handling in syslog.c */
79 extern void _syslog_fork_child();
80
81 typedef struct
82 {
83 int fd;
84 asl_msg_t *msg;
85 dispatch_semaphore_t sem;
86 } asl_aux_context_t;
87
88 typedef struct
89 {
90 int notify_count;
91 int rc_change_token;
92 int notify_token;
93 int master_token;
94 uint64_t proc_filter;
95 uint64_t master_filter;
96 dispatch_once_t port_lookup_once;
97 mach_port_t server_port;
98 char *sender;
99 pthread_mutex_t lock;
100 int aux_count;
101 asl_aux_context_t **aux_ctx;
102 asl_client_t *asl;
103 } _asl_global_t;
104
105
106 #ifndef BUILDING_VARIANT
107 __private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL};
108
109 #define ASL_SERVICE_NAME "com.apple.system.logger"
110
111 /*
112 * Called from the child process inside fork() to clean up
113 * inherited state from the parent process.
114 *
115 * NB. A lock isn't required, since we're single threaded in this call.
116 */
117 __private_extern__ void
118 _asl_fork_child()
119 {
120 _asl_global.notify_count = 0;
121 _asl_global.rc_change_token = -1;
122 _asl_global.master_token = -1;
123 _asl_global.notify_token = -1;
124
125 _asl_global.port_lookup_once = 0;
126 _asl_global.server_port = MACH_PORT_NULL;
127 }
128
129 /*
130 * asl_remote_notify_name: returns the notification key for remote-control filter
131 * changes for this process.
132 */
133 char *
134 asl_remote_notify_name()
135 {
136 pid_t pid = getpid();
137 uid_t euid = geteuid();
138 char *str = NULL;
139
140 if (euid == 0) asprintf(&str, "%s.%d", NOTIFY_PREFIX_SYSTEM, pid);
141 else asprintf(&str, "user.uid.%d.syslog.%d", euid, pid);
142
143 return str;
144 }
145
146 static int
147 _asl_notify_open(int do_lock)
148 {
149 char *notify_name;
150 uint32_t status;
151
152 if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
153
154 _asl_global.notify_count++;
155
156 if (_asl_global.notify_token != -1)
157 {
158 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
159 return 0;
160 }
161
162 if (_asl_global.rc_change_token == -1)
163 {
164 status = notify_register_check(NOTIFY_RC, &_asl_global.rc_change_token);
165 if (status != NOTIFY_STATUS_OK) _asl_global.rc_change_token = -1;
166 }
167
168 if (_asl_global.master_token == -1)
169 {
170 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_asl_global.master_token);
171 if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
172 }
173
174 notify_name = asl_remote_notify_name();
175 if (notify_name != NULL)
176 {
177 status = notify_register_plain(notify_name, &_asl_global.notify_token);
178 free(notify_name);
179 if (status != NOTIFY_STATUS_OK) _asl_global.notify_token = -1;
180 }
181
182 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
183
184 if (_asl_global.notify_token == -1) return -1;
185 return 0;
186 }
187
188 static void
189 _asl_notify_close()
190 {
191 pthread_mutex_lock(&_asl_global.lock);
192
193 if (_asl_global.notify_count > 0) _asl_global.notify_count--;
194
195 if (_asl_global.notify_count > 0)
196 {
197 pthread_mutex_unlock(&_asl_global.lock);
198 return;
199 }
200
201 if (_asl_global.rc_change_token >= 0) notify_cancel(_asl_global.rc_change_token);
202 _asl_global.rc_change_token = -1;
203
204 if (_asl_global.master_token >= 0) notify_cancel(_asl_global.master_token);
205 _asl_global.master_token = -1;
206
207 if (_asl_global.notify_token >= 0) notify_cancel(_asl_global.notify_token);
208 _asl_global.notify_token = -1;
209
210 pthread_mutex_unlock(&_asl_global.lock);
211 }
212
213 static void
214 _asl_global_init()
215 {
216 dispatch_once(&_asl_global.port_lookup_once, ^{
217 char *str = getenv("ASL_DISABLE");
218 if ((str == NULL) || strcmp(str, "1"))
219 {
220 bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &_asl_global.server_port);
221 }
222 });
223 }
224
225 aslclient
226 asl_open(const char *ident, const char *facility, uint32_t opts)
227 {
228 char *name, *x;
229 asl_client_t *asl;
230
231 asl = (asl_client_t *)calloc(1, sizeof(asl_client_t));
232 if (asl == NULL)
233 {
234 errno = ENOMEM;
235 return NULL;
236 }
237
238 asl->options = opts;
239
240 asl->sock = -1;
241
242 _asl_global_init();
243
244 asl->pid = getpid();
245 asl->uid = getuid();
246 asl->gid = getgid();
247
248 asl->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
249
250 if (ident != NULL)
251 {
252 asl->name = strdup(ident);
253 if (asl->name == NULL)
254 {
255 if (asl->sock >= 0) close(asl->sock);
256 free(asl);
257 return NULL;
258 }
259 }
260 else
261 {
262 name = *(*_NSGetArgv());
263 if (name != NULL)
264 {
265 x = strrchr(name, '/');
266 if (x != NULL) x++;
267 else x = name;
268 asl->name = strdup(x);
269 if (asl->name == NULL)
270 {
271 if (asl->sock >= 0) close(asl->sock);
272 free(asl);
273 return NULL;
274 }
275 }
276 }
277
278 asl->facility = NULL;
279 if (facility != NULL) asl->facility = strdup(facility);
280 else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER));
281 if (asl->facility == NULL)
282 {
283 if (asl->sock >= 0) close(asl->sock);
284 if (asl->name != NULL) free(asl->name);
285 free(asl);
286 return NULL;
287 }
288
289 if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
290
291 if (asl->options & ASL_OPT_STDERR) asl_add_output((aslclient)asl, fileno(stderr), ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE);
292
293 return (aslclient)asl;
294 }
295
296 aslclient
297 asl_open_from_file(int fd, const char *ident, const char *facility)
298 {
299 char *name, *x;
300 asl_client_t *asl;
301 uint32_t status;
302
303 asl = (asl_client_t *)calloc(1, sizeof(asl_client_t));
304 if (asl == NULL)
305 {
306 errno = ENOMEM;
307 return NULL;
308 }
309
310 asl->options = ASL_OPT_NO_REMOTE;
311 asl->sock = -1;
312
313 asl->pid = getpid();
314 asl->uid = getuid();
315 asl->gid = getgid();
316
317 asl->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
318
319 if (ident != NULL)
320 {
321 asl->name = strdup(ident);
322 if (asl->name == NULL)
323 {
324 free(asl);
325 return NULL;
326 }
327 }
328 else
329 {
330 name = *(*_NSGetArgv());
331 if (name != NULL)
332 {
333 x = strrchr(name, '/');
334 if (x != NULL) x++;
335 else x = name;
336 asl->name = strdup(x);
337 if (asl->name == NULL)
338 {
339 free(asl);
340 return NULL;
341 }
342 }
343 }
344
345 asl->facility = NULL;
346 if (facility != NULL) asl->facility = strdup(facility);
347 else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER));
348 if (asl->facility == NULL)
349 {
350 if (asl->name != NULL) free(asl->name);
351 free(asl);
352 return NULL;
353 }
354
355 status = asl_file_open_write_fd(fd, &(asl->aslfile));
356 if (status != ASL_STATUS_OK)
357 {
358 if (asl->name != NULL) free(asl->name);
359 if (asl->facility != NULL) free(asl->facility);
360 free(asl);
361 return NULL;
362 }
363
364 asl->aslfileid = 1;
365
366 return (aslclient)asl;
367 }
368
369 void
370 asl_close(aslclient ac)
371 {
372 asl_client_t *asl;
373 uint32_t i;
374
375 asl = (asl_client_t *)ac;
376 if (asl == NULL) return;
377
378 free(asl->name);
379 free(asl->facility);
380
381 if (asl->sock >= 0) close(asl->sock);
382 if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_close();
383 if (asl->fd_list != NULL) free(asl->fd_list);
384
385 if (asl->fd_mfmt != NULL)
386 {
387 for (i = 0; i < asl->fd_count; i++) if (asl->fd_mfmt[i] != NULL) free(asl->fd_mfmt[i]);
388 free(asl->fd_mfmt);
389 }
390
391 if (asl->fd_tfmt != NULL)
392 {
393 for (i = 0; i < asl->fd_count; i++) if (asl->fd_tfmt[i] != NULL) free(asl->fd_tfmt[i]);
394 free(asl->fd_tfmt);
395 }
396
397 if (asl->fd_encoding != NULL) free(asl->fd_encoding);
398
399 memset(asl, 0, sizeof(asl_client_t));
400 free(asl);
401 }
402
403 __private_extern__ asl_client_t *
404 _asl_open_default()
405 {
406 static dispatch_once_t once;
407
408 dispatch_once(&once, ^{
409 /*
410 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
411 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
412 * which locks _asl_global.lock.
413 */
414 _asl_global.asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
415
416 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
417 if (_asl_global.asl != NULL) _asl_global.asl->options = 0;
418
419 /* Now call _asl_notify_open(0) to finish the work */
420 _asl_notify_open(0);
421 });
422
423 return _asl_global.asl;
424 }
425
426 /*
427 * asl_add_file: write log messages to the given file descriptor
428 * Log messages will be written to this file as well as to the server.
429 */
430 int
431 asl_add_output(aslclient ac, int fd, const char *mfmt, const char *tfmt, uint32_t text_encoding)
432 {
433 uint32_t i;
434 int use_global_lock;
435 asl_client_t *asl;
436
437 use_global_lock = 0;
438 asl = (asl_client_t *)ac;
439 if (asl == NULL)
440 {
441 asl = _asl_open_default();
442 if (asl == NULL) return -1;
443 pthread_mutex_lock(&_asl_global.lock);
444 use_global_lock = 1;
445 }
446
447 for (i = 0; i < asl->fd_count; i++)
448 {
449 if (asl->fd_list[i] == fd)
450 {
451 /* update message format, time format, and text encoding */
452 if (asl->fd_mfmt[i] != NULL) free(asl->fd_mfmt[i]);
453 asl->fd_mfmt[i] = NULL;
454 if (mfmt != NULL) asl->fd_mfmt[i] = strdup(mfmt);
455
456 if (asl->fd_tfmt[i] != NULL) free(asl->fd_tfmt[i]);
457 asl->fd_tfmt[i] = NULL;
458 if (tfmt != NULL) asl->fd_tfmt[i] = strdup(tfmt);
459
460 asl->fd_encoding[i] = text_encoding;
461
462 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
463 return 0;
464 }
465 }
466
467 if (asl->fd_count == 0)
468 {
469 asl->fd_list = (int *)calloc(1, sizeof(int));
470 asl->fd_mfmt = (char **)calloc(1, sizeof(char *));
471 asl->fd_tfmt = (char **)calloc(1, sizeof(char *));
472 asl->fd_encoding = (uint32_t *)calloc(1, sizeof(int));
473 }
474 else
475 {
476 asl->fd_list = (int *)reallocf(asl->fd_list, (1 + asl->fd_count) * sizeof(int));
477 asl->fd_mfmt = (char **)reallocf(asl->fd_mfmt, (1 + asl->fd_count) * sizeof(char *));
478 asl->fd_tfmt = (char **)reallocf(asl->fd_tfmt, (1 + asl->fd_count) * sizeof(char *));
479 asl->fd_encoding = (uint32_t *)reallocf(asl->fd_encoding, (1 + asl->fd_count) * sizeof(uint32_t));
480 }
481
482 if ((asl->fd_list == NULL) || (asl->fd_mfmt == NULL) || (asl->fd_tfmt == NULL) || (asl->fd_encoding == NULL))
483 {
484 if (asl->fd_list != NULL) free(asl->fd_list);
485 if (asl->fd_mfmt != NULL) free(asl->fd_mfmt);
486 if (asl->fd_tfmt != NULL) free(asl->fd_tfmt);
487 if (asl->fd_encoding != NULL) free(asl->fd_encoding);
488
489 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
490 return -1;
491 }
492
493 asl->fd_list[asl->fd_count] = fd;
494 if (mfmt != NULL) asl->fd_mfmt[asl->fd_count] = strdup(mfmt);
495 if (tfmt != NULL) asl->fd_tfmt[asl->fd_count] = strdup(tfmt);
496 asl->fd_encoding[asl->fd_count] = text_encoding;
497
498 asl->fd_count++;
499
500 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
501 return 0;
502 }
503
504 int
505 asl_add_log_file(aslclient ac, int fd)
506 {
507 return asl_add_output(ac, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE);
508 }
509
510 /*
511 * asl_remove_output: stop writing log messages to the given file descriptor
512 */
513 int
514 asl_remove_output(aslclient ac, int fd)
515 {
516 uint32_t i;
517 int x, use_global_lock;
518 asl_client_t *asl;
519
520 use_global_lock = 0;
521 asl = (asl_client_t *)ac;
522 if (asl == NULL)
523 {
524 asl = _asl_open_default();
525 if (asl == NULL) return -1;
526 pthread_mutex_lock(&_asl_global.lock);
527 use_global_lock = 1;
528 }
529
530 if (asl->fd_count == 0)
531 {
532 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
533 return 0;
534 }
535
536 x = -1;
537 for (i = 0; i < asl->fd_count; i++)
538 {
539 if (asl->fd_list[i] == fd)
540 {
541 x = i;
542 break;
543 }
544 }
545
546 if (x == -1)
547 {
548 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
549 return 0;
550 }
551
552 if (asl->fd_mfmt[x] != NULL) free(asl->fd_mfmt[x]);
553 if (asl->fd_tfmt[x] != NULL) free(asl->fd_tfmt[x]);
554
555 for (i = x + 1; i < asl->fd_count; i++, x++)
556 {
557 asl->fd_list[x] = asl->fd_list[i];
558 asl->fd_mfmt[x] = asl->fd_mfmt[i];
559 asl->fd_tfmt[x] = asl->fd_tfmt[i];
560 asl->fd_encoding[x] = asl->fd_encoding[i];
561 }
562
563 asl->fd_count--;
564
565 if (asl->fd_count == 0)
566 {
567 free(asl->fd_list);
568 asl->fd_list = NULL;
569
570 free(asl->fd_mfmt);
571 asl->fd_mfmt = NULL;
572
573 free(asl->fd_tfmt);
574 asl->fd_tfmt = NULL;
575
576 free(asl->fd_encoding);
577 asl->fd_encoding = NULL;
578 }
579 else
580 {
581 asl->fd_list = (int *)reallocf(asl->fd_list, asl->fd_count * sizeof(int));
582 asl->fd_mfmt = (char **)reallocf(asl->fd_mfmt, asl->fd_count * sizeof(char *));
583 asl->fd_tfmt = (char **)reallocf(asl->fd_tfmt, asl->fd_count * sizeof(char *));
584 asl->fd_encoding = (uint32_t *)reallocf(asl->fd_encoding, asl->fd_count * sizeof(uint32_t));
585
586 if ((asl->fd_list == NULL) || (asl->fd_mfmt == NULL) || (asl->fd_tfmt == NULL) || (asl->fd_encoding == NULL))
587 {
588 if (asl->fd_list != NULL)
589 {
590 free(asl->fd_list);
591 asl->fd_list = NULL;
592 }
593
594 if (asl->fd_mfmt != NULL)
595 {
596 for (i = 0; i < asl->fd_count; i++) if (asl->fd_mfmt[i] != NULL) free(asl->fd_mfmt[i]);
597 free(asl->fd_mfmt);
598 asl->fd_mfmt = NULL;
599 }
600
601 if (asl->fd_tfmt != NULL)
602 {
603 for (i = 0; i < asl->fd_count; i++) if (asl->fd_tfmt[i] != NULL) free(asl->fd_tfmt[i]);
604 free(asl->fd_tfmt);
605 asl->fd_tfmt = NULL;
606 }
607
608 if (asl->fd_encoding != NULL)
609 {
610 free(asl->fd_encoding);
611 asl->fd_encoding = NULL;
612 }
613
614 asl->fd_count = 0;
615 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
616 return -1;
617 }
618 }
619
620 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
621 return 0;
622 }
623
624 int
625 asl_remove_log_file(aslclient ac, int fd)
626 {
627 return asl_remove_output(ac, fd);
628 }
629
630 int
631 asl_set_filter(aslclient ac, int f)
632 {
633 int last, use_global_lock;
634 asl_client_t *asl;
635
636 use_global_lock = 0;
637 asl = (asl_client_t *)ac;
638 if (asl == NULL)
639 {
640 asl = _asl_open_default();
641 if (asl == NULL) return -1;
642 pthread_mutex_lock(&_asl_global.lock);
643 use_global_lock = 1;
644 }
645
646 last = asl->filter;
647 asl->filter = f;
648
649 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
650 return last;
651 }
652
653 #endif /* BUILDING_VARIANT */
654
655 /*
656 * asl_vlog: Similar to asl_log, but taking a va_list instead of a list of
657 * arguments.
658 * msg: an aslmsg
659 * level: the log level of the associated message
660 * format: A formating string followed by a list of arguments, like vprintf()
661 * returns 0 for success, non-zero for failure
662 */
663 int
664 asl_vlog(aslclient ac, aslmsg msg, int level, const char *format, va_list ap)
665 {
666 int saved_errno = errno;
667 int status;
668 char *str, *fmt, estr[NL_TEXTMAX];
669 uint32_t i, len, elen, expand;
670 asl_client_t *asl;
671
672 asl = (asl_client_t *)ac;
673 if (asl == NULL)
674 {
675 /*
676 * Initialize _asl_global so that asl_new will have global data.
677 * Not strictly necessary, but helps performance.
678 */
679 asl = _asl_open_default();
680 if (asl == NULL) return -1;
681 }
682
683 if (format == NULL) return -1;
684
685 /* insert strerror for %m */
686 len = 0;
687 elen = 0;
688
689 expand = 0;
690 for (i = 0; format[i] != '\0'; i++)
691 {
692 if (format[i] == '%')
693 {
694 if (format[i+1] == '\0') len++;
695 else if (format[i+1] == 'm')
696 {
697 expand = 1;
698 strerror_r(saved_errno, estr, sizeof(estr));
699 elen = strlen(estr);
700 len += elen;
701 i++;
702 }
703 else
704 {
705 len += 2;
706 i++;
707 }
708 }
709 else len++;
710 }
711
712 fmt = (char *)format;
713
714 if (expand != 0)
715 {
716 fmt = malloc(len + 1);
717 if (fmt == NULL)
718 {
719 if (estr != NULL) free(estr);
720 return -1;
721 }
722
723 len = 0;
724
725 for (i = 0; format[i] != '\0'; i++)
726 {
727 if (format[i] == '%')
728 {
729 if (format[i+1] == '\0')
730 {
731 }
732 else if ((format[i+1] == 'm') && (elen != 0))
733 {
734 memcpy(fmt+len, estr, elen);
735 len += elen;
736 i++;
737 }
738 else
739 {
740 fmt[len++] = format[i++];
741 fmt[len++] = format[i];
742 }
743 }
744 else fmt[len++] = format[i];
745 }
746
747 fmt[len] = '\0';
748 }
749
750 vasprintf(&str, fmt, ap);
751 if (expand != 0) free(fmt);
752
753 if (str == NULL) return -1;
754
755 status = _asl_send_message(ac, (asl_msg_t *)msg, level, str);
756 free(str);
757
758 return status;
759 }
760
761 /*
762 * asl_log: log a message with a particular log level
763 * msg: an aslmsg
764 * level: the log level
765 * format: A formating string followed by a list of arguments, like printf()
766 * returns 0 for success, non-zero for failure
767 */
768 int
769 asl_log(aslclient ac, aslmsg a, int level, const char *format, ...)
770 {
771 va_list ap;
772 int status;
773
774 if (format == NULL) return -1;
775
776 va_start(ap, format);
777 status = asl_vlog(ac, a, level, format, ap);
778 va_end(ap);
779
780 return status;
781 }
782
783 #ifndef BUILDING_VARIANT
784
785 static asl_msg_t *
786 _asl_merge_msg_aux0(asl_msg_t *msg, asl_msg_aux_0_t aux0)
787 {
788 const char *key, *val;
789 asl_msg_t *out;
790 uint32_t x;
791 int klevel, ktime, knano, khost, ksender, kfac, kpid, kuid, kgid, kmsg, kaux, kuti, kurl;
792
793 out = asl_msg_new(ASL_TYPE_MSG);
794 if (out == NULL) return NULL;
795
796 klevel = 0;
797 ktime = 0;
798 knano = 0;
799 khost = 0;
800 ksender= 0;
801 kfac = 0;
802 kpid = 0;
803 kuid = 0;
804 kgid = 0;
805 kmsg = 0;
806 kaux = 0;
807 kuti = 0;
808 kurl = 0;
809
810 key = NULL;
811 val = NULL;
812
813 for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
814 {
815 if (streq(key, ASL_KEY_LEVEL))
816 {
817 klevel = 1;
818 if (aux0.level != NULL) asl_msg_set_key_val(out, key, aux0.level);
819 else asl_msg_set_key_val(out, key, val);
820 }
821 else if (streq(key, ASL_KEY_TIME))
822 {
823 ktime = 1;
824 if (aux0.time != NULL) asl_msg_set_key_val(out, key, aux0.time);
825 else asl_msg_set_key_val(out, key, val);
826 }
827 else if (streq(key, ASL_KEY_TIME_NSEC))
828 {
829 knano = 1;
830 if (aux0.nano != NULL) asl_msg_set_key_val(out, key, aux0.nano);
831 else asl_msg_set_key_val(out, key, val);
832 }
833 else if (streq(key, ASL_KEY_HOST))
834 {
835 khost = 1;
836 if (aux0.host != NULL) asl_msg_set_key_val(out, key, aux0.host);
837 else asl_msg_set_key_val(out, key, val);
838 }
839 else if (streq(key, ASL_KEY_SENDER))
840 {
841 ksender = 1;
842 if (aux0.sender != NULL) asl_msg_set_key_val(out, key, aux0.sender);
843 else asl_msg_set_key_val(out, key, val);
844 }
845 else if (streq(key, ASL_KEY_FACILITY))
846 {
847 kfac = 1;
848 if (aux0.facility != NULL) asl_msg_set_key_val(out, key, aux0.facility);
849 else asl_msg_set_key_val(out, key, val);
850 }
851 else if (streq(key, ASL_KEY_PID))
852 {
853 kpid = 1;
854 if (aux0.pid != NULL) asl_msg_set_key_val(out, key, aux0.pid);
855 else asl_msg_set_key_val(out, key, val);
856 }
857 else if (streq(key, ASL_KEY_UID))
858 {
859 kuid = 1;
860 if (aux0.uid != NULL) asl_msg_set_key_val(out, key, aux0.uid);
861 else asl_msg_set_key_val(out, key, val);
862 }
863 else if (streq(key, ASL_KEY_GID))
864 {
865 kgid = 1;
866 if (aux0.gid != NULL) asl_msg_set_key_val(out, key, aux0.gid);
867 else asl_msg_set_key_val(out, key, val);
868 }
869 else if (streq(key, ASL_KEY_MSG))
870 {
871 kmsg = 1;
872 if (aux0.message != NULL) asl_msg_set_key_val(out, key, aux0.message);
873 else asl_msg_set_key_val(out, key, val);
874 }
875 else if (streq(key, ASL_KEY_AUX_TITLE))
876 {
877 kaux = 1;
878 if (aux0.auxtitle != NULL) asl_msg_set_key_val(out, key, aux0.auxtitle);
879 else asl_msg_set_key_val(out, key, val);
880 }
881 else if (streq(key, ASL_KEY_AUX_UTI))
882 {
883 kuti = 1;
884 if (aux0.auxuti != NULL) asl_msg_set_key_val(out, key, aux0.auxuti);
885 else asl_msg_set_key_val(out, key, val);
886 }
887 else if (streq(key, ASL_KEY_AUX_URL))
888 {
889 kurl = 1;
890 if (aux0.auxurl != NULL) asl_msg_set_key_val(out, key, aux0.auxurl);
891 else asl_msg_set_key_val(out, key, val);
892 }
893 else
894 {
895 asl_msg_set_key_val(out, key, val);
896 }
897 }
898
899 if ((klevel == 0) && (aux0.level != NULL)) asl_msg_set_key_val(out, ASL_KEY_LEVEL, aux0.level);
900 if ((ktime == 0) && (aux0.time != NULL)) asl_msg_set_key_val(out, ASL_KEY_TIME, aux0.time);
901 if ((knano == 0) && (aux0.nano != NULL)) asl_msg_set_key_val(out, ASL_KEY_TIME_NSEC, aux0.nano);
902 if ((khost == 0) && (aux0.host != NULL)) asl_msg_set_key_val(out, ASL_KEY_HOST, aux0.host);
903 if ((ksender == 0) && (aux0.sender != NULL)) asl_msg_set_key_val(out, ASL_KEY_SENDER, aux0.sender);
904 if ((kfac == 0) && (aux0.facility != NULL)) asl_msg_set_key_val(out, ASL_KEY_FACILITY, aux0.facility);
905 if ((kpid == 0) && (aux0.pid != NULL)) asl_msg_set_key_val(out, ASL_KEY_PID, aux0.pid);
906 if ((kuid == 0) && (aux0.uid != NULL)) asl_msg_set_key_val(out, ASL_KEY_UID, aux0.uid);
907 if ((kgid == 0) && (aux0.gid != NULL)) asl_msg_set_key_val(out, ASL_KEY_GID, aux0.gid);
908 if ((kmsg == 0) && (aux0.message != NULL)) asl_msg_set_key_val(out, ASL_KEY_MSG, aux0.message);
909 if ((kaux == 0) && (aux0.auxtitle != NULL)) asl_msg_set_key_val(out, ASL_KEY_AUX_TITLE, aux0.auxtitle);
910 if ((kuti == 0) && (aux0.auxuti != NULL)) asl_msg_set_key_val(out, ASL_KEY_AUX_UTI, aux0.auxuti);
911 if ((kurl == 0) && (aux0.auxurl != NULL)) asl_msg_set_key_val(out, ASL_KEY_AUX_URL, aux0.auxurl);
912
913 return out;
914 }
915
916 /*
917 * asl_get_filter: gets the values for the local, master, and remote filters,
918 * and indicates which one is active.
919 */
920 int
921 asl_get_filter(aslclient ac, int *local, int *master, int *remote, int *active)
922 {
923 asl_client_t *asl, *asl_default;
924 int l, m, r, x;
925 int status, check;
926 uint64_t v64;
927
928 l = 0;
929 m = 0;
930 r = 0;
931 x = 0;
932
933 asl_default = _asl_open_default();
934
935 asl = (asl_client_t *)ac;
936 if (asl == NULL) asl = asl_default;
937 if (asl != NULL) l = asl->filter & 0xff;
938
939 if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
940 {
941 pthread_mutex_lock(&_asl_global.lock);
942
943 if (_asl_global.rc_change_token >= 0)
944 {
945 /* initialize or re-check process-specific and master filters */
946 check = 0;
947 status = notify_check(_asl_global.rc_change_token, &check);
948 if ((status == NOTIFY_STATUS_OK) && (check != 0))
949 {
950 if (_asl_global.master_token >= 0)
951 {
952 v64 = 0;
953 status = notify_get_state(_asl_global.master_token, &v64);
954 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
955 }
956
957 if (_asl_global.notify_token >= 0)
958 {
959 v64 = 0;
960 status = notify_get_state(_asl_global.notify_token, &v64);
961 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
962 }
963 }
964 }
965
966 m = _asl_global.master_filter;
967 if (m != 0) x = 1;
968
969 r = _asl_global.proc_filter;
970 if (r != 0) x = 2;
971
972 pthread_mutex_unlock(&_asl_global.lock);
973 }
974
975 if (local != NULL) *local = l;
976 if (master != NULL) *master = m;
977 if (remote != NULL) *remote = r;
978 if (active != NULL) *active = x;
979
980 return 0;
981 }
982
983 /*
984 * asl_send: send a message
985 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
986 * has been used to set all of a message's attributes.
987 * msg: an aslmsg
988 * returns 0 for success, non-zero for failure
989 */
990 __private_extern__ int
991 _asl_send_message(aslclient ac, asl_msg_t *msg, int slevel, const char *aux_message)
992 {
993 vm_address_t out;
994 uint32_t i, len, outlen, level, lmask, outstatus, filter, fd_write;
995 uint64_t v64;
996 const char *val;
997 char *name, *x, *str;
998 time_t tick;
999 struct timeval tval;
1000 int status, check, tunnel;
1001 asl_client_t *asl;
1002 int use_global_lock;
1003 kern_return_t kstatus;
1004 char aux_level[64], aux_time[64], aux_nano[64], aux_pid[64], aux_uid[64], aux_gid[64];
1005 char *aux_option, aux_host[_POSIX_HOST_NAME_MAX];
1006 asl_msg_aux_t aux;
1007 asl_msg_aux_0_t aux0;
1008
1009 use_global_lock = 0;
1010 asl = (asl_client_t *)ac;
1011 if (asl == NULL)
1012 {
1013 asl = _asl_open_default();
1014 if (asl == NULL) return -1;
1015 use_global_lock = 1;
1016 }
1017
1018 if (asl->aslfile != NULL)
1019 {
1020 use_global_lock = 1;
1021 }
1022
1023 level = ASL_LEVEL_DEBUG;
1024 if (slevel >= 0) level = slevel;
1025
1026 val = asl_get((aslmsg)msg, ASL_KEY_LEVEL);
1027 if (val != NULL)
1028 {
1029 check = atoi(val);
1030 if (check < ASL_LEVEL_EMERG) check = ASL_LEVEL_EMERG;
1031 else if (check > ASL_LEVEL_DEBUG) check = ASL_LEVEL_DEBUG;
1032 level = check;
1033 }
1034
1035 lmask = ASL_FILTER_MASK(level);
1036
1037 if (!(asl->options & ASL_OPT_NO_REMOTE))
1038 {
1039 pthread_mutex_lock(&_asl_global.lock);
1040
1041 if (_asl_global.rc_change_token >= 0)
1042 {
1043 /* initialize or re-check process-specific and master filters */
1044 check = 0;
1045 status = notify_check(_asl_global.rc_change_token, &check);
1046 if ((status == NOTIFY_STATUS_OK) && (check != 0))
1047 {
1048 if (_asl_global.master_token >= 0)
1049 {
1050 v64 = 0;
1051 status = notify_get_state(_asl_global.master_token, &v64);
1052 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
1053 }
1054
1055 if (_asl_global.notify_token >= 0)
1056 {
1057 v64 = 0;
1058 status = notify_get_state(_asl_global.notify_token, &v64);
1059 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
1060 }
1061 }
1062 }
1063
1064 pthread_mutex_unlock(&_asl_global.lock);
1065 }
1066
1067 filter = asl->filter & 0xff;
1068 tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
1069
1070 /* master filter overrides local filter */
1071 if (_asl_global.master_filter != 0)
1072 {
1073 filter = _asl_global.master_filter;
1074 tunnel = 1;
1075 }
1076
1077 /* process-specific filter overrides local and master */
1078 if (_asl_global.proc_filter != 0)
1079 {
1080 filter = _asl_global.proc_filter;
1081 tunnel = 1;
1082 }
1083
1084 /*
1085 * Time, TimeNanoSec, Host, PID, UID, and GID values get set here.
1086 * Also sets Sender & Facility (if unset) and "ASLOption store" if remote control is active.
1087 */
1088
1089 aux.type = ASL_MSG_TYPE_AUX_0;
1090
1091 memset(&aux0, 0, sizeof(asl_msg_aux_0_t));
1092 aux.data.aux0 = &aux0;
1093
1094 aux0.message = aux_message;
1095
1096 snprintf(aux_level, sizeof(aux_level), "%u", level);
1097 aux0.level = aux_level;
1098
1099 memset(&tval, 0, sizeof(struct timeval));
1100
1101 status = gettimeofday(&tval, NULL);
1102 if (status == 0)
1103 {
1104 snprintf(aux_time, sizeof(aux_time), "%lu", tval.tv_sec);
1105 snprintf(aux_nano, sizeof(aux_nano), "%d", tval.tv_usec * 1000);
1106 aux0.time = aux_time;
1107 aux0.nano = aux_nano;
1108 }
1109 else
1110 {
1111 tick = time(NULL);
1112 snprintf(aux_time, sizeof(aux_time), "%lu", tick);
1113 aux0.time = aux_time;
1114 }
1115
1116 memset(&aux_host, 0, _POSIX_HOST_NAME_MAX);
1117 if (gethostname(aux_host, _POSIX_HOST_NAME_MAX) == 0)
1118 {
1119 aux0.host = aux_host;
1120 }
1121
1122 snprintf(aux_pid, sizeof(aux_pid), "%u", getpid());
1123 aux0.pid = aux_pid;
1124
1125 snprintf(aux_uid, sizeof(aux_uid), "%d", getuid());
1126 aux0.uid = aux_uid;
1127
1128 snprintf(aux_gid, sizeof(aux_uid), "%d", getgid());
1129 aux0.gid = aux_gid;
1130
1131 /*
1132 * Set Sender if needed
1133 */
1134 status = asl_msg_lookup((asl_msg_t *)msg, ASL_KEY_SENDER, &val, NULL);
1135 if ((status != 0) || (val == NULL))
1136 {
1137 if ((ac != NULL) && (ac->name != NULL))
1138 {
1139 /* Use the Sender name from the client handle */
1140 aux0.sender = ac->name;
1141 }
1142 else
1143 {
1144 /* Get the value for ASL_KEY_SENDER from cache */
1145 if (_asl_global.sender == NULL)
1146 {
1147 name = *(*_NSGetArgv());
1148 if (name != NULL)
1149 {
1150 x = strrchr(name, '/');
1151 if (x != NULL) x++;
1152 else x = name;
1153
1154 pthread_mutex_lock(&_asl_global.lock);
1155 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
1156 pthread_mutex_unlock(&_asl_global.lock);
1157 }
1158 }
1159
1160 if (_asl_global.sender != NULL) aux0.sender = _asl_global.sender;
1161 else aux0.sender = "Unknown";
1162 }
1163 }
1164
1165 /*
1166 * Set Facility
1167 */
1168 status = asl_msg_lookup((asl_msg_t *)msg, ASL_KEY_FACILITY, &val, NULL);
1169 if ((status != 0) || (val == NULL))
1170 {
1171 if ((ac != NULL) && (ac->facility != NULL))
1172 {
1173 /* Use the Facility name from the client handle */
1174 aux0.facility = ac->facility;
1175 }
1176 }
1177
1178 /* Set "ASLOption store" if remote control is active */
1179
1180 aux_option = NULL;
1181
1182 if (tunnel != 0)
1183 {
1184 val = asl_get((aslmsg)msg, ASL_KEY_OPTION);
1185 if (val == NULL)
1186 {
1187 aux0.option = ASL_OPT_STORE;
1188 }
1189 else
1190 {
1191 asprintf(&aux_option, "%s %s", ASL_OPT_STORE, val);
1192 aux0.option = aux_option;
1193 }
1194 }
1195
1196 outstatus = -1;
1197
1198 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
1199
1200 /*
1201 * If there is an aslfile this is a stand-alone file client.
1202 * Just save to the file.
1203 */
1204 if (asl->aslfile != NULL)
1205 {
1206 asl_msg_t *merged_msg;
1207
1208 outstatus = ASL_STATUS_FAILED;
1209
1210 merged_msg = _asl_merge_msg_aux0(msg, aux0);
1211 if (merged_msg != NULL)
1212 {
1213 outstatus = asl_file_save(asl->aslfile, (aslmsg)merged_msg, &(asl->aslfileid));
1214 asl->aslfileid++;
1215 asl_msg_release(merged_msg);
1216 }
1217
1218 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1219 return outstatus;
1220 }
1221
1222 _asl_global_init();
1223 if ((_asl_global.server_port != MACH_PORT_NULL) && (filter != 0) && ((filter & lmask) != 0))
1224 {
1225 len = _asl_msg_string_length_aux(msg, &aux);
1226
1227 if (len != 0)
1228 {
1229 /* send a mach message to syslogd */
1230 out = 0;
1231 outlen = len + 11;
1232 kstatus = vm_allocate(mach_task_self(), &out, outlen, TRUE);
1233 if (kstatus == KERN_SUCCESS)
1234 {
1235 memset((void *)out, 0, outlen);
1236 snprintf((char *)out, 12, "%10u ", len);
1237
1238 status = _asl_msg_to_string_buffer_aux(msg, &aux, (char *)(out + 11), len);
1239 if (status == 0)
1240 {
1241 if (kstatus == KERN_SUCCESS) kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)out, outlen);
1242 else vm_deallocate(mach_task_self(), out, outlen);
1243
1244 if (kstatus == KERN_SUCCESS) outstatus = 0;
1245 }
1246 else
1247 {
1248 vm_deallocate(mach_task_self(), (vm_address_t)out, outlen);
1249 }
1250 }
1251 }
1252 }
1253
1254 if (aux_option != NULL) free(aux_option);
1255 aux0.option = NULL;
1256
1257 outstatus = 0;
1258
1259 /* messages from syslog() get filtered on the way out to stderr */
1260 fd_write = 1;
1261 if ((asl->options & ASL_OPT_SYSLOG_LEGACY) && (filter != 0) && ((filter & lmask) == 0)) fd_write = 0;
1262
1263 if ((fd_write != 0) && (asl->fd_count > 0))
1264 {
1265 asl_msg_t *merged_msg;
1266
1267 /*
1268 * It's easier to merge the aux fields with the msg into a new message
1269 * than to have asl_format_messge deal with two inputs. Since this is
1270 * an infrequently used code path, we pay a small price to merge them
1271 * here and save a lot of code complexity.
1272 */
1273
1274 merged_msg = _asl_merge_msg_aux0(msg, aux0);
1275 if (merged_msg != NULL)
1276 {
1277 /* write to file descriptors */
1278
1279 for (i = 0; i < asl->fd_count; i++)
1280 {
1281 if (asl->fd_list[i] < 0) continue;
1282
1283 len = 0;
1284 str = asl_format_message(merged_msg, asl->fd_mfmt[i], asl->fd_tfmt[i], asl->fd_encoding[i], &len);
1285 if (str == NULL) continue;
1286
1287 status = write(asl->fd_list[i], str, len - 1);
1288 if (status < 0)
1289 {
1290 asl->fd_list[i] = -1;
1291 outstatus = -1;
1292 }
1293
1294 free(str);
1295 }
1296
1297 asl_msg_release(merged_msg);
1298 }
1299 }
1300
1301 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1302
1303 return outstatus;
1304 }
1305
1306 int
1307 asl_send(aslclient ac, aslmsg msg)
1308 {
1309 return _asl_send_message(ac, (asl_msg_t *)msg, -1, NULL);
1310 }
1311
1312 static int
1313 _asl_aux_save_context(asl_aux_context_t *ctx)
1314 {
1315 if (ctx == NULL) return -1;
1316
1317 pthread_mutex_lock(&_asl_global.lock);
1318
1319 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, (_asl_global.aux_count + 1) * sizeof(asl_aux_context_t *));
1320 if (_asl_global.aux_ctx == NULL)
1321 {
1322 _asl_global.aux_count = 0;
1323 return -1;
1324 }
1325
1326 _asl_global.aux_ctx[_asl_global.aux_count++] = ctx;
1327
1328 pthread_mutex_unlock(&_asl_global.lock);
1329
1330 return 0;
1331 }
1332
1333 /*
1334 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1335 * will be saved at the time that the auxiliary file is created. The message will include
1336 * any keys and values found in msg, and it will include the title and Uniform Type
1337 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1338 * new auxiliary file.
1339 */
1340 static int
1341 _asl_auxiliary(aslmsg msg, const char *title, const char *uti, const char *url, int *out_fd)
1342 {
1343 asl_msg_t *merged_msg;
1344 asl_msg_aux_t aux;
1345 asl_msg_aux_0_t aux0;
1346 fileport_t fileport;
1347 kern_return_t kstatus;
1348 uint32_t outlen, newurllen, len, where;
1349 int status, fd, fdpair[2];
1350 caddr_t out, newurl;
1351 dispatch_queue_t pipe_q;
1352 dispatch_io_t pipe_channel;
1353 dispatch_semaphore_t sem;
1354
1355 aux.type = ASL_MSG_TYPE_AUX_0;
1356
1357 memset(&aux0, 0, sizeof(asl_msg_aux_0_t));
1358 aux.data.aux0 = &aux0;
1359
1360 aux0.auxtitle = title;
1361 if (uti == NULL) aux0.auxuti = "public.data";
1362 else aux0.auxuti = uti;
1363 aux0.auxurl = url;
1364
1365 merged_msg = _asl_merge_msg_aux0((asl_msg_t *)msg, aux0);
1366 if (merged_msg == NULL) return -1;
1367
1368 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1369 if (out_fd == NULL)
1370 {
1371 status = _asl_send_message(NULL, merged_msg, -1, NULL);
1372 asl_msg_release(merged_msg);
1373 return status;
1374 }
1375
1376 where = asl_store_location();
1377
1378 if (where == ASL_STORE_LOCATION_MEMORY)
1379 {
1380 /* create a pipe */
1381
1382 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1383 if (ctx == NULL) return -1;
1384
1385 status = pipe(fdpair);
1386 if (status < 0)
1387 {
1388 free(ctx);
1389 return -1;
1390 }
1391
1392 /* give read end to dispatch_io_read */
1393 fd = fdpair[0];
1394 sem = dispatch_semaphore_create(0);
1395 ctx->sem = sem;
1396 ctx->fd = fdpair[1];
1397
1398 status = _asl_aux_save_context(ctx);
1399 if (status != 0)
1400 {
1401 close(fdpair[0]);
1402 close(fdpair[1]);
1403 dispatch_release(sem);
1404 free(ctx);
1405 return -1;
1406 }
1407
1408 pipe_q = dispatch_queue_create("PipeQ", NULL);
1409 pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){
1410 close(fd);
1411 });
1412
1413 *out_fd = fdpair[1];
1414
1415 dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
1416
1417 dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){
1418 if (err == 0)
1419 {
1420 size_t len = dispatch_data_get_size(pipedata);
1421 if (len > 0)
1422 {
1423 const char *bytes = NULL;
1424 char *encoded;
1425
1426 dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
1427 encoded = asl_core_encode_buffer(bytes, len);
1428 asl_set((aslmsg)merged_msg, ASL_KEY_AUX_DATA, encoded);
1429 free(encoded);
1430 _asl_send_message(NULL, merged_msg, -1, NULL);
1431 asl_msg_release(merged_msg);
1432 dispatch_release(md);
1433 }
1434 }
1435
1436 if (done)
1437 {
1438 dispatch_semaphore_signal(sem);
1439 dispatch_release(pipe_channel);
1440 dispatch_release(pipe_q);
1441 }
1442 });
1443
1444 return 0;
1445 }
1446
1447 _asl_global_init();
1448 if (_asl_global.server_port == MACH_PORT_NULL) return -1;
1449
1450 len = _asl_msg_string_length_aux(merged_msg, NULL);
1451 if (len == 0)
1452 {
1453 asl_msg_release(merged_msg);
1454 return -1;
1455 }
1456
1457 outlen = len + 11;
1458 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&out, outlen, TRUE);
1459 if (kstatus != KERN_SUCCESS)
1460 {
1461 asl_msg_release(merged_msg);
1462 return -1;
1463 }
1464
1465 memset(out, 0, outlen);
1466 snprintf((char *)out, 12, "%10u ", len);
1467
1468 status = _asl_msg_to_string_buffer_aux(merged_msg, NULL, (char *)(out + 11), len);
1469 if (status != 0)
1470 {
1471 asl_msg_release(merged_msg);
1472 vm_deallocate(mach_task_self(), (vm_address_t)out, outlen);
1473 return -1;
1474 }
1475
1476 status = 0;
1477 fileport = MACH_PORT_NULL;
1478 status = KERN_SUCCESS;
1479
1480 kstatus = _asl_server_create_aux_link(_asl_global.server_port, out, outlen, &fileport, &newurl, &newurllen, &status);
1481 if (kstatus != KERN_SUCCESS)
1482 {
1483 asl_msg_release(merged_msg);
1484 return -1;
1485 }
1486
1487 if (status != 0)
1488 {
1489 asl_msg_release(merged_msg);
1490 return status;
1491 }
1492
1493 if (newurl != NULL)
1494 {
1495 asl_msg_set_key_val(merged_msg, ASL_KEY_AUX_URL, newurl);
1496 vm_deallocate(mach_task_self(), (vm_address_t)newurl, newurllen);
1497 }
1498
1499 if (fileport == MACH_PORT_NULL)
1500 {
1501 asl_msg_release(merged_msg);
1502 return -1;
1503 }
1504
1505 fd = fileport_makefd(fileport);
1506 mach_port_deallocate(mach_task_self(), fileport);
1507 if (fd < 0)
1508 {
1509 asl_msg_release(merged_msg);
1510 status = -1;
1511 }
1512 else
1513 {
1514 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1515 if (ctx == NULL)
1516 {
1517 status = -1;
1518 }
1519 else
1520 {
1521 *out_fd = fd;
1522
1523 ctx->fd = fd;
1524 ctx->msg = merged_msg;
1525
1526 status = _asl_aux_save_context(ctx);
1527 }
1528 }
1529
1530 return status;
1531 }
1532
1533 int
1534 asl_create_auxiliary_file(aslmsg msg, const char *title, const char *uti, int *out_fd)
1535 {
1536 if (out_fd == NULL) return -1;
1537
1538 return _asl_auxiliary(msg, title, uti, NULL, out_fd);
1539 }
1540
1541 int
1542 asl_log_auxiliary_location(aslmsg msg, const char *title, const char *uti, const char *url)
1543 {
1544 return _asl_auxiliary(msg, title, uti, url, NULL);
1545 }
1546
1547 /*
1548 * Close an auxiliary file.
1549 * Sends the cached auxiliary message to syslogd.
1550 */
1551 int
1552 asl_close_auxiliary_file(int fd)
1553 {
1554 int i, j, status;
1555 asl_msg_t *aux_msg;
1556 dispatch_semaphore_t aux_sem;
1557
1558 pthread_mutex_lock(&(_asl_global.lock));
1559
1560 aux_msg = NULL;
1561 status = -1;
1562
1563 for (i = 0; i < _asl_global.aux_count; i++)
1564 {
1565 if (_asl_global.aux_ctx[i]->fd == fd)
1566 {
1567 status = 0;
1568
1569 aux_msg = _asl_global.aux_ctx[i]->msg;
1570 aux_sem = _asl_global.aux_ctx[i]->sem;
1571
1572 free(_asl_global.aux_ctx[i]);
1573
1574 for (j = i + 1; j < _asl_global.aux_count; i++, j++)
1575 {
1576 _asl_global.aux_ctx[i] = _asl_global.aux_ctx[j];
1577 }
1578
1579 _asl_global.aux_count--;
1580
1581 if (_asl_global.aux_count == 0)
1582 {
1583 free(_asl_global.aux_ctx);
1584 _asl_global.aux_ctx = NULL;
1585 }
1586 else
1587 {
1588 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, _asl_global.aux_count * sizeof(asl_aux_context_t *));
1589 if (_asl_global.aux_ctx == NULL)
1590 {
1591 _asl_global.aux_count = 0;
1592 status = -1;
1593 }
1594 }
1595
1596 break;
1597 }
1598 }
1599
1600 pthread_mutex_unlock(&(_asl_global.lock));
1601
1602 close(fd);
1603
1604 if (aux_msg != NULL)
1605 {
1606 if (_asl_send_message(NULL, aux_msg, -1, NULL) != ASL_STATUS_OK) status = -1;
1607 asl_msg_release(aux_msg);
1608 }
1609
1610 if (aux_sem != NULL)
1611 {
1612 dispatch_semaphore_wait(aux_sem, DISPATCH_TIME_FOREVER);
1613 dispatch_release(aux_sem);
1614 }
1615
1616 return status;
1617 }
1618
1619 /*
1620 * asl_search: Search for messages matching the criteria described
1621 * by the aslmsg. The caller should set the attributes to match using
1622 * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is
1623 * used for attributes set with asl_set().
1624 * a: an aslmsg
1625 * returns: a set of messages that can be iterated over using aslresp_next(),
1626 * and the values can be retrieved using aslresp_get.
1627 */
1628
1629 /*
1630 * This routine searches the ASL datastore on disk (/var/log/asl).
1631 * It is called my asl_search if syslogd is not running or if syslogd
1632 * indicates that an in-memory store is not being used.
1633 */
1634 static aslresponse
1635 _asl_search_store(aslclient ac, aslmsg a)
1636 {
1637 asl_search_result_t query, *out;
1638 asl_msg_t *q, *qlist[1];
1639 uint32_t status, op;
1640 uint64_t last_id, start_id;
1641 asl_store_t *store;
1642 const char *val;
1643
1644 if (a == NULL) return NULL;
1645
1646 q = (asl_msg_t *)a;
1647
1648 /* check for "ASLMessageId >[=] n" and set start_id */
1649 start_id = 0;
1650 val = NULL;
1651
1652 status = asl_msg_lookup(q, ASL_KEY_MSG_ID, &val, &op);
1653 if ((status == 0) && (val != NULL) && (op & ASL_QUERY_OP_GREATER))
1654 {
1655 if (op & ASL_QUERY_OP_EQUAL) start_id = atoll(val);
1656 else start_id = atoll(val) + 1;
1657 }
1658
1659 store = NULL;
1660 status = asl_store_open_read(NULL, &store);
1661 if (status != 0) return NULL;
1662 if (store == NULL) return NULL;
1663
1664 out = NULL;
1665 last_id = 0;
1666
1667 qlist[0] = (asl_msg_t *)a;
1668 memset(&query, 0, sizeof(asl_search_result_t));
1669 query.count = 1;
1670 query.msg = qlist;
1671
1672 status = asl_store_match(store, &query, &out, &last_id, start_id, 0, 1);
1673 asl_store_close(store);
1674
1675 return out;
1676 }
1677
1678 static uint32_t
1679 _asl_search_concat_results(asl_search_result_t *batch, asl_search_result_t **out)
1680 {
1681 uint32_t i, j;
1682
1683 if (out == NULL) return ASL_STATUS_FAILED;
1684
1685 /* nothing to do if batch is NULL or contains no messages */
1686 if (batch == NULL) return 0;
1687 if (batch->count == 0)
1688 {
1689 aslresponse_free(batch);
1690 return 0;
1691 }
1692
1693 if (*out == NULL) *out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
1694 if (*out == NULL)
1695 {
1696 aslresponse_free(batch);
1697 return ASL_STATUS_FAILED;
1698 }
1699
1700 if ((*out)->count == 0)
1701 {
1702 (*out)->msg = (asl_msg_t **)calloc(batch->count, sizeof(asl_msg_t *));
1703 }
1704 else
1705 {
1706 (*out)->msg = (asl_msg_t **)reallocf((*out)->msg, ((*out)->count + batch->count) * sizeof(asl_msg_t *));
1707 }
1708
1709 if ((*out)->msg == NULL)
1710 {
1711 aslresponse_free(batch);
1712 free(*out);
1713 *out = NULL;
1714 return ASL_STATUS_FAILED;
1715 }
1716
1717 for (i = 0, j = (*out)->count; i < batch->count; i++, j++) (*out)->msg[j] = batch->msg[i];
1718
1719 (*out)->count += batch->count;
1720 free(batch->msg);
1721 free(batch);
1722 return ASL_STATUS_OK;
1723 }
1724
1725 static aslresponse
1726 _asl_search_memory(aslclient ac, aslmsg a)
1727 {
1728 asl_search_result_t *batch, *out;
1729 char *qstr, *str, *res;
1730 uint32_t len, reslen, status;
1731 uint64_t cmax, qmin;
1732 kern_return_t kstatus;
1733 security_token_t sec;
1734 caddr_t vmstr;
1735
1736 if (a == NULL) return 0;
1737
1738 _asl_global_init();
1739 if (_asl_global.server_port == MACH_PORT_NULL) return NULL;
1740
1741 len = 0;
1742 qstr = asl_msg_to_string((asl_msg_t *)a, &len);
1743
1744 str = NULL;
1745 if (qstr == NULL)
1746 {
1747 asprintf(&str, "0\n");
1748 len = 3;
1749 }
1750 else
1751 {
1752 asprintf(&str, "1\n%s\n", qstr);
1753 len += 3;
1754 free(qstr);
1755 }
1756
1757 if (str == NULL) return NULL;
1758
1759 /*
1760 * Fetch a batch of results each time through the loop.
1761 * Fetching small batches rebuces the load on syslogd.
1762 */
1763 out = NULL;
1764 qmin = 0;
1765 cmax = 0;
1766
1767 forever
1768 {
1769 res = NULL;
1770 reslen = 0;
1771 sec.val[0] = -1;
1772 sec.val[1] = -1;
1773 status = ASL_STATUS_OK;
1774
1775 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
1776 if (kstatus != KERN_SUCCESS) return NULL;
1777
1778 memmove(vmstr, str, len);
1779
1780 status = 0;
1781 kstatus = _asl_server_query(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
1782 if (kstatus != KERN_SUCCESS) break;
1783 if (res == NULL) break;
1784
1785 batch = asl_list_from_string(res);
1786 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1787
1788 status = _asl_search_concat_results(batch, &out);
1789 if (status != ASL_STATUS_OK) break;
1790 if (out->count < FETCH_BATCH) break;
1791
1792 if (cmax >= qmin) qmin = cmax + 1;
1793 }
1794
1795 free(str);
1796
1797 return out;
1798 }
1799
1800 int
1801 asl_store_location()
1802 {
1803 kern_return_t kstatus;
1804 char *res;
1805 uint32_t reslen, status;
1806 uint64_t cmax;
1807 security_token_t sec;
1808
1809 _asl_global_init();
1810 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE;
1811
1812 res = NULL;
1813 reslen = 0;
1814 cmax = 0;
1815 sec.val[0] = -1;
1816 sec.val[1] = -1;
1817 status = ASL_STATUS_OK;
1818
1819 kstatus = _asl_server_query(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
1820
1821 /* res should never be returned, but just to be certain we don't leak VM ... */
1822 if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1823
1824 if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
1825
1826 if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY;
1827 return ASL_STORE_LOCATION_FILE;
1828 }
1829
1830 aslresponse
1831 asl_search(aslclient ac, aslmsg a)
1832 {
1833 int where;
1834 asl_search_result_t *out;
1835
1836 _asl_global_init();
1837
1838 where = asl_store_location();
1839 if (where == ASL_STORE_LOCATION_FILE) out = _asl_search_store(ac, a);
1840 else out = _asl_search_memory(ac, a);
1841
1842 return out;
1843 }
1844
1845 int
1846 asl_syslog_faciliy_name_to_num(const char *name)
1847 {
1848 if (name == NULL) return -1;
1849
1850 if (strcaseeq(name, "auth")) return LOG_AUTH;
1851 if (strcaseeq(name, "authpriv")) return LOG_AUTHPRIV;
1852 if (strcaseeq(name, "cron")) return LOG_CRON;
1853 if (strcaseeq(name, "daemon")) return LOG_DAEMON;
1854 if (strcaseeq(name, "ftp")) return LOG_FTP;
1855 if (strcaseeq(name, "install")) return LOG_INSTALL;
1856 if (strcaseeq(name, "kern")) return LOG_KERN;
1857 if (strcaseeq(name, "lpr")) return LOG_LPR;
1858 if (strcaseeq(name, "mail")) return LOG_MAIL;
1859 if (strcaseeq(name, "netinfo")) return LOG_NETINFO;
1860 if (strcaseeq(name, "remoteauth")) return LOG_REMOTEAUTH;
1861 if (strcaseeq(name, "news")) return LOG_NEWS;
1862 if (strcaseeq(name, "security")) return LOG_AUTH;
1863 if (strcaseeq(name, "syslog")) return LOG_SYSLOG;
1864 if (strcaseeq(name, "user")) return LOG_USER;
1865 if (strcaseeq(name, "uucp")) return LOG_UUCP;
1866 if (strcaseeq(name, "local0")) return LOG_LOCAL0;
1867 if (strcaseeq(name, "local1")) return LOG_LOCAL1;
1868 if (strcaseeq(name, "local2")) return LOG_LOCAL2;
1869 if (strcaseeq(name, "local3")) return LOG_LOCAL3;
1870 if (strcaseeq(name, "local4")) return LOG_LOCAL4;
1871 if (strcaseeq(name, "local5")) return LOG_LOCAL5;
1872 if (strcaseeq(name, "local6")) return LOG_LOCAL6;
1873 if (strcaseeq(name, "local7")) return LOG_LOCAL7;
1874 if (strcaseeq(name, "launchd")) return LOG_LAUNCHD;
1875
1876 return -1;
1877 }
1878
1879 const char *
1880 asl_syslog_faciliy_num_to_name(int n)
1881 {
1882 if (n < 0) return NULL;
1883
1884 if (n == LOG_AUTH) return "auth";
1885 if (n == LOG_AUTHPRIV) return "authpriv";
1886 if (n == LOG_CRON) return "cron";
1887 if (n == LOG_DAEMON) return "daemon";
1888 if (n == LOG_FTP) return "ftp";
1889 if (n == LOG_INSTALL) return "install";
1890 if (n == LOG_KERN) return "kern";
1891 if (n == LOG_LPR) return "lpr";
1892 if (n == LOG_MAIL) return "mail";
1893 if (n == LOG_NETINFO) return "netinfo";
1894 if (n == LOG_REMOTEAUTH) return "remoteauth";
1895 if (n == LOG_NEWS) return "news";
1896 if (n == LOG_AUTH) return "security";
1897 if (n == LOG_SYSLOG) return "syslog";
1898 if (n == LOG_USER) return "user";
1899 if (n == LOG_UUCP) return "uucp";
1900 if (n == LOG_LOCAL0) return "local0";
1901 if (n == LOG_LOCAL1) return "local1";
1902 if (n == LOG_LOCAL2) return "local2";
1903 if (n == LOG_LOCAL3) return "local3";
1904 if (n == LOG_LOCAL4) return "local4";
1905 if (n == LOG_LOCAL5) return "local5";
1906 if (n == LOG_LOCAL6) return "local6";
1907 if (n == LOG_LOCAL7) return "local7";
1908 if (n == LOG_LAUNCHD) return "launchd";
1909
1910 return NULL;
1911 }
1912
1913 /*
1914 * utility for converting a time string into a time_t
1915 * we only deal with the following formats:
1916 * Canonical form YYYY.MM.DD hh:mm:ss UTC
1917 * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37)
1918 * absolute form - # seconds since the epoch (e.g. 1095789191)
1919 * relative time - seconds before or after now (e.g. -300, +43200)
1920 * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s)
1921 */
1922
1923 #define CANONICAL_TIME_REX "^[0-9][0-9][0-9][0-9].[01]?[0-9].[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9][ ]+UTC$"
1924 #define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$"
1925 #define ABSOLUTE_TIME_REX "^[0-9]+[s]?$"
1926 #define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$"
1927
1928 #define SECONDS_PER_MINUTE 60
1929 #define SECONDS_PER_HOUR 3600
1930 #define SECONDS_PER_DAY 86400
1931 #define SECONDS_PER_WEEK 604800
1932
1933 static regex_t rex_canon, rex_ctime, rex_abs, rex_rel;
1934 static int reg_status = 0;
1935
1936 /*
1937 * We use the last letter in the month name to determine
1938 * the month number (0-11). There are two collisions:
1939 * Jan and Jun both end in n
1940 * Mar and Apr both end in r
1941 * In these cases we check the second letter.
1942 *
1943 * The MTH_LAST array maps the last letter to a number.
1944 */
1945 static const int8_t MTH_LAST[] = {-1, 1, 11, -1, -1, -1, 7, -1, -1, -1, -1, 6, -1, 5, -1, 8, -1, 3, -1, 9, -1, 10, -1, -1, 4, -1};
1946
1947 static int
1948 _month_num(char *s)
1949 {
1950 int i;
1951 int8_t v8;
1952
1953 v8 = -1;
1954 if (s[2] > 90) v8 = s[2] - 'a';
1955 else v8 = s[2] - 'A';
1956
1957 if ((v8 < 0) || (v8 > 25)) return -1;
1958
1959 v8 = MTH_LAST[v8];
1960 if (v8 < 0) return -1;
1961
1962 i = v8;
1963 if ((i == 5) && ((s[1] == 'a') || (s[1] == 'A'))) return 0;
1964 if ((i == 3) && ((s[1] == 'a') || (s[1] == 'A'))) return 2;
1965 return i;
1966 }
1967
1968 time_t
1969 asl_parse_time(const char *in)
1970 {
1971 int len, y;
1972 struct tm t;
1973 time_t tick, delta, factor;
1974 char *str, *p, *x;
1975 static dispatch_once_t once;
1976
1977 if (in == NULL) return -1;
1978
1979 dispatch_once(&once, ^{
1980 int status;
1981 int rflags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
1982
1983 memset(&rex_canon, 0, sizeof(regex_t));
1984 status = regcomp(&rex_canon, CANONICAL_TIME_REX, rflags);
1985 if (status != 0) reg_status = -1;
1986
1987 memset(&rex_ctime, 0, sizeof(regex_t));
1988 status = regcomp(&rex_ctime, CTIME_REX, rflags);
1989 if (status != 0) reg_status = -1;
1990
1991 memset(&rex_abs, 0, sizeof(regex_t));
1992 status = regcomp(&rex_abs, ABSOLUTE_TIME_REX, rflags);
1993 if (status != 0) reg_status = -1;
1994
1995 memset(&rex_rel, 0, sizeof(regex_t));
1996 status = regcomp(&rex_rel, RELATIVE_TIME_REX, rflags);
1997 if (status != 0) reg_status = -1;
1998 });
1999
2000 if (reg_status < 0) return -1;
2001
2002 len = strlen(in) + 1;
2003
2004 if (regexec(&rex_abs, in, 0, NULL, 0) == 0)
2005 {
2006 /*
2007 * Absolute time (number of seconds since the epoch)
2008 */
2009 str = strdup(in);
2010 if (str == NULL) return -1;
2011
2012 if ((str[len-2] == 's') || (str[len-2] == 'S')) str[len-2] = '\0';
2013
2014 tick = atol(str);
2015 free(str);
2016
2017 return tick;
2018 }
2019 else if (regexec(&rex_rel, in, 0, NULL, 0) == 0)
2020 {
2021 /*
2022 * Reletive time (number of seconds before or after right now)
2023 */
2024 str = strdup(in);
2025 if (str == NULL) return -1;
2026
2027 factor = 1;
2028
2029 if ((str[len-2] == 's') || (str[len-2] == 'S'))
2030 {
2031 str[len-2] = '\0';
2032 }
2033 else if ((str[len-2] == 'm') || (str[len-2] == 'M'))
2034 {
2035 str[len-2] = '\0';
2036 factor = SECONDS_PER_MINUTE;
2037 }
2038 else if ((str[len-2] == 'h') || (str[len-2] == 'H'))
2039 {
2040 str[len-2] = '\0';
2041 factor = SECONDS_PER_HOUR;
2042 }
2043 else if ((str[len-2] == 'd') || (str[len-2] == 'D'))
2044 {
2045 str[len-2] = '\0';
2046 factor = SECONDS_PER_DAY;
2047 }
2048 else if ((str[len-2] == 'w') || (str[len-2] == 'W'))
2049 {
2050 str[len-2] = '\0';
2051 factor = SECONDS_PER_WEEK;
2052 }
2053
2054 tick = time(NULL);
2055 delta = factor * atol(str);
2056 tick += delta;
2057
2058 free(str);
2059
2060 return tick;
2061 }
2062 else if (regexec(&rex_canon, in, 0, NULL, 0) == 0)
2063 {
2064 memset(&t, 0, sizeof(struct tm));
2065 str = strdup(in);
2066 if (str == NULL) return -1;
2067
2068 /* Get year */
2069 x = str;
2070 p = strchr(x, '.');
2071 *p = '\0';
2072 t.tm_year = atoi(x) - 1900;
2073
2074 /* Get month */
2075 x = p + 1;
2076 p = strchr(x, '.');
2077 *p = '\0';
2078 t.tm_mon = atoi(x) - 1;
2079
2080 /* Get day */
2081 x = p + 1;
2082 p = strchr(x, ' ');
2083 *p = '\0';
2084 t.tm_mday = atoi(x);
2085
2086 /* Get hour */
2087 for (x = p + 1; *x == ' '; x++);
2088 p = strchr(x, ':');
2089 *p = '\0';
2090 t.tm_hour = atoi(x);
2091
2092 /* Get minutes */
2093 x = p + 1;
2094 p = strchr(x, ':');
2095 *p = '\0';
2096 t.tm_min = atoi(x);
2097
2098 /* Get seconds */
2099 x = p + 1;
2100 p = strchr(x, ' ');
2101 *p = '\0';
2102 t.tm_sec = atoi(x);
2103
2104 free(str);
2105 return timegm(&t);
2106 }
2107 else if (regexec(&rex_ctime, in, 0, NULL, 0) == 0)
2108 {
2109 /* We assume it's in the current year */
2110 memset(&t, 0, sizeof(struct tm));
2111 tick = time(NULL);
2112 gmtime_r(&tick, &t);
2113 y = t.tm_year;
2114
2115 memset(&t, 0, sizeof(struct tm));
2116 str = strdup(in);
2117 if (str == NULL) return -1;
2118
2119 t.tm_year = y;
2120 t.tm_mon = _month_num(str);
2121 if (t.tm_mon < 0) return -1;
2122
2123 for (x = strchr(str, ' '); *x == ' '; x++);
2124 p = strchr(x, ' ');
2125 *p = '\0';
2126 t.tm_mday = atoi(x);
2127
2128 /* Get hour */
2129 for (x = p + 1; *x == ' '; x++);
2130 p = strchr(x, ':');
2131 *p = '\0';
2132 t.tm_hour = atoi(x);
2133
2134 /* Get minutes */
2135 x = p + 1;
2136 p = strchr(x, ':');
2137 *p = '\0';
2138 t.tm_min = atoi(x);
2139
2140 /* Get seconds */
2141 x = p + 1;
2142 t.tm_sec = atoi(x);
2143
2144 t.tm_isdst = -1;
2145
2146 free(str);
2147 return mktime(&t);
2148 }
2149
2150 return -1;
2151 }
2152
2153 #endif /* BUILDING_VARIANT */