1 | /* |
2 | * Copyright (c) 2013 Apple Computer, Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
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. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | |
29 | #include <sys/errno.h> |
30 | #include <sys/types.h> |
31 | #include <sys/malloc.h> |
32 | #include <sys/buf.h> |
33 | #include <sys/time.h> |
34 | #include <sys/kauth.h> |
35 | #include <sys/mount.h> |
36 | #include <sys/vnode.h> |
37 | #include <sys/syslog.h> |
38 | #include <sys/vnode_internal.h> |
39 | #include <sys/fslog.h> |
40 | #include <sys/mount_internal.h> |
41 | #include <sys/kasl.h> |
42 | |
43 | #include <dev/random/randomdev.h> |
44 | |
45 | #include <uuid/uuid.h> |
46 | |
47 | #include <stdarg.h> |
48 | |
49 | /* String to append as format modifier for each key-value pair */ |
50 | #define KASL_KEYVAL_FMT "[%s %s] " |
51 | #define KASL_KEYVAL_FMT_LEN (sizeof(KASL_KEYVAL_FMT) - 1) |
52 | |
53 | #define KASL_NEWLINE_CHAR "\n" |
54 | #define KASL_NEWLINE_CHAR_LEN (sizeof(KASL_NEWLINE_CHAR) - 1) |
55 | |
56 | /* Length of entire ASL message in 10 characters. Kernel defaults to zero */ |
57 | #define KASL_ASL_MSG_LEN " 0" |
58 | |
59 | /* Length of default format string to be used by printf */ |
60 | #define MAX_FMT_LEN 256 |
61 | |
62 | |
63 | /* Function to print input values as key-value pairs in format |
64 | * identifiable by Apple system log (ASL) facility. All key-value pairs |
65 | * are assumed to be pointer to strings and are provided using two ways - |
66 | * (a) va_list argument which is a list of varying number of arguments |
67 | * created by the caller of this function. |
68 | * (b) variable number of arguments passed to this function. |
69 | * |
70 | * Parameters - |
71 | * level - Priority level for this ASL message |
72 | * facility - Facility for this ASL message. |
73 | * num_pairs - Number of key-value pairs provided by vargs argument. |
74 | * vargs - List of key-value pairs. |
75 | * ... - Additional key-value pairs (apart from vargs) as variable |
76 | * argument list. A NULL value indicates the end of the |
77 | * variable argument list. |
78 | * |
79 | * Returns - |
80 | * zero - On success, when it prints all key-values pairs provided. |
81 | * E2BIG - When it cannot print all key-value pairs provided and had |
82 | * to truncate the output. |
83 | */ |
84 | int |
85 | kern_asl_msg_va(int level, const char *facility, int num_pairs, va_list vargs, ...) |
86 | { |
87 | int err = 0; |
88 | char fmt[MAX_FMT_LEN]; /* Format string to use with vaddlog */ |
89 | int calc_pairs = 0; |
90 | size_t len; |
91 | int i; |
92 | va_list ap; |
93 | char *ptr; |
94 | |
95 | /* Mask extra bits, if any, from priority level */ |
96 | level = LOG_PRI(level); |
97 | |
98 | /* Create the first part of format string consisting of ASL |
99 | * message length, level, and facility. |
100 | */ |
101 | if (facility) { |
102 | snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] [%s %s] " , |
103 | KASL_ASL_MSG_LEN, |
104 | KASL_KEY_LEVEL, level, |
105 | KASL_KEY_FACILITY, facility); |
106 | } else { |
107 | snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] " , |
108 | KASL_ASL_MSG_LEN, |
109 | KASL_KEY_LEVEL, level); |
110 | } |
111 | |
112 | /* Determine the number of key-value format string [%s %s] that |
113 | * should be added in format string for every key-value pair provided |
114 | * in va_list. Calculate maximum number of format string that can be |
115 | * accommodated in the remaining format buffer (after saving space |
116 | * for newline character). If the caller provided pairs in va_list |
117 | * is more than calculated pairs, truncate extra pairs. |
118 | */ |
119 | len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1; |
120 | calc_pairs = len / KASL_KEYVAL_FMT_LEN; |
121 | if (num_pairs <= calc_pairs) { |
122 | calc_pairs = num_pairs; |
123 | } else { |
124 | err = E2BIG; |
125 | } |
126 | |
127 | /* Append format strings [%s %s] for the key-value pairs in vargs */ |
128 | len = MAX_FMT_LEN - KASL_NEWLINE_CHAR_LEN; |
129 | for (i = 0; i < calc_pairs; i++) { |
130 | (void) strlcat(fmt, KASL_KEYVAL_FMT, len); |
131 | } |
132 | |
133 | /* Count number of variable arguments provided to this function |
134 | * and determine total number of key-value pairs. |
135 | */ |
136 | calc_pairs = 0; |
137 | va_start(ap, vargs); |
138 | ptr = va_arg(ap, char *); |
139 | while (ptr) { |
140 | calc_pairs++; |
141 | ptr = va_arg(ap, char *); |
142 | } |
143 | calc_pairs /= 2; |
144 | va_end(ap); |
145 | |
146 | /* If user provided variable number of arguments, append them as |
147 | * as real key-value "[k v]" into the format string. If the format |
148 | * string is too small, ignore the key-value pair completely. |
149 | */ |
150 | if (calc_pairs) { |
151 | char *key, *val; |
152 | size_t pairlen; |
153 | int offset; |
154 | |
155 | /* Calculate bytes available for key-value pairs after reserving |
156 | * bytes for newline character and NULL terminator |
157 | */ |
158 | len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1; |
159 | offset = strlen(fmt); |
160 | |
161 | va_start(ap, vargs); |
162 | for (i = 0; i < calc_pairs; i++) { |
163 | key = va_arg(ap, char *); |
164 | val = va_arg(ap, char *); |
165 | |
166 | /* Calculate bytes required to store next key-value pair |
167 | * as "[key val] " including space for '[', ']', and |
168 | * two spaces. |
169 | */ |
170 | pairlen = strlen(key) + strlen(val) + 4; |
171 | if (pairlen > len) { |
172 | err = E2BIG; |
173 | break; |
174 | } |
175 | |
176 | /* len + 1 because one byte has been set aside for NULL |
177 | * terminator in calculation of 'len' above |
178 | */ |
179 | snprintf((fmt + offset), len + 1, KASL_KEYVAL_FMT, |
180 | key, val); |
181 | offset += pairlen; |
182 | len -= pairlen; |
183 | } |
184 | va_end(ap); |
185 | } |
186 | |
187 | /* Append newline */ |
188 | (void) strlcat(fmt, KASL_NEWLINE_CHAR, MAX_FMT_LEN); |
189 | |
190 | /* Print the key-value pairs in ASL format */ |
191 | vaddlog(fmt, vargs); |
192 | |
193 | /* |
194 | * Note: can't use os_log_with_args() here because 'fmt' is |
195 | * constructed on the stack i.e. doesn't come from a text |
196 | * section. More importantly, the newer logging system |
197 | * doesn't grok ASL either. |
198 | */ |
199 | |
200 | return (err); |
201 | } |
202 | |
203 | int |
204 | kern_asl_msg(int level, const char *facility, int num_pairs, ...) |
205 | { |
206 | int err; |
207 | va_list ap; |
208 | |
209 | va_start(ap, num_pairs); |
210 | err = kern_asl_msg_va(level, facility, |
211 | num_pairs, ap, NULL); |
212 | va_end(ap); |
213 | |
214 | return err; |
215 | } |
216 | |
217 | /* Search if given string contains '[' and ']'. If any, escape it by |
218 | * prefixing with a '\'. If the length of the string is not big enough, |
219 | * no changes are done and error is returned. |
220 | * |
221 | * Parameters - |
222 | * str - string that can contain '[' or ']', should be NULL terminated |
223 | * len - length, in bytes, of valid data, including NULL character. |
224 | * buflen - size of buffer that contains the string |
225 | */ |
226 | int |
227 | escape_str(char *str, int len, int buflen) |
228 | { |
229 | int count; |
230 | char *src, *dst; |
231 | |
232 | /* Count number of characters to escape */ |
233 | src = str; |
234 | count = 0; |
235 | do { |
236 | if ((*src == '[') || (*src == ']')) { |
237 | count++; |
238 | } |
239 | } while (*src++); |
240 | |
241 | if (count) { |
242 | /* |
243 | * Check if the buffer has enough space to escape all |
244 | * characters |
245 | */ |
246 | if ((buflen - len) < count) { |
247 | return (ENOSPC); |
248 | } |
249 | |
250 | src = str + len; |
251 | dst = src + count; |
252 | while (count) { |
253 | *dst-- = *src; |
254 | if ((*src == '[') || (*src == ']')) { |
255 | /* Last char copied needs to be escaped */ |
256 | *dst-- = '\\'; |
257 | count--; |
258 | } |
259 | src--; |
260 | } |
261 | } |
262 | |
263 | return (0); |
264 | } |
265 | |