X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/bd504ef0e0b883cdd7917b73b3574eb9ce669905..39236c6e673c41db228275375ab7fdb0f837b292:/bsd/kern/kern_asl.c diff --git a/bsd/kern/kern_asl.c b/bsd/kern/kern_asl.c new file mode 100644 index 000000000..3d97f8113 --- /dev/null +++ b/bsd/kern/kern_asl.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +/* String to append as format modifier for each key-value pair */ +#define KASL_KEYVAL_FMT "[%s %s] " +#define KASL_KEYVAL_FMT_LEN (sizeof(KASL_KEYVAL_FMT) - 1) + +#define KASL_NEWLINE_CHAR "\n" +#define KASL_NEWLINE_CHAR_LEN (sizeof(KASL_NEWLINE_CHAR) - 1) + +/* Length of entire ASL message in 10 characters. Kernel defaults to zero */ +#define KASL_ASL_MSG_LEN " 0" + +/* Length of default format string to be used by printf */ +#define MAX_FMT_LEN 256 + + +/* Function to print input values as key-value pairs in format + * identifiable by Apple system log (ASL) facility. All key-value pairs + * are assumed to be pointer to strings and are provided using two ways - + * (a) va_list argument which is a list of varying number of arguments + * created by the caller of this function. + * (b) variable number of arguments passed to this function. + * + * Parameters - + * level - Priority level for this ASL message + * facility - Facility for this ASL message. + * num_pairs - Number of key-value pairs provided by vargs argument. + * vargs - List of key-value pairs. + * ... - Additional key-value pairs (apart from vargs) as variable + * argument list. A NULL value indicates the end of the + * variable argument list. + * + * Returns - + * zero - On success, when it prints all key-values pairs provided. + * E2BIG - When it cannot print all key-value pairs provided and had + * to truncate the output. + */ +int +kern_asl_msg_va(int level, const char *facility, int num_pairs, va_list vargs, ...) +{ + int err = 0; + char fmt[MAX_FMT_LEN]; /* Format string to use with vaddlog */ + int calc_pairs = 0; + size_t len; + int i; + va_list ap; + char *ptr; + + /* Mask extra bits, if any, from priority level */ + level = LOG_PRI(level); + + /* Create the first part of format string consisting of ASL + * message length, level, and facility. + */ + if (facility) { + snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] [%s %s] ", + KASL_ASL_MSG_LEN, + KASL_KEY_LEVEL, level, + KASL_KEY_FACILITY, facility); + } else { + snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] ", + KASL_ASL_MSG_LEN, + KASL_KEY_LEVEL, level); + } + + /* Determine the number of key-value format string [%s %s] that + * should be added in format string for every key-value pair provided + * in va_list. Calculate maximum number of format string that can be + * accommodated in the remaining format buffer (after saving space + * for newline character). If the caller provided pairs in va_list + * is more than calculated pairs, truncate extra pairs. + */ + len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1; + calc_pairs = len / KASL_KEYVAL_FMT_LEN; + if (num_pairs <= calc_pairs) { + calc_pairs = num_pairs; + } else { + err = E2BIG; + } + + /* Append format strings [%s %s] for the key-value pairs in vargs */ + len = MAX_FMT_LEN - KASL_NEWLINE_CHAR_LEN; + for (i = 0; i < calc_pairs; i++) { + (void) strlcat(fmt, KASL_KEYVAL_FMT, len); + } + + /* Count number of variable arguments provided to this function + * and determine total number of key-value pairs. + */ + calc_pairs = 0; + va_start(ap, vargs); + ptr = va_arg(ap, char *); + while (ptr) { + calc_pairs++; + ptr = va_arg(ap, char *); + } + calc_pairs /= 2; + va_end(ap); + + /* If user provided variable number of arguments, append them as + * as real key-value "[k v]" into the format string. If the format + * string is too small, ignore the key-value pair completely. + */ + if (calc_pairs) { + char *key, *val; + size_t pairlen; + int offset; + + /* Calculate bytes available for key-value pairs after reserving + * bytes for newline character and NULL terminator + */ + len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1; + offset = strlen(fmt); + + va_start(ap, vargs); + for (i = 0; i < calc_pairs; i++) { + key = va_arg(ap, char *); + val = va_arg(ap, char *); + + /* Calculate bytes required to store next key-value pair + * as "[key val] " including space for '[', ']', and + * two spaces. + */ + pairlen = strlen(key) + strlen(val) + 4; + if (pairlen > len) { + err = E2BIG; + break; + } + + /* len + 1 because one byte has been set aside for NULL + * terminator in calculation of 'len' above + */ + snprintf((fmt + offset), len + 1, KASL_KEYVAL_FMT, + key, val); + offset += pairlen; + len -= pairlen; + } + va_end(ap); + } + + /* Append newline */ + (void) strlcat(fmt, KASL_NEWLINE_CHAR, MAX_FMT_LEN); + + /* Print the key-value pairs in ASL format */ + vaddlog(fmt, vargs); + + return (err); +} + +int +kern_asl_msg(int level, const char *facility, int num_pairs, ...) +{ + int err; + va_list ap; + + va_start(ap, num_pairs); + err = kern_asl_msg_va(level, facility, + num_pairs, ap, NULL); + va_end(ap); + + return err; +} + +/* Search if given string contains '[' and ']'. If any, escape it by + * prefixing with a '\'. If the length of the string is not big enough, + * no changes are done and error is returned. + * + * Parameters - + * str - string that can contain '[' or ']', should be NULL terminated + * len - length, in bytes, of valid data, including NULL character. + * buflen - size of buffer that contains the string + */ +int +escape_str(char *str, int len, int buflen) +{ + int count; + char *src, *dst; + + /* Count number of characters to escape */ + src = str; + count = 0; + do { + if ((*src == '[') || (*src == ']')) { + count++; + } + } while (*src++); + + if (count) { + /* + * Check if the buffer has enough space to escape all + * characters + */ + if ((buflen - len) < count) { + return (ENOSPC); + } + + src = str + len; + dst = src + count; + while (count) { + *dst-- = *src; + if ((*src == '[') || (*src == ']')) { + /* Last char copied needs to be escaped */ + *dst-- = '\\'; + count--; + } + src--; + } + } + + return (0); +}