2 * Copyright (c) 2005, 2006, 2009 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
28 #endif /* !VARIANT_DYLD */
29 #include <sys/types.h>
31 #include <mach/mach_init.h>
32 #include <mach/vm_map.h>
35 #include <sys/syslog.h>
37 #include <sys/socket.h>
41 #include <servers/bootstrap.h>
47 #define VM_PAGE_SIZE 4096
50 #define SBUF_SIZE(s) (((SBUF *)(s))->b.end - ((SBUF *)(s))->b.buf + 1)
51 /* we use a small buffer to minimize stack usage constraints */
59 void (*full
)(struct _BUF
*);
62 typedef struct _SBUF
{
66 #endif /* !VARIANT_DYLD */
69 #define ASL_SERVICE_NAME "com.apple.system.logger"
71 static mach_port_t asl_port
;
72 static pthread_once_t asl_init_once
= PTHREAD_ONCE_INIT
;
74 /* private extern exports from asl.c */
75 const char *_asl_escape(unsigned char);
77 /* flush the buffer */
86 w
= write(b
->fd
, buf
, n
);
88 if(errno
== EINTR
|| errno
== EAGAIN
)
97 /* flush the buffer and reset the pointer */
105 /* enlarge the buffer */
110 vm_size_t sold
, snew
;
113 new = (vm_address_t
)(b
->end
+ 1);
114 if(vm_allocate(mach_task_self(), &new, VM_PAGE_SIZE
, 0) == 0) {
115 /* page is adjacent */
116 b
->end
+= VM_PAGE_SIZE
;
120 snew
= (sold
+ VM_PAGE_SIZE
) & ~(VM_PAGE_SIZE
- 1);
121 if(vm_allocate(mach_task_self(), &new, snew
, 1) != 0)
123 longjmp(((SBUF
*)b
)->j
, 1); /* out of memory */
124 #else /* VARIANT_DYLD */
125 abort(); /* out of memory */
126 #endif /* !VARIANT_DYLD */
127 diff
= new - (vm_address_t
)b
->buf
;
128 memcpy((void *)new, b
->buf
, sold
);
129 if((intptr_t)(b
->buf
) & (VM_PAGE_SIZE
- 1)) {
130 sold
&= ~(VM_PAGE_SIZE
- 1);
131 b
->buf
= (char *)((intptr_t)(b
->buf
+ VM_PAGE_SIZE
) & ~(VM_PAGE_SIZE
- 1));
132 b
->end
= (char *)(new + snew
- 1);
134 b
->end
+= diff
+ VM_PAGE_SIZE
;
136 vm_deallocate(mach_task_self(), (vm_address_t
)b
->buf
, sold
);
138 b
->buf
= (char *)new;
142 static inline void put_s(BUF
*, _esc_func
, const char *);
143 /* output a single character */
145 put_c(BUF
*b
, _esc_func esc
, unsigned char c
)
149 if(esc
&& (cp
= esc(c
)) != NULL
)
158 /* output a null-terminated string */
160 put_s(BUF
*b
, _esc_func esc
, const char *str
)
163 put_c(b
, esc
, *str
++);
166 /* output a string of the specified size */
168 put_n(BUF
*b
, _esc_func esc
, const char *str
, int n
)
171 put_c(b
, esc
, *str
++);
175 * Output the signed decimal string representing the number in "in". "width" is
176 * the minimum field width, and "zero" is a boolean value, true for zero padding
177 * (otherwise blank padding).
180 dec(BUF
*b
, _esc_func esc
, long long in
, int width
, int zero
)
183 char *cp
= buf
+ sizeof(buf
);
186 unsigned long long n
= (unsigned long long)in
;
196 *--cp
= (n
% 10) + '0';
205 pad
= width
- strlen(cp
);
206 zero
= zero
? '0' : ' ';
215 * Output the hex string representing the number in "n". "width" is the
216 * minimum field width, and "zero" is a boolean value, true for zero padding
217 * (otherwise blank padding). "upper" is a boolean value, true for upper
218 * case hex characters, lower case otherwise. "p" is a boolean value, true
219 * if 0x should be prepended (for %p), otherwise nothing.
221 static char _h
[] = "0123456789abcdef";
222 static char _H
[] = "0123456789ABCDEF";
223 static char _0x
[] = "0x";
226 hex(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
, int upper
, int p
)
229 char *cp
= buf
+ sizeof(buf
);
230 char *h
= upper
? _H
: _h
;
248 zero
= zero
? '0' : ' ';
257 * Output the unsigned decimal string representing the number in "n". "width"
258 * is the minimum field width, and "zero" is a boolean value, true for zero
259 * padding (otherwise blank padding).
262 udec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
265 char *cp
= buf
+ sizeof(buf
);
271 *--cp
= (n
% 10) + '0';
276 pad
= width
- strlen(cp
);
277 zero
= zero
? '0' : ' ';
284 * Output the unsigned decimal string representing the number in "n", rounded
285 * to the nearest MB, KB or b. "width" is the minimum field width, and "zero"
286 * is a boolean value, true for zero padding (otherwise blank padding).
289 ydec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
291 if(n
>= 10 * (1 << 20)) {
293 udec(b
, esc
, n
>> 20, width
, zero
);
295 } else if (n
>= 10 * (1 << 10)) {
297 udec(b
, esc
, n
>> 10, width
, zero
);
300 udec(b
, esc
, n
, width
, zero
);
306 * The actual engine for all the _simple_*printf routines.
309 __simple_bprintf(BUF
*b
, _esc_func esc
, const char *fmt
, va_list ap
)
312 int lflag
, zero
, width
;
314 if(!(cp
= strchr(fmt
, '%'))) {
318 put_n(b
, esc
, fmt
, cp
- fmt
);
325 lflag
= zero
= width
= 0;
332 case '1': case '2': case '3': case '4': case '5':
333 case '6': case '7': case '8': case '9':
334 while(*fmt
>= '0' && *fmt
<= '9')
335 width
= 10 * width
+ (*fmt
++ - '0');
338 zero
= zero
? '0' : ' ';
342 put_c(b
, esc
, va_arg(ap
, int));
347 dec(b
, esc
, va_arg(ap
, int), width
, zero
);
350 dec(b
, esc
, va_arg(ap
, long), width
, zero
);
353 dec(b
, esc
, va_arg(ap
, long long), width
, zero
);
362 hex(b
, esc
, (unsigned long)va_arg(ap
, void *), width
, zero
, 0, 1);
365 cp
= va_arg(ap
, char *);
367 zero
= zero
? '0' : ' ';
375 udec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
378 udec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
381 udec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
388 hex(b
, esc
, va_arg(ap
, unsigned int), width
, zero
,
392 hex(b
, esc
, va_arg(ap
, unsigned long), width
, zero
,
396 hex(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
,
404 ydec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
407 ydec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
410 ydec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
425 * A simplified vfprintf variant. The format string is interpreted with
426 * arguments from the va_list, and the results are written to the given
430 _simple_vdprintf(int fd
, const char *fmt
, va_list ap
)
438 b
.end
= b
.buf
+ MYBUFSIZE
;
439 b
.full
= _flush_reset
;
440 __simple_bprintf(&b
, NULL
, fmt
, ap
);
445 * A simplified fprintf variant. The format string is interpreted with
446 * arguments from the variable argument list, and the results are written
447 * to the given file descriptor.
450 _simple_dprintf(int fd
, const char *fmt
, ...)
455 _simple_vdprintf(fd
, fmt
, ap
);
460 * A simplified string allocate routine. Pass the opaque pointer to structure
461 * to _simple_*sprintf() routines. Use _simple_string() to retrieve the
462 * current string (the string is guaranteed to be null terminated only on
463 * the call to _simple_string()). Use _simple_sfree() to free the structure
471 if(vm_allocate(mach_task_self(), (vm_address_t
*)&b
, VM_PAGE_SIZE
, 1))
473 b
->b
.ptr
= b
->b
.buf
= (char *)b
+ sizeof(SBUF
);
474 b
->b
.end
= (char *)b
+ VM_PAGE_SIZE
- 1;
475 b
->b
.full
= _enlarge
;
476 return (_SIMPLE_STRING
)b
;
480 * The format string is interpreted with arguments from the va_list, and the
481 * results are appended to the string maintained by the opaque structure, as
482 * returned by a previous call to _simple_salloc(). Non-zero is returned on
483 * out-of-memory error.
486 _simple_vsprintf(_SIMPLE_STRING b
, const char *fmt
, va_list ap
)
488 return _simple_vesprintf(b
, NULL
, fmt
, ap
);
492 * The format string is interpreted with arguments from the variable argument
493 * list, and the results are appended to the string maintained by the opaque
494 * structure, as returned by a previous call to _simple_salloc(). Non-zero is
495 * returned on out-of-memory error.
498 _simple_sprintf(_SIMPLE_STRING b
, const char *fmt
, ...)
504 ret
= _simple_vesprintf(b
, NULL
, fmt
, ap
);
510 * Like _simple_vsprintf(), except __esc is a function to call on each
511 * character; the function returns NULL if the character should be passed
512 * as is, otherwise, the returned character string is used instead.
515 _simple_vesprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, va_list ap
)
518 if(setjmp(((SBUF
*)b
)->j
))
520 #endif /* !VARIANT_DYLD */
521 __simple_bprintf((BUF
*)b
, esc
, fmt
, ap
);
526 * Like _simple_sprintf(), except __esc is a function to call on each
527 * character; the function returns NULL if the character should be passed
528 * as is, otherwise, the returned character string is used instead.
530 int _simple_esprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, ...)
536 ret
= _simple_vesprintf(b
, esc
, fmt
, ap
);
542 * Return the null terminated string from the opaque structure, as returned
543 * by a previous call to _simple_salloc().
546 _simple_string(_SIMPLE_STRING b
)
548 *((BUF
*)b
)->ptr
= 0;
549 return ((BUF
*)b
)->buf
;
553 * Reposition the pointer to the first null in the buffer. After a call to
554 * _simple_string, the buffer can be modified, and shrunk.
557 _simple_sresize(_SIMPLE_STRING b
)
559 ((BUF
*)b
)->ptr
= ((BUF
*)b
)->buf
+ strlen(((BUF
*)b
)->buf
);
563 * Append the null-terminated string to the string associated with the opaque
564 * structure. Non-zero is returned on out-of-memory error.
567 _simple_sappend(_SIMPLE_STRING b
, const char *str
)
569 return _simple_esappend(b
, NULL
, str
);
573 * Like _simple_sappend(), except __esc is a function to call on each
574 * character; the function returns NULL if the character should be passed
575 * as is, otherwise, the returned character string is used instead.
577 int _simple_esappend(_SIMPLE_STRING b
, _esc_func esc
, const char *str
)
580 if(setjmp(((SBUF
*)b
)->j
))
582 #endif /* !VARIANT_DYLD */
583 put_s((BUF
*)b
, esc
, str
);
588 * Write the string associated with the opaque structure to the file descriptor.
591 _simple_put(_SIMPLE_STRING b
, int fd
)
598 * Write the string associated with the opaque structure and a trailing newline,
599 * to the file descriptor.
602 _simple_putline(_SIMPLE_STRING b
, int fd
)
605 *((BUF
*)b
)->ptr
++ = '\n';
611 * Free the opaque structure, and the associated string.
614 _simple_sfree(_SIMPLE_STRING b
)
618 if(b
== NULL
) return;
619 if(((intptr_t)(((SBUF
*)b
)->b
.buf
) & (VM_PAGE_SIZE
- 1)) == 0) {
620 vm_deallocate(mach_task_self(), (vm_address_t
)((SBUF
*)b
)->b
.buf
, SBUF_SIZE(b
));
623 s
= ((SBUF
*)b
)->b
.end
- (char *)b
+ 1;
624 vm_deallocate(mach_task_self(), (vm_address_t
)b
, s
);
628 * Simplified ASL log interface; does not use malloc. Unfortunately, this
629 * requires knowledge of the format used by ASL.
633 _simple_asl_init(void)
635 kern_return_t status
;
638 if (asl_port
== MACH_PORT_NULL
)
640 str
= getenv("ASL_DISABLE");
641 if ((str
!= NULL
) && (!strcmp(str
, "1"))) return;
643 status
= bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &asl_port
);
644 if (status
!= KERN_SUCCESS
) asl_port
= MACH_PORT_NULL
;
649 _simple_asl_log_prog(int level
, const char *facility
, const char *message
, const char *prog
)
653 if (pthread_once(&asl_init_once
, _simple_asl_init
) != 0) return;
654 if (asl_port
== MACH_PORT_NULL
) return;
656 if ((b
= _simple_salloc()) == NULL
) return;
660 kern_return_t kstatus
;
666 gettimeofday(&tv
, NULL
);
668 if (_simple_sprintf(b
, " 0 [Time ", 0)) break;
669 if (_simple_esprintf(b
, _asl_escape
, "%lu", tv
.tv_sec
)) break;
670 if (_simple_sappend(b
, "] [Sender ")) break;
671 if (_simple_esappend(b
, _asl_escape
, prog
)) break;
672 if (_simple_sappend(b
, "] [Level ")) break;
673 if (_simple_esprintf(b
, _asl_escape
, "%d", level
)) break;
674 if (_simple_sappend(b
, "] [Facility ")) break;
675 if (_simple_esappend(b
, _asl_escape
, facility
)) break;
676 if (_simple_sappend(b
, "] [Message ")) break;
677 if (_simple_esappend(b
, _asl_escape
, message
)) break;
679 /* remove trailing (escaped) newlines */
680 cp
= _simple_string(b
);
685 if (strcmp(cp
, "\\n") != 0) break;
691 if (_simple_sappend(b
, "]\n")) break;
693 cp
= _simple_string(b
);
696 * The MIG defs for _asl_server_message specifies "dealloc",
697 * so we copy the string into a new vm buffer and send that.
700 kstatus
= vm_allocate(mach_task_self(), &out
, outlen
, TRUE
);
701 if (kstatus
!= KERN_SUCCESS
) break;
703 memcpy((void *)out
, cp
, outlen
);
704 _asl_server_message(asl_port
, (caddr_t
)out
, outlen
);
711 _simple_asl_log(int level
, const char *facility
, const char *message
)
713 _simple_asl_log_prog(level
, facility
, message
, getprogname());