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>
44 #define VM_PAGE_SIZE 4096
45 #define SBUF_SIZE(s) (((SBUF *)(s))->b.end - ((SBUF *)(s))->b.buf + 1)
46 /* we use a small buffer to minimize stack usage constraints */
54 void (*full
)(struct _BUF
*);
57 typedef struct _SBUF
{
61 #endif /* !VARIANT_DYLD */
64 static int asl_socket
;
65 static pthread_once_t asl_socket_once
= PTHREAD_ONCE_INIT
;
67 /* private extern exports from asl.c */
68 const char *_asl_escape(unsigned char);
70 /* flush the buffer */
79 w
= write(b
->fd
, buf
, n
);
81 if(errno
== EINTR
|| errno
== EAGAIN
)
90 /* flush the buffer and reset the pointer */
98 /* enlarge the buffer */
103 vm_size_t sold
, snew
;
106 new = (vm_address_t
)(b
->end
+ 1);
107 if(vm_allocate(mach_task_self(), &new, VM_PAGE_SIZE
, 0) == 0) {
108 /* page is adjacent */
109 b
->end
+= VM_PAGE_SIZE
;
113 snew
= (sold
+ VM_PAGE_SIZE
) & ~(VM_PAGE_SIZE
- 1);
114 if(vm_allocate(mach_task_self(), &new, snew
, 1) != 0)
116 longjmp(((SBUF
*)b
)->j
, 1); /* out of memory */
117 #else /* VARIANT_DYLD */
118 abort(); /* out of memory */
119 #endif /* !VARIANT_DYLD */
120 diff
= new - (vm_address_t
)b
->buf
;
121 memcpy((void *)new, b
->buf
, sold
);
122 if((intptr_t)(b
->buf
) & (VM_PAGE_SIZE
- 1)) {
123 sold
&= ~(VM_PAGE_SIZE
- 1);
124 b
->buf
= (char *)((intptr_t)(b
->buf
+ VM_PAGE_SIZE
) & ~(VM_PAGE_SIZE
- 1));
125 b
->end
= (char *)(new + snew
- 1);
127 b
->end
+= diff
+ VM_PAGE_SIZE
;
129 vm_deallocate(mach_task_self(), (vm_address_t
)b
->buf
, sold
);
131 b
->buf
= (char *)new;
135 static inline void put_s(BUF
*, _esc_func
, const char *);
136 /* output a single character */
138 put_c(BUF
*b
, _esc_func esc
, unsigned char c
)
142 if(esc
&& (cp
= esc(c
)) != NULL
)
151 /* output a null-terminated string */
153 put_s(BUF
*b
, _esc_func esc
, const char *str
)
156 put_c(b
, esc
, *str
++);
159 /* output a string of the specified size */
161 put_n(BUF
*b
, _esc_func esc
, const char *str
, int n
)
164 put_c(b
, esc
, *str
++);
168 * Output the signed decimal string representing the number in "in". "width" is
169 * the minimum field width, and "zero" is a boolean value, true for zero padding
170 * (otherwise blank padding).
173 dec(BUF
*b
, _esc_func esc
, long long in
, int width
, int zero
)
176 char *cp
= buf
+ sizeof(buf
);
179 unsigned long long n
= (unsigned long long)in
;
189 *--cp
= (n
% 10) + '0';
198 pad
= width
- strlen(cp
);
199 zero
= zero
? '0' : ' ';
208 * Output the hex string representing the number in "n". "width" is the
209 * minimum field width, and "zero" is a boolean value, true for zero padding
210 * (otherwise blank padding). "upper" is a boolean value, true for upper
211 * case hex characters, lower case otherwise. "p" is a boolean value, true
212 * if 0x should be prepended (for %p), otherwise nothing.
214 static char _h
[] = "0123456789abcdef";
215 static char _H
[] = "0123456789ABCDEF";
216 static char _0x
[] = "0x";
219 hex(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
, int upper
, int p
)
222 char *cp
= buf
+ sizeof(buf
);
223 char *h
= upper
? _H
: _h
;
241 zero
= zero
? '0' : ' ';
250 * Output the unsigned decimal string representing the number in "n". "width"
251 * is the minimum field width, and "zero" is a boolean value, true for zero
252 * padding (otherwise blank padding).
255 udec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
258 char *cp
= buf
+ sizeof(buf
);
264 *--cp
= (n
% 10) + '0';
269 pad
= width
- strlen(cp
);
270 zero
= zero
? '0' : ' ';
277 * Output the unsigned decimal string representing the number in "n", rounded
278 * to the nearest MB, KB or b. "width" is the minimum field width, and "zero"
279 * is a boolean value, true for zero padding (otherwise blank padding).
282 ydec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
284 if(n
>= 10 * (1 << 20)) {
286 udec(b
, esc
, n
>> 20, width
, zero
);
288 } else if (n
>= 10 * (1 << 10)) {
290 udec(b
, esc
, n
>> 10, width
, zero
);
293 udec(b
, esc
, n
, width
, zero
);
299 * The actual engine for all the _simple_*printf routines.
302 __simple_bprintf(BUF
*b
, _esc_func esc
, const char *fmt
, va_list ap
)
305 int lflag
, zero
, width
;
307 if(!(cp
= strchr(fmt
, '%'))) {
311 put_n(b
, esc
, fmt
, cp
- fmt
);
318 lflag
= zero
= width
= 0;
325 case '1': case '2': case '3': case '4': case '5':
326 case '6': case '7': case '8': case '9':
327 while(*fmt
>= '0' && *fmt
<= '9')
328 width
= 10 * width
+ (*fmt
++ - '0');
331 zero
= zero
? '0' : ' ';
335 put_c(b
, esc
, va_arg(ap
, int));
340 dec(b
, esc
, va_arg(ap
, int), width
, zero
);
343 dec(b
, esc
, va_arg(ap
, long), width
, zero
);
346 dec(b
, esc
, va_arg(ap
, long long), width
, zero
);
355 hex(b
, esc
, (unsigned long)va_arg(ap
, void *), width
, zero
, 0, 1);
358 cp
= va_arg(ap
, char *);
360 zero
= zero
? '0' : ' ';
368 udec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
371 udec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
374 udec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
381 hex(b
, esc
, va_arg(ap
, unsigned int), width
, zero
,
385 hex(b
, esc
, va_arg(ap
, unsigned long), width
, zero
,
389 hex(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
,
397 ydec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
400 ydec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
403 ydec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
418 * A simplified vfprintf variant. The format string is interpreted with
419 * arguments from the va_list, and the results are written to the given
423 _simple_vdprintf(int fd
, const char *fmt
, va_list ap
)
431 b
.end
= b
.buf
+ MYBUFSIZE
;
432 b
.full
= _flush_reset
;
433 __simple_bprintf(&b
, NULL
, fmt
, ap
);
438 * A simplified fprintf variant. The format string is interpreted with
439 * arguments from the variable argument list, and the results are written
440 * to the given file descriptor.
443 _simple_dprintf(int fd
, const char *fmt
, ...)
448 _simple_vdprintf(fd
, fmt
, ap
);
453 * A simplified string allocate routine. Pass the opaque pointer to structure
454 * to _simple_*sprintf() routines. Use _simple_string() to retrieve the
455 * current string (the string is guaranteed to be null terminated only on
456 * the call to _simple_string()). Use _simple_sfree() to free the structure
464 if(vm_allocate(mach_task_self(), (vm_address_t
*)&b
, VM_PAGE_SIZE
, 1))
466 b
->b
.ptr
= b
->b
.buf
= (char *)b
+ sizeof(SBUF
);
467 b
->b
.end
= (char *)b
+ VM_PAGE_SIZE
- 1;
468 b
->b
.full
= _enlarge
;
469 return (_SIMPLE_STRING
)b
;
473 * The format string is interpreted with arguments from the va_list, and the
474 * results are appended to the string maintained by the opaque structure, as
475 * returned by a previous call to _simple_salloc(). Non-zero is returned on
476 * out-of-memory error.
479 _simple_vsprintf(_SIMPLE_STRING b
, const char *fmt
, va_list ap
)
481 return _simple_vesprintf(b
, NULL
, fmt
, ap
);
485 * The format string is interpreted with arguments from the variable argument
486 * list, and the results are appended to the string maintained by the opaque
487 * structure, as returned by a previous call to _simple_salloc(). Non-zero is
488 * returned on out-of-memory error.
491 _simple_sprintf(_SIMPLE_STRING b
, const char *fmt
, ...)
497 ret
= _simple_vesprintf(b
, NULL
, fmt
, ap
);
503 * Like _simple_vsprintf(), except __esc is a function to call on each
504 * character; the function returns NULL if the character should be passed
505 * as is, otherwise, the returned character string is used instead.
508 _simple_vesprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, va_list ap
)
511 if(setjmp(((SBUF
*)b
)->j
))
513 #endif /* !VARIANT_DYLD */
514 __simple_bprintf((BUF
*)b
, esc
, fmt
, ap
);
519 * Like _simple_sprintf(), except __esc is a function to call on each
520 * character; the function returns NULL if the character should be passed
521 * as is, otherwise, the returned character string is used instead.
523 int _simple_esprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, ...)
529 ret
= _simple_vesprintf(b
, esc
, fmt
, ap
);
535 * Return the null terminated string from the opaque structure, as returned
536 * by a previous call to _simple_salloc().
539 _simple_string(_SIMPLE_STRING b
)
541 *((BUF
*)b
)->ptr
= 0;
542 return ((BUF
*)b
)->buf
;
546 * Reposition the pointer to the first null in the buffer. After a call to
547 * _simple_string, the buffer can be modified, and shrunk.
550 _simple_sresize(_SIMPLE_STRING b
)
552 ((BUF
*)b
)->ptr
= ((BUF
*)b
)->buf
+ strlen(((BUF
*)b
)->buf
);
556 * Append the null-terminated string to the string associated with the opaque
557 * structure. Non-zero is returned on out-of-memory error.
560 _simple_sappend(_SIMPLE_STRING b
, const char *str
)
562 return _simple_esappend(b
, NULL
, str
);
566 * Like _simple_sappend(), except __esc is a function to call on each
567 * character; the function returns NULL if the character should be passed
568 * as is, otherwise, the returned character string is used instead.
570 int _simple_esappend(_SIMPLE_STRING b
, _esc_func esc
, const char *str
)
573 if(setjmp(((SBUF
*)b
)->j
))
575 #endif /* !VARIANT_DYLD */
576 put_s((BUF
*)b
, esc
, str
);
581 * Write the string associated with the opaque structure to the file descriptor.
584 _simple_put(_SIMPLE_STRING b
, int fd
)
591 * Write the string associated with the opaque structure and a trailing newline,
592 * to the file descriptor.
595 _simple_putline(_SIMPLE_STRING b
, int fd
)
598 *((BUF
*)b
)->ptr
++ = '\n';
604 * Free the opaque structure, and the associated string.
607 _simple_sfree(_SIMPLE_STRING b
)
611 if(((intptr_t)(((SBUF
*)b
)->b
.buf
) & (VM_PAGE_SIZE
- 1)) == 0) {
612 vm_deallocate(mach_task_self(), (vm_address_t
)((SBUF
*)b
)->b
.buf
, SBUF_SIZE(b
));
615 s
= ((SBUF
*)b
)->b
.end
- (char *)b
+ 1;
616 vm_deallocate(mach_task_self(), (vm_address_t
)b
, s
);
620 * Simplified ASL log interface; does not use malloc. Unfortunately, this
621 * requires knowledge of the format used by ASL.
626 struct sockaddr_un server
;
628 server
.sun_family
= AF_UNIX
;
629 strncpy(server
.sun_path
, _PATH_LOG
, sizeof(server
.sun_path
));
630 asl_socket
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
631 if (asl_socket
< 0) return;
633 fcntl(asl_socket
, F_SETFD
, 1);
635 if (connect(asl_socket
, (struct sockaddr
*)&server
, sizeof(server
)) == -1)
643 _simple_asl_log(int level
, const char *facility
, const char *message
)
647 if(pthread_once(&asl_socket_once
, socket_init
) != 0)
649 if((b
= _simple_salloc()) == NULL
)
656 if(_simple_sprintf(b
, "%10u [Time ", 0))
658 gettimeofday(&tv
, NULL
);
659 if(_simple_esprintf(b
, _asl_escape
, "%lu", tv
.tv_sec
))
661 if(_simple_sappend(b
, "] [Host] [Sender "))
663 if(_simple_esappend(b
, _asl_escape
, getprogname()))
665 if(_simple_sappend(b
, "] [PID "))
667 if(_simple_esprintf(b
, _asl_escape
, "%u", getpid()))
669 if(_simple_sappend(b
, "] [UID "))
671 if(_simple_esprintf(b
, _asl_escape
, "%d", getuid()))
673 if(_simple_sappend(b
, "] [GID "))
675 if(_simple_esprintf(b
, _asl_escape
, "%d", getgid()))
677 if(_simple_sappend(b
, "] [Level "))
679 if(_simple_esprintf(b
, _asl_escape
, "%d", level
))
681 if(_simple_sappend(b
, "] [Message "))
683 if(_simple_esappend(b
, _asl_escape
, message
))
685 /* remove trailing (escaped) newlines */
686 cp
= _simple_string(b
);
690 if(strcmp(cp
, "\\n") != 0)
695 if(_simple_sappend(b
, "] [Facility "))
697 if(_simple_esappend(b
, _asl_escape
, facility
))
699 if(_simple_sappend(b
, "]\n"))
701 cp
= _simple_string(b
);
702 u
= strlen(cp
) - 10; // includes newline and null
707 while(bp
> cp
&& u
) {
708 *--bp
= u
% 10 + '0';
711 write(asl_socket
, cp
, strlen(cp
) + 1);