2 * Copyright (c) 2005, 2006 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@
27 #include <sys/types.h>
29 #include <mach/mach_init.h>
30 #include <mach/vm_map.h>
33 #include <sys/socket.h>
40 #define VM_PAGE_SIZE 4096
41 #define SBUF_SIZE(s) (((SBUF *)(s))->b.end - ((SBUF *)(s))->b.buf + 1)
42 /* we use a small buffer to minimize stack usage constraints */
50 void (*full
)(struct _BUF
*);
53 typedef struct _SBUF
{
58 static int asl_socket
;
59 static pthread_once_t asl_socket_once
= PTHREAD_ONCE_INIT
;
61 /* private extern exports from asl.c */
62 const char *_asl_escape(unsigned char);
63 int _asl_server_socket(int *, struct sockaddr_un
*);
65 /* flush the buffer */
74 w
= write(b
->fd
, buf
, n
);
76 if(errno
== EINTR
|| errno
== EAGAIN
)
85 /* flush the buffer and reset the pointer */
93 /* enlarge the buffer */
101 new = (vm_address_t
)(b
->end
+ 1);
102 if(vm_allocate(mach_task_self(), &new, VM_PAGE_SIZE
, 0) == 0) {
103 /* page is adjacent */
104 b
->end
+= VM_PAGE_SIZE
;
108 snew
= (sold
+ VM_PAGE_SIZE
) & ~(VM_PAGE_SIZE
- 1);
109 if(vm_allocate(mach_task_self(), &new, snew
, 1) != 0)
110 longjmp(((SBUF
*)b
)->j
, 1); /* out of memory */
111 diff
= new - (vm_address_t
)b
->buf
;
112 memcpy((void *)new, b
->buf
, sold
);
113 if((intptr_t)(b
->buf
) & (VM_PAGE_SIZE
- 1)) {
114 sold
&= ~(VM_PAGE_SIZE
- 1);
115 b
->buf
= (char *)((intptr_t)(b
->buf
+ VM_PAGE_SIZE
) & ~(VM_PAGE_SIZE
- 1));
116 b
->end
= (char *)(new + snew
- 1);
118 b
->end
+= diff
+ VM_PAGE_SIZE
;
120 vm_deallocate(mach_task_self(), (vm_address_t
)b
->buf
, sold
);
122 b
->buf
= (char *)new;
126 static inline void put_s(BUF
*, _esc_func
, const char *);
127 /* output a single character */
129 put_c(BUF
*b
, _esc_func esc
, unsigned char c
)
133 if(esc
&& (cp
= esc(c
)) != NULL
)
142 /* output a null-terminated string */
144 put_s(BUF
*b
, _esc_func esc
, const char *str
)
147 put_c(b
, esc
, *str
++);
150 /* output a string of the specified size */
152 put_n(BUF
*b
, _esc_func esc
, const char *str
, int n
)
155 put_c(b
, esc
, *str
++);
159 * Output the signed decimal string representing the number in "in". "width" is
160 * the minimum field width, and "zero" is a boolean value, true for zero padding
161 * (otherwise blank padding).
164 dec(BUF
*b
, _esc_func esc
, long long in
, int width
, int zero
)
167 char *cp
= buf
+ sizeof(buf
);
170 unsigned long long n
= (unsigned long long)in
;
180 *--cp
= (n
% 10) + '0';
189 pad
= width
- strlen(cp
);
190 zero
= zero
? '0' : ' ';
199 * Output the hex string representing the number in "n". "width" is the
200 * minimum field width, and "zero" is a boolean value, true for zero padding
201 * (otherwise blank padding). "upper" is a boolean value, true for upper
202 * case hex characters, lower case otherwise. "p" is a boolean value, true
203 * if 0x should be prepended (for %p), otherwise nothing.
205 static char _h
[] = "0123456789abcdef";
206 static char _H
[] = "0123456789ABCDEF";
207 static char _0x
[] = "0x";
210 hex(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
, int upper
, int p
)
213 char *cp
= buf
+ sizeof(buf
);
214 char *h
= upper
? _H
: _h
;
232 zero
= zero
? '0' : ' ';
241 * Output the unsigned decimal string representing the number in "n". "width"
242 * is the minimum field width, and "zero" is a boolean value, true for zero
243 * padding (otherwise blank padding).
246 udec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
249 char *cp
= buf
+ sizeof(buf
);
255 *--cp
= (n
% 10) + '0';
260 pad
= width
- strlen(cp
);
261 zero
= zero
? '0' : ' ';
268 * Output the unsigned decimal string representing the number in "n", rounded
269 * to the nearest MB, KB or b. "width" is the minimum field width, and "zero"
270 * is a boolean value, true for zero padding (otherwise blank padding).
273 ydec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
275 if(n
>= 10 * (1 << 20)) {
277 udec(b
, esc
, n
>> 20, width
, zero
);
279 } else if (n
>= 10 * (1 << 10)) {
281 udec(b
, esc
, n
>> 10, width
, zero
);
284 udec(b
, esc
, n
, width
, zero
);
290 * The actual engine for all the _simple_*printf routines.
293 __simple_bprintf(BUF
*b
, _esc_func esc
, const char *fmt
, va_list ap
)
296 int lflag
, zero
, width
;
298 if(!(cp
= strchr(fmt
, '%'))) {
302 put_n(b
, esc
, fmt
, cp
- fmt
);
309 lflag
= zero
= width
= 0;
316 case '1': case '2': case '3': case '4': case '5':
317 case '6': case '7': case '8': case '9':
318 while(*fmt
>= '0' && *fmt
<= '9')
319 width
= 10 * width
+ (*fmt
++ - '0');
322 zero
= zero
? '0' : ' ';
326 put_c(b
, esc
, va_arg(ap
, int));
331 dec(b
, esc
, va_arg(ap
, int), width
, zero
);
334 dec(b
, esc
, va_arg(ap
, long), width
, zero
);
337 dec(b
, esc
, va_arg(ap
, long long), width
, zero
);
346 hex(b
, esc
, (unsigned long)va_arg(ap
, void *), width
, zero
, 0, 1);
349 cp
= va_arg(ap
, char *);
351 zero
= zero
? '0' : ' ';
359 udec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
362 udec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
365 udec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
372 hex(b
, esc
, va_arg(ap
, unsigned int), width
, zero
,
376 hex(b
, esc
, va_arg(ap
, unsigned long), width
, zero
,
380 hex(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
,
388 ydec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
391 ydec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
394 ydec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
409 * A simplified vfprintf variant. The format string is interpreted with
410 * arguments from the va_list, and the results are written to the given
414 _simple_vdprintf(int fd
, const char *fmt
, va_list ap
)
422 b
.end
= b
.buf
+ MYBUFSIZE
;
423 b
.full
= _flush_reset
;
424 __simple_bprintf(&b
, NULL
, fmt
, ap
);
429 * A simplified fprintf variant. The format string is interpreted with
430 * arguments from the variable argument list, and the results are written
431 * to the given file descriptor.
434 _simple_dprintf(int fd
, const char *fmt
, ...)
439 _simple_vdprintf(fd
, fmt
, ap
);
444 * A simplified string allocate routine. Pass the opaque pointer to structure
445 * to _simple_*sprintf() routines. Use _simple_string() to retrieve the
446 * current string (the string is guaranteed to be null terminated only on
447 * the call to _simple_string()). Use _simple_sfree() to free the structure
455 if(vm_allocate(mach_task_self(), (vm_address_t
*)&b
, VM_PAGE_SIZE
, 1))
457 b
->b
.ptr
= b
->b
.buf
= (char *)b
+ sizeof(SBUF
);
458 b
->b
.end
= (char *)b
+ VM_PAGE_SIZE
- 1;
459 b
->b
.full
= _enlarge
;
460 return (_SIMPLE_STRING
)b
;
464 * The format string is interpreted with arguments from the va_list, and the
465 * results are appended to the string maintained by the opaque structure, as
466 * returned by a previous call to _simple_salloc(). Non-zero is returned on
467 * out-of-memory error.
470 _simple_vsprintf(_SIMPLE_STRING b
, const char *fmt
, va_list ap
)
472 return _simple_vesprintf(b
, NULL
, fmt
, ap
);
476 * The format string is interpreted with arguments from the variable argument
477 * list, and the results are appended to the string maintained by the opaque
478 * structure, as returned by a previous call to _simple_salloc(). Non-zero is
479 * returned on out-of-memory error.
482 _simple_sprintf(_SIMPLE_STRING b
, const char *fmt
, ...)
488 ret
= _simple_vesprintf(b
, NULL
, fmt
, ap
);
494 * Like _simple_vsprintf(), except __esc is a function to call on each
495 * character; the function returns NULL if the character should be passed
496 * as is, otherwise, the returned character string is used instead.
499 _simple_vesprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, va_list ap
)
501 if(setjmp(((SBUF
*)b
)->j
))
503 __simple_bprintf((BUF
*)b
, esc
, fmt
, ap
);
508 * Like _simple_sprintf(), except __esc is a function to call on each
509 * character; the function returns NULL if the character should be passed
510 * as is, otherwise, the returned character string is used instead.
512 int _simple_esprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, ...)
518 ret
= _simple_vesprintf(b
, esc
, fmt
, ap
);
524 * Return the null terminated string from the opaque structure, as returned
525 * by a previous call to _simple_salloc().
528 _simple_string(_SIMPLE_STRING b
)
530 *((BUF
*)b
)->ptr
= 0;
531 return ((BUF
*)b
)->buf
;
535 * Reposition the pointer to the first null in the buffer. After a call to
536 * _simple_string, the buffer can be modified, and shrunk.
539 _simple_sresize(_SIMPLE_STRING b
)
541 ((BUF
*)b
)->ptr
= ((BUF
*)b
)->buf
+ strlen(((BUF
*)b
)->buf
);
545 * Append the null-terminated string to the string associated with the opaque
546 * structure. Non-zero is returned on out-of-memory error.
549 _simple_sappend(_SIMPLE_STRING b
, const char *str
)
551 return _simple_esappend(b
, NULL
, str
);
555 * Like _simple_sappend(), except __esc is a function to call on each
556 * character; the function returns NULL if the character should be passed
557 * as is, otherwise, the returned character string is used instead.
559 int _simple_esappend(_SIMPLE_STRING b
, _esc_func esc
, const char *str
)
561 if(setjmp(((SBUF
*)b
)->j
))
563 put_s((BUF
*)b
, esc
, str
);
568 * Write the string associated with the opaque structure to the file descriptor.
571 _simple_put(_SIMPLE_STRING b
, int fd
)
578 * Write the string associated with the opaque structure and a trailing newline,
579 * to the file descriptor.
582 _simple_putline(_SIMPLE_STRING b
, int fd
)
585 *((BUF
*)b
)->ptr
++ = '\n';
591 * Free the opaque structure, and the associated string.
594 _simple_sfree(_SIMPLE_STRING b
)
598 if(((intptr_t)(((SBUF
*)b
)->b
.buf
) & (VM_PAGE_SIZE
- 1)) == 0) {
599 vm_deallocate(mach_task_self(), (vm_address_t
)((SBUF
*)b
)->b
.buf
, SBUF_SIZE(b
));
602 s
= ((SBUF
*)b
)->b
.end
- (char *)b
+ 1;
603 vm_deallocate(mach_task_self(), (vm_address_t
)b
, s
);
607 * Simplified ASL log interface; does not use malloc. Unfortunately, this
608 * requires knowledge of the format used by ASL.
613 struct sockaddr_un server
;
614 _asl_server_socket(&asl_socket
, &server
);
618 _simple_asl_log(int level
, const char *facility
, const char *message
)
622 if(pthread_once(&asl_socket_once
, socket_init
) != 0)
624 if((b
= _simple_salloc()) == NULL
)
631 if(_simple_sprintf(b
, "%10u [Time ", 0))
633 gettimeofday(&tv
, NULL
);
634 if(_simple_esprintf(b
, _asl_escape
, "%lu", tv
.tv_sec
))
636 if(_simple_sappend(b
, "] [Host] [Sender "))
638 if(_simple_esappend(b
, _asl_escape
, getprogname()))
640 if(_simple_sappend(b
, "] [PID "))
642 if(_simple_esprintf(b
, _asl_escape
, "%u", getpid()))
644 if(_simple_sappend(b
, "] [UID "))
646 if(_simple_esprintf(b
, _asl_escape
, "%d", getuid()))
648 if(_simple_sappend(b
, "] [GID "))
650 if(_simple_esprintf(b
, _asl_escape
, "%d", getgid()))
652 if(_simple_sappend(b
, "] [Level "))
654 if(_simple_esprintf(b
, _asl_escape
, "%d", level
))
656 if(_simple_sappend(b
, "] [Message "))
658 if(_simple_esappend(b
, _asl_escape
, message
))
660 /* remove trailing (escaped) newlines */
661 cp
= _simple_string(b
);
665 if(strcmp(cp
, "\\n") != 0)
670 if(_simple_sappend(b
, "] [Facility "))
672 if(_simple_esappend(b
, _asl_escape
, facility
))
674 if(_simple_sappend(b
, "]\n"))
676 cp
= _simple_string(b
);
677 u
= strlen(cp
) - 10; // includes newline and null
682 while(bp
> cp
&& u
) {
683 *--bp
= u
% 10 + '0';
686 write(asl_socket
, cp
, strlen(cp
) + 1);