/* * 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 <sys/errno.h> #include <sys/types.h> #include <sys/malloc.h> #include <sys/buf.h> #include <sys/time.h> #include <sys/kauth.h> #include <sys/mount.h> #include <sys/vnode.h> #include <sys/syslog.h> #include <sys/vnode_internal.h> #include <sys/fslog.h> #include <sys/mount_internal.h> #include <sys/kasl.h> #include <dev/random/randomdev.h> #include <uuid/uuid.h> #include <stdarg.h> /* 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); /* * Note: can't use os_log_with_args() here because 'fmt' is * constructed on the stack i.e. doesn't come from a text * section. More importantly, the newer logging system * doesn't grok ASL either. */ 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); }