Fri Sep 30 06:16:47 2016 UTC ()
Be consistent about returning -1 on error. Don't return random errnos
instead.


(dholland)
diff -r1.11 -r1.12 src/lib/libc/gen/sysctlgetmibinfo.c

cvs diff -r1.11 -r1.12 src/lib/libc/gen/sysctlgetmibinfo.c (switch to unified diff)

--- src/lib/libc/gen/sysctlgetmibinfo.c 2014/05/16 12:22:32 1.11
+++ src/lib/libc/gen/sysctlgetmibinfo.c 2016/09/30 06:16:47 1.12
@@ -1,611 +1,618 @@ @@ -1,611 +1,618 @@
1/* $NetBSD: sysctlgetmibinfo.c,v 1.11 2014/05/16 12:22:32 martin Exp $ */ 1/* $NetBSD: sysctlgetmibinfo.c,v 1.12 2016/09/30 06:16:47 dholland Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2003,2004 The NetBSD Foundation, Inc. 4 * Copyright (c) 2003,2004 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Brown. 8 * by Andrew Brown.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33#if defined(LIBC_SCCS) && !defined(lint) 33#if defined(LIBC_SCCS) && !defined(lint)
34__RCSID("$NetBSD: sysctlgetmibinfo.c,v 1.11 2014/05/16 12:22:32 martin Exp $"); 34__RCSID("$NetBSD: sysctlgetmibinfo.c,v 1.12 2016/09/30 06:16:47 dholland Exp $");
35#endif /* LIBC_SCCS and not lint */ 35#endif /* LIBC_SCCS and not lint */
36 36
37#ifndef RUMP_ACTION 37#ifndef RUMP_ACTION
38#include "namespace.h" 38#include "namespace.h"
39#ifdef _REENTRANT 39#ifdef _REENTRANT
40#include "reentrant.h" 40#include "reentrant.h"
41#endif /* _REENTRANT */ 41#endif /* _REENTRANT */
42#endif /* RUMP_ACTION */ 42#endif /* RUMP_ACTION */
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/sysctl.h> 44#include <sys/sysctl.h>
45 45
46#include <assert.h> 46#include <assert.h>
47#include <errno.h> 47#include <errno.h>
48#include <inttypes.h> 48#include <inttypes.h>
49#include <stdlib.h> 49#include <stdlib.h>
50#include <string.h> 50#include <string.h>
51 51
52#ifdef RUMP_ACTION 52#ifdef RUMP_ACTION
53#include <rump/rump_syscalls.h> 53#include <rump/rump_syscalls.h>
54#define sysctl(a,b,c,d,e,f) rump_sys___sysctl(a,b,c,d,e,f) 54#define sysctl(a,b,c,d,e,f) rump_sys___sysctl(a,b,c,d,e,f)
55#else 55#else
56#ifdef __weak_alias 56#ifdef __weak_alias
57__weak_alias(__learn_tree,___learn_tree) 57__weak_alias(__learn_tree,___learn_tree)
58__weak_alias(sysctlgetmibinfo,_sysctlgetmibinfo) 58__weak_alias(sysctlgetmibinfo,_sysctlgetmibinfo)
59#endif 59#endif
60#endif 60#endif
61 61
62/* 62/*
63 * the place where we attach stuff we learn on the fly, not 63 * the place where we attach stuff we learn on the fly, not
64 * necessarily used. 64 * necessarily used.
65 */ 65 */
66static struct sysctlnode sysctl_mibroot = { 66static struct sysctlnode sysctl_mibroot = {
67#if defined(lint) 67#if defined(lint)
68 /* 68 /*
69 * lint doesn't like my initializers 69 * lint doesn't like my initializers
70 */ 70 */
71 0 71 0
72#else /* !lint */ 72#else /* !lint */
73 .sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE, 73 .sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE,
74 .sysctl_size = sizeof(struct sysctlnode), 74 .sysctl_size = sizeof(struct sysctlnode),
75 .sysctl_name = "(root)", 75 .sysctl_name = "(root)",
76#endif /* !lint */ 76#endif /* !lint */
77}; 77};
78 78
79/* 79/*
80 * routines to handle learning and cleanup 80 * routines to handle learning and cleanup
81 */ 81 */
82static int compar(const void *, const void *); 82static int compar(const void *, const void *);
83static void free_children(struct sysctlnode *); 83static void free_children(struct sysctlnode *);
84static void relearnhead(void); 84static void relearnhead(void);
85 85
86/* 86/*
87 * specifically not static since sysctl(8) "borrows" it. 87 * specifically not static since sysctl(8) "borrows" it.
88 */ 88 */
89int __learn_tree(int *, u_int, struct sysctlnode *); 89int __learn_tree(int *, u_int, struct sysctlnode *);
90 90
91/* 91/*
92 * for ordering nodes -- a query may or may not be given them in 92 * for ordering nodes -- a query may or may not be given them in
93 * numeric order 93 * numeric order
94 */ 94 */
95static int 95static int
96compar(const void *a, const void *b) 96compar(const void *a, const void *b)
97{ 97{
98 98
99 return (((const struct sysctlnode *)a)->sysctl_num - 99 return (((const struct sysctlnode *)a)->sysctl_num -
100 ((const struct sysctlnode *)b)->sysctl_num); 100 ((const struct sysctlnode *)b)->sysctl_num);
101} 101}
102 102
103/* 103/*
104 * recursively nukes a branch or an entire tree from the given node 104 * recursively nukes a branch or an entire tree from the given node
105 */ 105 */
106static void 106static void
107free_children(struct sysctlnode *rnode)  107free_children(struct sysctlnode *rnode)
108{ 108{
109 struct sysctlnode *node; 109 struct sysctlnode *node;
110 110
111 if (rnode == NULL || 111 if (rnode == NULL ||
112 SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE || 112 SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE ||
113 rnode->sysctl_child == NULL) 113 rnode->sysctl_child == NULL)
114 return; 114 return;
115 115
116 for (node = rnode->sysctl_child; 116 for (node = rnode->sysctl_child;
117 node < &rnode->sysctl_child[rnode->sysctl_clen]; 117 node < &rnode->sysctl_child[rnode->sysctl_clen];
118 node++) { 118 node++) {
119 free_children(node); 119 free_children(node);
120 } 120 }
121 free(rnode->sysctl_child); 121 free(rnode->sysctl_child);
122 rnode->sysctl_child = NULL; 122 rnode->sysctl_child = NULL;
123} 123}
124 124
125/* 125/*
126 * verifies that the head of the tree in the kernel is the same as the 126 * verifies that the head of the tree in the kernel is the same as the
127 * head of the tree we already got, integrating new stuff and removing 127 * head of the tree we already got, integrating new stuff and removing
128 * old stuff, if it's not. 128 * old stuff, if it's not.
129 */ 129 */
130static void 130static void
131relearnhead(void) 131relearnhead(void)
132{ 132{
133 struct sysctlnode *h, *i, *o, qnode; 133 struct sysctlnode *h, *i, *o, qnode;
134 size_t si, so; 134 size_t si, so;
135 int rc, name; 135 int rc, name;
136 size_t nlen, olen, ni, oi; 136 size_t nlen, olen, ni, oi;
137 uint32_t t; 137 uint32_t t;
138 138
139 /* 139 /*
140 * if there's nothing there, there's no need to expend any 140 * if there's nothing there, there's no need to expend any
141 * effort 141 * effort
142 */ 142 */
143 if (sysctl_mibroot.sysctl_child == NULL) 143 if (sysctl_mibroot.sysctl_child == NULL)
144 return; 144 return;
145 145
146 /* 146 /*
147 * attempt to pull out the head of the tree, starting with the 147 * attempt to pull out the head of the tree, starting with the
148 * size we have now, and looping if we need more (or less) 148 * size we have now, and looping if we need more (or less)
149 * space 149 * space
150 */ 150 */
151 si = 0; 151 si = 0;
152 so = sysctl_mibroot.sysctl_clen * sizeof(struct sysctlnode); 152 so = sysctl_mibroot.sysctl_clen * sizeof(struct sysctlnode);
153 name = CTL_QUERY; 153 name = CTL_QUERY;
154 memset(&qnode, 0, sizeof(qnode)); 154 memset(&qnode, 0, sizeof(qnode));
155 qnode.sysctl_flags = SYSCTL_VERSION; 155 qnode.sysctl_flags = SYSCTL_VERSION;
156 do { 156 do {
157 si = so; 157 si = so;
158 h = malloc(si); 158 h = malloc(si);
159 rc = sysctl(&name, 1, h, &so, &qnode, sizeof(qnode)); 159 rc = sysctl(&name, 1, h, &so, &qnode, sizeof(qnode));
160 if (rc == -1 && errno != ENOMEM) 160 if (rc == -1 && errno != ENOMEM)
161 return; 161 return;
162 if (si < so) 162 if (si < so)
163 free(h); 163 free(h);
164 } while (si < so); 164 } while (si < so);
165 165
166 /* 166 /*
167 * order the new copy of the head 167 * order the new copy of the head
168 */ 168 */
169 nlen = so / sizeof(struct sysctlnode); 169 nlen = so / sizeof(struct sysctlnode);
170 qsort(h, nlen, sizeof(struct sysctlnode), compar); 170 qsort(h, nlen, sizeof(struct sysctlnode), compar);
171 171
172 /* 172 /*
173 * verify that everything is the same. if it is, we don't 173 * verify that everything is the same. if it is, we don't
174 * need to do any more work here. 174 * need to do any more work here.
175 */ 175 */
176 olen = sysctl_mibroot.sysctl_clen; 176 olen = sysctl_mibroot.sysctl_clen;
177 rc = (nlen == olen) ? 0 : 1; 177 rc = (nlen == olen) ? 0 : 1;
178 o = sysctl_mibroot.sysctl_child; 178 o = sysctl_mibroot.sysctl_child;
179 for (ni = 0; rc == 0 && ni < nlen; ni++) { 179 for (ni = 0; rc == 0 && ni < nlen; ni++) {
180 if (h[ni].sysctl_num != o[ni].sysctl_num || 180 if (h[ni].sysctl_num != o[ni].sysctl_num ||
181 h[ni].sysctl_ver != o[ni].sysctl_ver) 181 h[ni].sysctl_ver != o[ni].sysctl_ver)
182 rc = 1; 182 rc = 1;
183 } 183 }
184 if (rc == 0) { 184 if (rc == 0) {
185 free(h); 185 free(h);
186 return; 186 return;
187 } 187 }
188 188
189 /* 189 /*
190 * something changed. h will become the new head, and we need 190 * something changed. h will become the new head, and we need
191 * pull over any subtrees we already have if they're the same 191 * pull over any subtrees we already have if they're the same
192 * version. 192 * version.
193 */ 193 */
194 i = h; 194 i = h;
195 ni = oi = 0; 195 ni = oi = 0;
196 while (ni < nlen && oi < olen) { 196 while (ni < nlen && oi < olen) {
197 /* 197 /*
198 * something was inserted or deleted 198 * something was inserted or deleted
199 */ 199 */
200 if (SYSCTL_TYPE(i[ni].sysctl_flags) == CTLTYPE_NODE) 200 if (SYSCTL_TYPE(i[ni].sysctl_flags) == CTLTYPE_NODE)
201 i[ni].sysctl_child = NULL; 201 i[ni].sysctl_child = NULL;
202 if (i[ni].sysctl_num != o[oi].sysctl_num) { 202 if (i[ni].sysctl_num != o[oi].sysctl_num) {
203 if (i[ni].sysctl_num < o[oi].sysctl_num) { 203 if (i[ni].sysctl_num < o[oi].sysctl_num) {
204 ni++; 204 ni++;
205 } 205 }
206 else { 206 else {
207 free_children(&o[oi]); 207 free_children(&o[oi]);
208 oi++; 208 oi++;
209 } 209 }
210 continue; 210 continue;
211 } 211 }
212 212
213 /* 213 /*
214 * same number, but different version, so throw away 214 * same number, but different version, so throw away
215 * any accumulated children 215 * any accumulated children
216 */ 216 */
217 if (i[ni].sysctl_ver != o[oi].sysctl_ver) 217 if (i[ni].sysctl_ver != o[oi].sysctl_ver)
218 free_children(&o[oi]); 218 free_children(&o[oi]);
219 219
220 /* 220 /*
221 * this node is the same, but we only need to 221 * this node is the same, but we only need to
222 * move subtrees. 222 * move subtrees.
223 */ 223 */
224 else if (SYSCTL_TYPE(i[ni].sysctl_flags) == CTLTYPE_NODE) {  224 else if (SYSCTL_TYPE(i[ni].sysctl_flags) == CTLTYPE_NODE) {
225 /* 225 /*
226 * move subtree to new parent 226 * move subtree to new parent
227 */ 227 */
228 i[ni].sysctl_clen = o[oi].sysctl_clen; 228 i[ni].sysctl_clen = o[oi].sysctl_clen;
229 i[ni].sysctl_csize = o[oi].sysctl_csize; 229 i[ni].sysctl_csize = o[oi].sysctl_csize;
230 i[ni].sysctl_child = o[oi].sysctl_child; 230 i[ni].sysctl_child = o[oi].sysctl_child;
231 /* 231 /*
232 * reparent inherited subtree 232 * reparent inherited subtree
233 */ 233 */
234 for (t = 0; 234 for (t = 0;
235 i[ni].sysctl_child != NULL && 235 i[ni].sysctl_child != NULL &&
236 t < i[ni].sysctl_clen; 236 t < i[ni].sysctl_clen;
237 t++) 237 t++)
238 i[ni].sysctl_child[t].sysctl_parent = &i[ni]; 238 i[ni].sysctl_child[t].sysctl_parent = &i[ni];
239 } 239 }
240 ni++; 240 ni++;
241 oi++; 241 oi++;
242 } 242 }
243 243
244 /* 244 /*
245 * left over new nodes need to have empty subtrees cleared 245 * left over new nodes need to have empty subtrees cleared
246 */ 246 */
247 while (ni < nlen) { 247 while (ni < nlen) {
248 if (SYSCTL_TYPE(i[ni].sysctl_flags) == CTLTYPE_NODE) 248 if (SYSCTL_TYPE(i[ni].sysctl_flags) == CTLTYPE_NODE)
249 i[ni].sysctl_child = NULL; 249 i[ni].sysctl_child = NULL;
250 ni++; 250 ni++;
251 } 251 }
252 252
253 /* 253 /*
254 * left over old nodes need to be cleaned out 254 * left over old nodes need to be cleaned out
255 */ 255 */
256 while (oi < olen) { 256 while (oi < olen) {
257 free_children(&o[oi]); 257 free_children(&o[oi]);
258 oi++; 258 oi++;
259 } 259 }
260 260
261 /* 261 /*
262 * pop new head in 262 * pop new head in
263 */ 263 */
264 _DIAGASSERT(__type_fit(uint32_t, nlen)); 264 _DIAGASSERT(__type_fit(uint32_t, nlen));
265 sysctl_mibroot.sysctl_csize = 265 sysctl_mibroot.sysctl_csize =
266 sysctl_mibroot.sysctl_clen = (uint32_t)nlen; 266 sysctl_mibroot.sysctl_clen = (uint32_t)nlen;
267 sysctl_mibroot.sysctl_child = h; 267 sysctl_mibroot.sysctl_child = h;
268 free(o); 268 free(o);
269} 269}
270 270
271/* 271/*
272 * sucks in the children at a given level and attaches it to the tree. 272 * sucks in the children at a given level and attaches it to the tree.
273 */ 273 */
274int 274int
275__learn_tree(int *name, u_int namelen, struct sysctlnode *pnode) 275__learn_tree(int *name, u_int namelen, struct sysctlnode *pnode)
276{ 276{
277 struct sysctlnode qnode; 277 struct sysctlnode qnode;
278 uint32_t rc; 278 uint32_t rc;
279 size_t sz; 279 size_t sz;
280 280
281 if (pnode == NULL) 281 if (pnode == NULL)
282 pnode = &sysctl_mibroot; 282 pnode = &sysctl_mibroot;
283 if (SYSCTL_TYPE(pnode->sysctl_flags) != CTLTYPE_NODE) { 283 if (SYSCTL_TYPE(pnode->sysctl_flags) != CTLTYPE_NODE) {
284 errno = EINVAL; 284 errno = EINVAL;
285 return (-1); 285 return (-1);
286 } 286 }
287 if (pnode->sysctl_child != NULL) 287 if (pnode->sysctl_child != NULL)
288 return (0); 288 return (0);
289 289
290 if (pnode->sysctl_clen == 0) 290 if (pnode->sysctl_clen == 0)
291 sz = SYSCTL_DEFSIZE * sizeof(struct sysctlnode); 291 sz = SYSCTL_DEFSIZE * sizeof(struct sysctlnode);
292 else 292 else
293 sz = pnode->sysctl_clen * sizeof(struct sysctlnode); 293 sz = pnode->sysctl_clen * sizeof(struct sysctlnode);
294 pnode->sysctl_child = malloc(sz); 294 pnode->sysctl_child = malloc(sz);
295 if (pnode->sysctl_child == NULL) 295 if (pnode->sysctl_child == NULL)
296 return (-1); 296 return (-1);
297 297
298 name[namelen] = CTL_QUERY; 298 name[namelen] = CTL_QUERY;
299 pnode->sysctl_clen = 0; 299 pnode->sysctl_clen = 0;
300 pnode->sysctl_csize = 0; 300 pnode->sysctl_csize = 0;
301 memset(&qnode, 0, sizeof(qnode)); 301 memset(&qnode, 0, sizeof(qnode));
302 qnode.sysctl_flags = SYSCTL_VERSION; 302 qnode.sysctl_flags = SYSCTL_VERSION;
303 rc = sysctl(name, namelen + 1, pnode->sysctl_child, &sz, 303 rc = sysctl(name, namelen + 1, pnode->sysctl_child, &sz,
304 &qnode, sizeof(qnode)); 304 &qnode, sizeof(qnode));
305 if (sz == 0) { 305 if (sz == 0) {
306 free(pnode->sysctl_child); 306 free(pnode->sysctl_child);
307 pnode->sysctl_child = NULL; 307 pnode->sysctl_child = NULL;
308 return (rc); 308 return (rc);
309 } 309 }
310 if (rc) { 310 if (rc) {
311 free(pnode->sysctl_child); 311 free(pnode->sysctl_child);
312 pnode->sysctl_child = NULL; 312 pnode->sysctl_child = NULL;
313 if ((sz % sizeof(struct sysctlnode)) != 0) 313 if ((sz % sizeof(struct sysctlnode)) != 0)
314 errno = EINVAL; 314 errno = EINVAL;
315 if (errno != ENOMEM) 315 if (errno != ENOMEM)
316 return (rc); 316 return (rc);
317 } 317 }
318 318
319 if (pnode->sysctl_child == NULL) { 319 if (pnode->sysctl_child == NULL) {
320 pnode->sysctl_child = malloc(sz); 320 pnode->sysctl_child = malloc(sz);
321 if (pnode->sysctl_child == NULL) 321 if (pnode->sysctl_child == NULL)
322 return (-1); 322 return (-1);
323 323
324 rc = sysctl(name, namelen + 1, pnode->sysctl_child, &sz, 324 rc = sysctl(name, namelen + 1, pnode->sysctl_child, &sz,
325 &qnode, sizeof(qnode)); 325 &qnode, sizeof(qnode));
326 if (rc) { 326 if (rc) {
327 free(pnode->sysctl_child); 327 free(pnode->sysctl_child);
328 pnode->sysctl_child = NULL; 328 pnode->sysctl_child = NULL;
329 return (rc); 329 return (rc);
330 } 330 }
331 } 331 }
332 332
333 /* 333 /*
334 * how many did we get? 334 * how many did we get?
335 */ 335 */
336 sz /= sizeof(struct sysctlnode); 336 sz /= sizeof(struct sysctlnode);
337 pnode->sysctl_csize = pnode->sysctl_clen = (uint32_t)sz; 337 pnode->sysctl_csize = pnode->sysctl_clen = (uint32_t)sz;
338 if (pnode->sysctl_clen != sz) { 338 if (pnode->sysctl_clen != sz) {
339 free(pnode->sysctl_child); 339 free(pnode->sysctl_child);
340 pnode->sysctl_child = NULL; 340 pnode->sysctl_child = NULL;
341 errno = EINVAL; 341 errno = EINVAL;
342 return (-1); 342 return (-1);
343 } 343 }
344 344
345 /* 345 /*
346 * you know, the kernel doesn't really keep them in any 346 * you know, the kernel doesn't really keep them in any
347 * particular order...just like entries in a directory 347 * particular order...just like entries in a directory
348 */ 348 */
349 qsort(pnode->sysctl_child, pnode->sysctl_clen,  349 qsort(pnode->sysctl_child, pnode->sysctl_clen,
350 sizeof(struct sysctlnode), compar); 350 sizeof(struct sysctlnode), compar);
351 351
352 /* 352 /*
353 * rearrange parent<->child linkage 353 * rearrange parent<->child linkage
354 */ 354 */
355 for (rc = 0; rc < pnode->sysctl_clen; rc++) { 355 for (rc = 0; rc < pnode->sysctl_clen; rc++) {
356 pnode->sysctl_child[rc].sysctl_parent = pnode; 356 pnode->sysctl_child[rc].sysctl_parent = pnode;
357 if (SYSCTL_TYPE(pnode->sysctl_child[rc].sysctl_flags) == 357 if (SYSCTL_TYPE(pnode->sysctl_child[rc].sysctl_flags) ==
358 CTLTYPE_NODE) { 358 CTLTYPE_NODE) {
359 /* 359 /*
360 * these nodes may have children, but we 360 * these nodes may have children, but we
361 * haven't discovered that yet. 361 * haven't discovered that yet.
362 */ 362 */
363 pnode->sysctl_child[rc].sysctl_child = NULL; 363 pnode->sysctl_child[rc].sysctl_child = NULL;
364 } 364 }
365 pnode->sysctl_child[rc].sysctl_desc = NULL; 365 pnode->sysctl_child[rc].sysctl_desc = NULL;
366 } 366 }
367 367
368 return (0); 368 return (0);
369} 369}
370 370
371/* 371/*
372 * that's "given name" as a string, the integer form of the name fit 372 * that's "given name" as a string, the integer form of the name fit
373 * to be passed to sysctl(), "canonicalized name" (optional), and a 373 * to be passed to sysctl(), "canonicalized name" (optional), and a
374 * pointer to the length of the integer form. oh, and then a pointer 374 * pointer to the length of the integer form. oh, and then a pointer
375 * to the node, in case you (the caller) care. you can leave them all 375 * to the node, in case you (the caller) care. you can leave them all
376 * NULL except for gname, though that might be rather pointless, 376 * NULL except for gname, though that might be rather pointless,
377 * unless all you wanna do is verify that a given name is acceptable. 377 * unless all you wanna do is verify that a given name is acceptable.
378 * 378 *
379 * returns either 0 (everything was fine) or -1 and sets errno 379 * returns either 0 (everything was fine) or -1 and sets errno
380 * accordingly. if errno is set to EAGAIN, we detected a change to 380 * accordingly. if errno is set to EAGAIN, we detected a change to
381 * the mib while parsing, and you should try again. in the case of an 381 * the mib while parsing, and you should try again. in the case of an
382 * invalid node name, cname will be set to contain the offending name. 382 * invalid node name, cname will be set to contain the offending name.
383 */ 383 */
384#ifdef _REENTRANT 384#ifdef _REENTRANT
385static mutex_t sysctl_mutex = MUTEX_INITIALIZER; 385static mutex_t sysctl_mutex = MUTEX_INITIALIZER;
386static int sysctlgetmibinfo_unlocked(const char *, int *, u_int *, char *, 386static int sysctlgetmibinfo_unlocked(const char *, int *, u_int *, char *,
387 size_t *, struct sysctlnode **, int); 387 size_t *, struct sysctlnode **, int);
388#endif /* __REENTRANT */ 388#endif /* __REENTRANT */
389 389
390int 390int
391sysctlgetmibinfo(const char *gname, int *iname, u_int *namelenp, 391sysctlgetmibinfo(const char *gname, int *iname, u_int *namelenp,
392 char *cname, size_t *csz, struct sysctlnode **rnode, int v) 392 char *cname, size_t *csz, struct sysctlnode **rnode, int v)
393#ifdef _REENTRANT 393#ifdef _REENTRANT
394{ 394{
395 int rc; 395 int rc;
396 396
397 mutex_lock(&sysctl_mutex); 397 mutex_lock(&sysctl_mutex);
398 rc = sysctlgetmibinfo_unlocked(gname, iname, namelenp, cname, csz, 398 rc = sysctlgetmibinfo_unlocked(gname, iname, namelenp, cname, csz,
399 rnode, v); 399 rnode, v);
400 mutex_unlock(&sysctl_mutex); 400 mutex_unlock(&sysctl_mutex);
401 401
402 return (rc); 402 return (rc);
403} 403}
404 404
405static int 405static int
406sysctlgetmibinfo_unlocked(const char *gname, int *iname, u_int *namelenp, 406sysctlgetmibinfo_unlocked(const char *gname, int *iname, u_int *namelenp,
407 char *cname, size_t *csz, struct sysctlnode **rnode, 407 char *cname, size_t *csz, struct sysctlnode **rnode,
408 int v) 408 int v)
409#endif /* _REENTRANT */ 409#endif /* _REENTRANT */
410{ 410{
411 struct sysctlnode *pnode, *node; 411 struct sysctlnode *pnode, *node;
412 int name[CTL_MAXNAME], n, haven; 412 int name[CTL_MAXNAME], n, haven;
413 u_int ni, nl; 413 u_int ni, nl;
414 intmax_t q; 414 intmax_t q;
415 char sep[2], token[SYSCTL_NAMELEN], 415 char sep[2], token[SYSCTL_NAMELEN],
416 pname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME]; 416 pname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME];
417 const char *piece, *dot; 417 const char *piece, *dot;
418 char *t; 418 char *t;
419 size_t l; 419 size_t l;
420 420
421 if (rnode != NULL) { 421 if (rnode != NULL) {
422 if (*rnode == NULL) { 422 if (*rnode == NULL) {
423 /* XXX later deal with dealing back a sub version */ 423 /* XXX later deal with dealing back a sub version */
424 if (v != SYSCTL_VERSION) 424 if (v != SYSCTL_VERSION) {
425 return (EINVAL); 425 errno = EINVAL;
 426 return -1;
 427 }
426 428
427 pnode = &sysctl_mibroot; 429 pnode = &sysctl_mibroot;
428 } 430 }
429 else { 431 else {
430 /* this is just someone being silly */ 432 /* this is just someone being silly */
431 if (SYSCTL_VERS((*rnode)->sysctl_flags) != (uint32_t)v) 433 if (SYSCTL_VERS((*rnode)->sysctl_flags)
432 return (EINVAL); 434 != (uint32_t)v) {
 435 errno = EINVAL;
 436 return -1;
 437 }
433 438
434 /* XXX later deal with other people's trees */ 439 /* XXX later deal with other people's trees */
435 if (SYSCTL_VERS((*rnode)->sysctl_flags) != 440 if (SYSCTL_VERS((*rnode)->sysctl_flags) !=
436 SYSCTL_VERSION) 441 SYSCTL_VERSION) {
437 return (EINVAL); 442 errno = EINVAL;
 443 return -1;
 444 }
438 445
439 pnode = *rnode; 446 pnode = *rnode;
440 } 447 }
441 } 448 }
442 else 449 else
443 pnode = &sysctl_mibroot; 450 pnode = &sysctl_mibroot;
444 451
445 if (pnode == &sysctl_mibroot) 452 if (pnode == &sysctl_mibroot)
446 relearnhead(); 453 relearnhead();
447 454
448 nl = ni = 0; 455 nl = ni = 0;
449 token[0] = '\0'; 456 token[0] = '\0';
450 pname[0] = '\0'; 457 pname[0] = '\0';
451 node = NULL; 458 node = NULL;
452 459
453 /* 460 /*
454 * default to using '.' as the separator, but allow '/' as 461 * default to using '.' as the separator, but allow '/' as
455 * well, and then allow a leading separator 462 * well, and then allow a leading separator
456 */ 463 */
457 if ((dot = strpbrk(gname, "./")) == NULL) 464 if ((dot = strpbrk(gname, "./")) == NULL)
458 sep[0] = '.'; 465 sep[0] = '.';
459 else 466 else
460 sep[0] = dot[0]; 467 sep[0] = dot[0];
461 sep[1] = '\0'; 468 sep[1] = '\0';
462 if (gname[0] == sep[0]) { 469 if (gname[0] == sep[0]) {
463 strlcat(pname, sep, sizeof(pname)); 470 strlcat(pname, sep, sizeof(pname));
464 gname++; 471 gname++;
465 } 472 }
466 473
467#define COPY_OUT_DATA(t, c, cs, nlp, l) do { \ 474#define COPY_OUT_DATA(t, c, cs, nlp, l) do { \
468 if ((c) != NULL && (cs) != NULL) \ 475 if ((c) != NULL && (cs) != NULL) \
469 *(cs) = strlcpy((c), (t), *(cs)); \ 476 *(cs) = strlcpy((c), (t), *(cs)); \
470 else if ((cs) != NULL) \ 477 else if ((cs) != NULL) \
471 *(cs) = strlen(t) + 1; \ 478 *(cs) = strlen(t) + 1; \
472 if ((nlp) != NULL) \ 479 if ((nlp) != NULL) \
473 *(nlp) = (l); \ 480 *(nlp) = (l); \
474 } while (/*CONSTCOND*/0) 481 } while (/*CONSTCOND*/0)
475 482
476 piece = gname; 483 piece = gname;
477 while (piece != NULL && *piece != '\0') { 484 while (piece != NULL && *piece != '\0') {
478 /* 485 /*
479 * what was i looking for? 486 * what was i looking for?
480 */ 487 */
481 dot = strchr(piece, sep[0]); 488 dot = strchr(piece, sep[0]);
482 if (dot == NULL) { 489 if (dot == NULL) {
483 l = strlcpy(token, piece, sizeof(token)); 490 l = strlcpy(token, piece, sizeof(token));
484 if (l > sizeof(token)) { 491 if (l > sizeof(token)) {
485 COPY_OUT_DATA(piece, cname, csz, namelenp, nl); 492 COPY_OUT_DATA(piece, cname, csz, namelenp, nl);
486 errno = ENAMETOOLONG; 493 errno = ENAMETOOLONG;
487 return (-1); 494 return (-1);
488 } 495 }
489 } 496 }
490 else if (dot - piece > (intptr_t)(sizeof(token) - 1)) { 497 else if (dot - piece > (intptr_t)(sizeof(token) - 1)) {
491 COPY_OUT_DATA(token, cname, csz, namelenp, nl); 498 COPY_OUT_DATA(token, cname, csz, namelenp, nl);
492 errno = ENAMETOOLONG; 499 errno = ENAMETOOLONG;
493 return (-1); 500 return (-1);
494 } 501 }
495 else { 502 else {
496 strncpy(token, piece, (size_t)(dot - piece)); 503 strncpy(token, piece, (size_t)(dot - piece));
497 token[dot - piece] = '\0'; 504 token[dot - piece] = '\0';
498 } 505 }
499 506
500 /* 507 /*
501 * i wonder if this "token" is an integer? 508 * i wonder if this "token" is an integer?
502 */ 509 */
503 errno = 0; 510 errno = 0;
504 q = strtoimax(token, &t, 0); 511 q = strtoimax(token, &t, 0);
505 n = (int)q; 512 n = (int)q;
506 if (errno != 0 || *t != '\0') 513 if (errno != 0 || *t != '\0')
507 haven = 0; 514 haven = 0;
508 else if (q < INT_MIN || q > UINT_MAX) 515 else if (q < INT_MIN || q > UINT_MAX)
509 haven = 0; 516 haven = 0;
510 else 517 else
511 haven = 1; 518 haven = 1;
512 519
513 /* 520 /*
514 * make sure i have something to look at 521 * make sure i have something to look at
515 */ 522 */
516 if (SYSCTL_TYPE(pnode->sysctl_flags) != CTLTYPE_NODE) { 523 if (SYSCTL_TYPE(pnode->sysctl_flags) != CTLTYPE_NODE) {
517 if (haven && nl > 0) { 524 if (haven && nl > 0) {
518 strlcat(pname, sep, sizeof(pname)); 525 strlcat(pname, sep, sizeof(pname));
519 goto just_numbers; 526 goto just_numbers;
520 } 527 }
521 COPY_OUT_DATA(token, cname, csz, namelenp, nl); 528 COPY_OUT_DATA(token, cname, csz, namelenp, nl);
522 errno = ENOTDIR; 529 errno = ENOTDIR;
523 return (-1); 530 return (-1);
524 } 531 }
525 if (pnode->sysctl_child == NULL) { 532 if (pnode->sysctl_child == NULL) {
526 if (__learn_tree(name, nl, pnode) == -1) { 533 if (__learn_tree(name, nl, pnode) == -1) {
527 COPY_OUT_DATA(token, cname, csz, namelenp, nl); 534 COPY_OUT_DATA(token, cname, csz, namelenp, nl);
528 return (-1); 535 return (-1);
529 } 536 }
530 } 537 }
531 node = pnode->sysctl_child; 538 node = pnode->sysctl_child;
532 if (node == NULL) { 539 if (node == NULL) {
533 COPY_OUT_DATA(token, cname, csz, namelenp, nl); 540 COPY_OUT_DATA(token, cname, csz, namelenp, nl);
534 errno = ENOENT; 541 errno = ENOENT;
535 return (-1); 542 return (-1);
536 } 543 }
537 544
538 /* 545 /*
539 * now...is it there? 546 * now...is it there?
540 */ 547 */
541 for (ni = 0; ni < pnode->sysctl_clen; ni++) 548 for (ni = 0; ni < pnode->sysctl_clen; ni++)
542 if ((haven && ((n == node[ni].sysctl_num) || 549 if ((haven && ((n == node[ni].sysctl_num) ||
543 (node[ni].sysctl_flags & CTLFLAG_ANYNUMBER))) || 550 (node[ni].sysctl_flags & CTLFLAG_ANYNUMBER))) ||
544 strcmp(token, node[ni].sysctl_name) == 0) 551 strcmp(token, node[ni].sysctl_name) == 0)
545 break; 552 break;
546 if (ni >= pnode->sysctl_clen) { 553 if (ni >= pnode->sysctl_clen) {
547 COPY_OUT_DATA(token, cname, csz, namelenp, nl); 554 COPY_OUT_DATA(token, cname, csz, namelenp, nl);
548 errno = ENOENT; 555 errno = ENOENT;
549 return (-1); 556 return (-1);
550 } 557 }
551 558
552 /* 559 /*
553 * ah...it is. 560 * ah...it is.
554 */ 561 */
555 pnode = &node[ni]; 562 pnode = &node[ni];
556 if (nl > 0) 563 if (nl > 0)
557 strlcat(pname, sep, sizeof(pname)); 564 strlcat(pname, sep, sizeof(pname));
558 if (haven && n != pnode->sysctl_num) { 565 if (haven && n != pnode->sysctl_num) {
559 just_numbers: 566 just_numbers:
560 strlcat(pname, token, sizeof(pname)); 567 strlcat(pname, token, sizeof(pname));
561 name[nl] = n; 568 name[nl] = n;
562 } 569 }
563 else { 570 else {
564 strlcat(pname, pnode->sysctl_name, sizeof(pname)); 571 strlcat(pname, pnode->sysctl_name, sizeof(pname));
565 name[nl] = pnode->sysctl_num; 572 name[nl] = pnode->sysctl_num;
566 } 573 }
567 piece = (dot != NULL) ? dot + 1 : NULL; 574 piece = (dot != NULL) ? dot + 1 : NULL;
568 nl++; 575 nl++;
569 if (nl == CTL_MAXNAME) { 576 if (nl == CTL_MAXNAME) {
570 COPY_OUT_DATA(token, cname, csz, namelenp, nl); 577 COPY_OUT_DATA(token, cname, csz, namelenp, nl);
571 errno = ERANGE; 578 errno = ERANGE;
572 return (-1); 579 return (-1);
573 } 580 }
574 } 581 }
575 582
576 if (nl == 0) { 583 if (nl == 0) {
577 if (namelenp != NULL) 584 if (namelenp != NULL)
578 *namelenp = 0; 585 *namelenp = 0;
579 errno = EINVAL; 586 errno = EINVAL;
580 return (-1); 587 return (-1);
581 } 588 }
582 589
583 COPY_OUT_DATA(pname, cname, csz, namelenp, nl); 590 COPY_OUT_DATA(pname, cname, csz, namelenp, nl);
584 if (iname != NULL && namelenp != NULL) 591 if (iname != NULL && namelenp != NULL)
585 memcpy(iname, &name[0], MIN(nl, *namelenp) * sizeof(int)); 592 memcpy(iname, &name[0], MIN(nl, *namelenp) * sizeof(int));
586 if (namelenp != NULL) 593 if (namelenp != NULL)
587 *namelenp = nl; 594 *namelenp = nl;
588 if (rnode != NULL) { 595 if (rnode != NULL) {
589 if (*rnode != NULL) 596 if (*rnode != NULL)
590 /* 597 /*
591 * they gave us a private tree to work in, so 598 * they gave us a private tree to work in, so
592 * we give back a pointer into that private 599 * we give back a pointer into that private
593 * tree 600 * tree
594 */ 601 */
595 *rnode = pnode; 602 *rnode = pnode;
596 else { 603 else {
597 /* 604 /*
598 * they gave us a place to put the node data, 605 * they gave us a place to put the node data,
599 * so give them a copy 606 * so give them a copy
600 */ 607 */
601 *rnode = malloc(sizeof(struct sysctlnode)); 608 *rnode = malloc(sizeof(struct sysctlnode));
602 if (*rnode != NULL) { 609 if (*rnode != NULL) {
603 **rnode = *pnode; 610 **rnode = *pnode;
604 (*rnode)->sysctl_child = NULL; 611 (*rnode)->sysctl_child = NULL;
605 (*rnode)->sysctl_parent = NULL; 612 (*rnode)->sysctl_parent = NULL;
606 } 613 }
607 } 614 }
608 } 615 }
609 616
610 return (0); 617 return (0);
611} 618}