]> git.saurik.com Git - apple/libc.git/blob - libdarwin/bsd.c
Libc-1353.11.2.tar.gz
[apple/libc.git] / libdarwin / bsd.c
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
26
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)
32 {
33 bool found = false;
34
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 }
73 }
74
75 return found;
76 }
77
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 */
83 static bool
84 _get_boot_arg_value(const char *which, char *where, size_t max)
85 {
86 bool found = false;
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);
91
92 if (!error) {
93 found = _parse_boot_arg_value(argsbuff, which, where, max);
94 }
95
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 {
103 errno_t error = 0;
104 int ret = 0;
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.
110 ret = sysctl(mib, (unsigned int)mib_cnt, NULL, &needed, NULL, 0);
111 if (ret) {
112 error = errno;
113 goto __out;
114 }
115
116 mybuff = malloc(needed);
117 if (!mybuff) {
118 error = errno;
119 goto __out;
120 }
121
122 ret = sysctl(mib, (unsigned int)mib_cnt, mybuff, &needed, NULL, 0);
123 if (ret) {
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.
127 error = errno;
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 }