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