]>
Commit | Line | Data |
---|---|---|
70ad1dc8 A |
1 | /* |
2 | * Copyright (c) 2018 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_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. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
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. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | #include "internal.h" | |
24 | ||
25 | #pragma mark Utilities | |
70ad1dc8 | 26 | |
507116e3 A |
27 | /* |
28 | * Factored out from _get_parse_boot_arg_value for unit testing purposes | |
29 | */ | |
30 | static bool | |
31 | _parse_boot_arg_value(char *argsbuff, const char *which, char *where, size_t max) | |
70ad1dc8 | 32 | { |
507116e3 | 33 | bool found = false; |
70ad1dc8 | 34 | |
507116e3 A |
35 | char *token = NULL; |
36 | char *argsstr = argsbuff; | |
37 | static const char seps[] = { ' ', '\t', }; | |
38 | while ((token = strsep(&argsstr, seps)) != NULL) { | |
39 | bool is_boolean = false; | |
40 | ||
41 | char *value = NULL; | |
42 | char *equals = strchr(token, '='); | |
43 | if (token[0] == '-') { | |
44 | /* | |
45 | * Arguments whose names begins with "-" are booleans, so don't get | |
46 | * key=value splitting. Though I'd still discourage you from | |
47 | * naming your option "-edge=case". | |
48 | */ | |
49 | is_boolean = true; | |
50 | } else if (equals) { | |
51 | equals[0] = '\0'; | |
52 | value = &equals[1]; | |
53 | } else { | |
54 | is_boolean = true; | |
55 | } | |
56 | ||
57 | if (strcmp(which, token) == 0) { | |
58 | /* | |
59 | * Found it! Copy out the value as required. | |
60 | */ | |
61 | found = true; | |
62 | ||
63 | if (!where) { | |
64 | // Caller just wants to know whether the boot-arg exists. | |
65 | } else if (is_boolean || value == NULL) { | |
66 | strlcpy(where, "", max); | |
67 | } else { | |
68 | strlcpy(where, value, max); | |
69 | } | |
70 | ||
71 | break; | |
72 | } | |
70ad1dc8 A |
73 | } |
74 | ||
507116e3 | 75 | return found; |
70ad1dc8 A |
76 | } |
77 | ||
507116e3 A |
78 | /* |
79 | * This is (very) loosely based on the implementation of | |
80 | * PE_parse_boot_argn() (or at least the parts where I was able to easily | |
81 | * decipher the policy). | |
82 | */ | |
70ad1dc8 A |
83 | static bool |
84 | _get_boot_arg_value(const char *which, char *where, size_t max) | |
85 | { | |
70ad1dc8 | 86 | bool found = false; |
507116e3 A |
87 | __os_free char *argsbuff = NULL; |
88 | size_t argsbuff_len = 0; | |
89 | errno_t error = sysctlbyname_get_data_np("kern.bootargs", | |
90 | (void **)&argsbuff, &argsbuff_len); | |
70ad1dc8 | 91 | |
507116e3 A |
92 | if (!error) { |
93 | found = _parse_boot_arg_value(argsbuff, which, where, max); | |
70ad1dc8 A |
94 | } |
95 | ||
70ad1dc8 A |
96 | return found; |
97 | } | |
98 | ||
99 | #pragma mark API | |
100 | errno_t | |
101 | sysctl_get_data_np(int mib[4], size_t mib_cnt, void **buff, size_t *buff_len) | |
102 | { | |
507116e3 A |
103 | errno_t error = 0; |
104 | int ret = 0; | |
70ad1dc8 A |
105 | size_t needed = 0; |
106 | void *mybuff = NULL; | |
107 | ||
108 | // We need to get the length of the parameter so we can allocate a buffer | |
109 | // that's large enough. | |
507116e3 A |
110 | ret = sysctl(mib, (unsigned int)mib_cnt, NULL, &needed, NULL, 0); |
111 | if (ret) { | |
112 | error = errno; | |
70ad1dc8 A |
113 | goto __out; |
114 | } | |
115 | ||
116 | mybuff = malloc(needed); | |
117 | if (!mybuff) { | |
118 | error = errno; | |
119 | goto __out; | |
120 | } | |
121 | ||
507116e3 A |
122 | ret = sysctl(mib, (unsigned int)mib_cnt, mybuff, &needed, NULL, 0); |
123 | if (ret) { | |
70ad1dc8 A |
124 | // It's conceivable that some other process came along within this |
125 | // window and modified the variable to be even larger than we'd | |
126 | // previously been told, but if that's the case, just give up. | |
507116e3 | 127 | error = errno; |
70ad1dc8 A |
128 | goto __out; |
129 | } | |
130 | ||
131 | *buff = mybuff; | |
132 | *buff_len = needed; | |
133 | ||
134 | __out: | |
135 | if (error) { | |
136 | free(mybuff); | |
137 | } | |
138 | return error; | |
139 | } | |
140 | ||
141 | errno_t | |
142 | sysctlbyname_get_data_np(const char *mibdesc, void **buff, size_t *buff_len) | |
143 | { | |
144 | int ret = -1; | |
145 | int error = -1; | |
146 | int mib[4]; | |
147 | size_t mib_cnt = countof(mib); | |
148 | ||
149 | ret = sysctlnametomib(mibdesc, mib, &mib_cnt); | |
150 | if (ret) { | |
151 | error = errno; | |
152 | goto __out; | |
153 | } | |
154 | ||
155 | error = sysctl_get_data_np(mib, mib_cnt, buff, buff_len); | |
156 | ||
157 | __out: | |
158 | return error; | |
159 | } | |
160 | ||
161 | bool | |
162 | os_parse_boot_arg_int(const char *which, int64_t *where) | |
163 | { | |
164 | bool found = false; | |
165 | char buff[24] = {0}; | |
166 | char *endptr = NULL; | |
167 | int64_t val = 0; | |
168 | ||
169 | found = _get_boot_arg_value(which, buff, sizeof(buff)); | |
170 | if (!found || !where) { | |
171 | goto __out; | |
172 | } | |
173 | ||
174 | // A base of zero handles bases 8, 10, and 16. | |
175 | val = strtoll(buff, &endptr, 0); | |
176 | if (*endptr == 0) { | |
177 | *where = val; | |
178 | } else { | |
179 | // The boot-arg value was invalid, so say we didn't find it. | |
180 | found = false; | |
181 | } | |
182 | ||
183 | __out: | |
184 | return found; | |
185 | } | |
186 | ||
187 | bool | |
188 | os_parse_boot_arg_string(const char *which, char *where, size_t maxlen) | |
189 | { | |
190 | return _get_boot_arg_value(which, where, maxlen); | |
191 | } |