xref: /minix/minix/tests/test87.c (revision 045e0ed3)
1 /* Tests for sysctl(2) and the MIB service - by D.C. van Moolenbroek */
2 /* This test needs to run as root: many sysctl(2) calls are privileged. */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <pwd.h>
7 #include <sys/mman.h>
8 #include <sys/wait.h>
9 #include <minix/sysctl.h>
10 #include <assert.h>
11 
12 #define ITERATIONS 2
13 
14 #include "common.h"
15 
16 #define NONROOT_USER	"bin"		/* name of any unprivileged user */
17 
18 #define NEXT_VER(n)	(((n) + 1 == 0) ? 1 : ((n) + 1)) /* node version + 1 */
19 
20 static void *bad_ptr;			/* a pointer to unmapped memory */
21 static unsigned int nodes, objects;	/* stats for pre/post test check */
22 
23 /*
24  * Spawn a child process that drops privileges and then executes the given
25  * procedure.  The returned PID value is of the dead, cleaned-up child, and
26  * should be used only to check whether the child could store its own PID.
27  */
28 static pid_t
29 test_nonroot(void (* proc)(void))
30 {
31 	struct passwd *pw;
32 	pid_t pid;
33 	int status;
34 
35 	pid = fork();
36 
37 	switch (pid) {
38 	case -1:
39 		e(0);
40 		break;
41 	case 0:
42 		errct = 0;
43 
44 		if ((pw = getpwnam(NONROOT_USER)) == NULL) e(0);
45 
46 		if (setuid(pw->pw_uid) != 0) e(0);
47 
48 		proc();
49 
50 		exit(errct);
51 	default:
52 		if (wait(&status) != pid) e(0);
53 		if (!WIFEXITED(status)) e(0);
54 		if (WEXITSTATUS(status) != 0) e(0);
55 	}
56 
57 	return pid;
58 }
59 
60 /*
61  * Test basic operations from an unprivileged process.
62  */
63 static void
64 sub87a(void)
65 {
66 	size_t oldlen;
67 	pid_t pid;
68 	bool b;
69 	int i, mib[4];
70 
71 	pid = getpid();
72 
73 	mib[0] = CTL_MINIX;
74 	mib[1] = MINIX_TEST;
75 
76 	/* Regular reads should succeed. */
77 	mib[2] = TEST_INT;
78 	oldlen = sizeof(i);
79 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
80 	if (oldlen != sizeof(i)) e(0);
81 	if (i != 0x01020304) e(0);
82 
83 	mib[2] = TEST_BOOL;
84 	oldlen = sizeof(b);
85 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
86 	if (oldlen != sizeof(b)) e(0);
87 	if (b != false) e(0);
88 
89 	/* Regular writes should fail. */
90 	b = true;
91 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != -1) e(0);
92 	if (errno != EPERM) e(0);
93 
94 	oldlen = sizeof(b);
95 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
96 	if (oldlen != sizeof(b)) e(0);
97 	if (b != false) e(0);
98 
99 	/* Privileged reads and writes should fail. */
100 	mib[2] = TEST_PRIVATE;
101 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != -1) e(0);
102 	if (errno != EPERM) e(0);
103 
104 	oldlen = sizeof(i);
105 	i = 1;
106 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
107 	if (errno != EPERM) e(0);
108 	if (i != 1) e(0);
109 
110 	if (sysctl(mib, 3, NULL, NULL, &i, sizeof(i)) != -1) e(0);
111 	if (errno != EPERM) e(0);
112 
113 	mib[2] = TEST_SECRET;
114 	mib[3] = SECRET_VALUE;
115 	i = 0;
116 	oldlen = sizeof(i);
117 	if (sysctl(mib, 4, &i, &oldlen, NULL, 0) != -1) e(0);
118 	if (errno != EPERM) e(0);
119 	if (i == 12345) e(0);
120 
121 	mib[3]++;
122 	i = 0;
123 	oldlen = sizeof(i);
124 	if (sysctl(mib, 4, &i, &oldlen, NULL, 0) != -1) e(0);
125 	if (errno != EPERM) e(0);
126 
127 	/* Free-for-all writes should succeed. */
128 	mib[2] = TEST_ANYWRITE;
129 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
130 	if (oldlen != sizeof(i)) e(0);
131 
132 	i = pid;
133 	if (sysctl(mib, 3, NULL, NULL, &i, sizeof(i)) != 0) e(0);
134 
135 	i = 0;
136 	oldlen = sizeof(i);
137 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
138 	if (oldlen != sizeof(i)) e(0);
139 	if (i != pid) e(0);
140 }
141 
142 /*
143  * Test the basic sysctl(2) interface.
144  */
145 static void
146 test87a(void)
147 {
148 	char buf[32];
149 	size_t len, oldlen;
150 	pid_t pid;
151 	u_quad_t q;
152 	bool b, b2;
153 	int i, va[2], lastva = -1 /*gcc*/, mib[CTL_MAXNAME + 1];
154 
155 	subtest = 0;
156 
157 	mib[0] = INT_MAX; /* some root-level identifier that does not exist */
158 	for (i = 1; i <= CTL_MAXNAME; i++)
159 		mib[i] = i;
160 
161 	/*
162 	 * We cannot test for invalid 'name' and 'oldlenp' pointers, because
163 	 * those may be accessed directly by the libc system call stub.  The
164 	 * NetBSD part of the stub even accesses name[0] without checking
165 	 * namelen first.
166 	 */
167 	if (sysctl(mib, 0, NULL, NULL, NULL, 0) != -1) e(0);
168 	if (errno != EINVAL) e(0);
169 	if (sysctl(mib, INT_MAX, NULL, NULL, NULL, 0) != -1) e(0);
170 	if (errno != EINVAL) e(0);
171 	if (sysctl(mib, UINT_MAX, NULL, NULL, NULL, 0) != -1) e(0);
172 	if (errno != EINVAL) e(0);
173 	for (i = 1; i <= CTL_MAXNAME; i++) {
174 		if (sysctl(mib, i, NULL, NULL, NULL, 0) != -1) e(i);
175 		if (errno != ENOENT) e(i);
176 	}
177 	if (sysctl(mib, i, NULL, NULL, NULL, 0) != -1) e(0);
178 	if (errno != EINVAL) e(0);
179 
180 	/* Test names that are too short, right, and too long. */
181 	mib[0] = CTL_MINIX;
182 	if (sysctl(mib, 1, NULL, NULL, NULL, 0) != -1) e(0);
183 	if (errno != EISDIR) e(0);
184 	mib[1] = MINIX_TEST;
185 	if (sysctl(mib, 2, NULL, NULL, NULL, 0) != -1) e(0);
186 	if (errno != EISDIR) e(0);
187 	mib[2] = TEST_INT;
188 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != 0) e(0);
189 	mib[3] = 0;
190 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
191 	if (errno != ENOTDIR) e(0);
192 
193 	/* Do some tests with meta-identifiers (special keys). */
194 	mib[3] = CTL_QUERY;
195 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
196 	if (errno != ENOTDIR) e(0);
197 
198 	mib[2] = CTL_QUERY;
199 	mib[3] = 0;
200 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
201 	if (errno != EINVAL) e(0);
202 
203 	mib[2] = CTL_EOL; /* a known-invalid meta-identifier */
204 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
205 	if (errno != EOPNOTSUPP) e(0);
206 
207 	/* This case returns EINVAL now but might as well return EOPNOTSUPP. */
208 	mib[3] = 0;
209 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
210 	if (errno != EOPNOTSUPP && errno != EINVAL) e(0);
211 
212 	/* Make sure the given oldlen value is ignored when unused. */
213 	mib[2] = TEST_INT;
214 	oldlen = 0;
215 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
216 	if (oldlen != sizeof(int)) e(0);
217 	oldlen = 1;
218 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
219 	if (oldlen != sizeof(int)) e(0);
220 	oldlen = SSIZE_MAX;
221 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
222 	if (oldlen != sizeof(int)) e(0);
223 	oldlen = SIZE_MAX;
224 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
225 	if (oldlen != sizeof(int)) e(0);
226 
227 	/* Test retrieval with the exact length. */
228 	oldlen = sizeof(va[0]);
229 	va[0] = va[1] = -1;
230 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
231 	if (oldlen != sizeof(va[0])) e(0);
232 	if (va[0] != 0x01020304) e(0);
233 	if (va[1] != -1) e(0);
234 
235 	/* Test retrieval with a length that is too short. */
236 	for (i = 0; i < sizeof(va[0]); i++) {
237 		va[0] = -1;
238 		oldlen = i;
239 		if (sysctl(mib, 3, va, &oldlen, NULL, 0) != -1) e(0);
240 		if (errno != ENOMEM) e(0);
241 		if (oldlen != sizeof(va[0])) e(0);
242 		if (i == 0 && va[0] != -1) e(0);
243 		if (i > 0 && va[0] >= lastva) e(0);
244 		if (va[1] != -1) e(0);
245 		lastva = va[0];
246 	}
247 
248 	/* Test retrieval with a length that is too long. */
249 	oldlen = sizeof(va[0]) + 1;
250 	va[0] = -1;
251 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
252 	if (oldlen != sizeof(va[0])) e(0);
253 	if (va[0] != 0x01020304) e(0);
254 	if (va[1] != -1) e(0);
255 
256 	oldlen = SSIZE_MAX;
257 	va[0] = -1;
258 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
259 	if (oldlen != sizeof(va[0])) e(0);
260 	if (va[0] != 0x01020304) e(0);
261 	if (va[1] != -1) e(0);
262 
263 	oldlen = SIZE_MAX;
264 	va[0] = -1;
265 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
266 	if (oldlen != sizeof(va[0])) e(0);
267 	if (va[0] != 0x01020304) e(0);
268 	if (va[1] != -1) e(0);
269 
270 	/*
271 	 * Ensure that we cannot overwrite this read-only integer.  A write
272 	 * request must have both a pointer and a nonzero length, though.
273 	 */
274 	va[0] = 0x05060708;
275 	if (sysctl(mib, 3, NULL, NULL, NULL, 1) != 0) e(0);
276 	if (sysctl(mib, 3, NULL, NULL, va, 0) != 0) e(0);
277 	if (sysctl(mib, 3, NULL, NULL, va, sizeof(va[0])) != -1) e(0);
278 	if (errno != EPERM) e(0);
279 
280 	oldlen = sizeof(va[0]);
281 	va[0] = -1;
282 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
283 	if (oldlen != sizeof(va[0])) e(0);
284 	if (va[0] != 0x01020304) e(0);
285 	if (va[1] != -1) e(0);
286 
287 	/* Test retrieval into a bad pointer. */
288 	oldlen = sizeof(int);
289 	if (sysctl(mib, 3, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
290 	if (errno != EFAULT) e(0);
291 
292 	/*
293 	 * Test reading and writing booleans.  Booleans may actually be an int,
294 	 * a char, or just one bit of a char.  As a result, the MIB service can
295 	 * not test properly for non-bool values being passed in bool fields,
296 	 * and we can not do effective testing on this either, because in both
297 	 * cases our efforts may simply be optimized away, and result in
298 	 * unexpected success.
299 	 */
300 	mib[2] = TEST_BOOL;
301 	oldlen = sizeof(b);
302 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
303 	if (oldlen != sizeof(b)) e(0);
304 	if (b != false && b != true) e(0);
305 
306 	b = true;
307 	if (sysctl(mib, 3, NULL, &oldlen, &b, sizeof(b)) != 0) e(0);
308 	if (oldlen != sizeof(b)) e(0);
309 
310 	b = false;
311 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
312 	if (oldlen != sizeof(b)) e(0);
313 	if (b != true) e(0);
314 
315 	b = false;
316 	b2 = false;
317 	oldlen = sizeof(b2);
318 	if (sysctl(mib, 3, &b2, &oldlen, &b, sizeof(b)) != 0) e(0);
319 	if (oldlen != sizeof(b2)) e(0);
320 	if (b != false) e(0);
321 	if (b2 != true) e(0);
322 
323 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b) + 1) != -1) e(0);
324 	if (errno != EINVAL) e(0);
325 
326 	/*
327 	 * The MIB service does not support value swaps.  If we pass in the
328 	 * same buffer for old and new data, we expect that the old data stays.
329 	 */
330 	b = true;
331 	oldlen = sizeof(b);
332 	if (sysctl(mib, 3, &b, &oldlen, &b, sizeof(b)) != 0) e(0);
333 	if (oldlen != sizeof(b)) e(0);
334 	if (b != false) e(0);
335 
336 	b = true;
337 	oldlen = sizeof(b);
338 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
339 	if (oldlen != sizeof(b)) e(0);
340 	if (b != false) e(0);
341 
342 	/* Test reading and writing a quad. */
343 	mib[2] = TEST_QUAD;
344 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
345 	if (oldlen != sizeof(q)) e(0);
346 
347 	q = 0x1234567890abcdefULL;
348 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
349 
350 	q = 0ULL;
351 	oldlen = sizeof(q);
352 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
353 	if (oldlen != sizeof(q)) e(0);
354 	if (q != 0x1234567890abcdefULL) e(0);
355 
356 	q = ~0ULL;
357 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
358 
359 	/* Test writing with a bad pointer.  The value must stay. */
360 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(q)) != -1) e(0);
361 	if (errno != EFAULT) e(0);
362 
363 	q = 0ULL;
364 	oldlen = sizeof(q);
365 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
366 	if (oldlen != sizeof(q)) e(0);
367 	if (q != ~0ULL) e(0);
368 
369 	q = 0ULL;
370 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
371 
372 	q = 1ULL;
373 	oldlen = sizeof(q);
374 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
375 	if (oldlen != sizeof(q)) e(0);
376 	if (q != 0ULL) e(0);
377 
378 	/* Test reading and writing a string. */
379 	mib[2] = TEST_STRING;
380 	strlcpy(buf, "test", sizeof(buf));
381 	len = strlen(buf);
382 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != 0) e(0);
383 
384 	oldlen = sizeof(buf);
385 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
386 	if (oldlen != len + 1) e(0);
387 
388 	memset(buf, 0x07, sizeof(buf));
389 	oldlen = sizeof(buf);
390 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
391 	if (strcmp(buf, "test")) e(0);
392 	if (oldlen != len + 1) e(0);
393 	if (buf[len + 1] != 0x07) e(0);
394 
395 	strlcpy(buf, "abc123", sizeof(buf));
396 	oldlen = 2;
397 	if (sysctl(mib, 3, NULL, &oldlen, buf, strlen(buf) + 1) != 0) e(0);
398 	if (oldlen != len + 1) e(0);
399 	len = strlen(buf);
400 
401 	memset(buf, 0x07, sizeof(buf));
402 	oldlen = len - 1;
403 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
404 	if (errno != ENOMEM) e(0);
405 	if (oldlen != len + 1) e(0);
406 	if (strncmp(buf, "abc12", len - 1)) e(0);
407 	if (buf[len - 1] != 0x07 || buf[len] != 0x07) e(0);
408 
409 	memset(buf, 0x07, sizeof(buf));
410 	oldlen = len + 1;
411 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
412 	if (oldlen != len + 1) e(0);
413 	if (strcmp(buf, "abc123")) e(0);
414 
415 	/*
416 	 * Now put in a shorter string, without null terminator.  The string
417 	 * must be accepted; the null terminator must be added automatically.
418 	 */
419 	strlcpy(buf, "foolproof", sizeof(buf));
420 	len = strlen("foo");
421 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
422 
423 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
424 	if (oldlen != len + 1) e(0);
425 
426 	memset(buf, 0x07, sizeof(buf));
427 	oldlen = len;
428 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
429 	if (errno != ENOMEM) e(0);
430 	if (oldlen != len + 1) e(0);
431 	if (strncmp(buf, "foo", len)) e(0);
432 	if (buf[len] != 0x07) e(0);
433 
434 	memset(buf, 0x07, sizeof(buf));
435 	oldlen = sizeof(buf);
436 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
437 	if (oldlen != len + 1) e(0);
438 	if (strcmp(buf, "foo")) e(0);
439 	if (buf[len + 1] != 0x07) e(0);
440 
441 	/*
442 	 * Passing in more data after the string is fine, but whatever comes
443 	 * after the first null terminator is disregarded.
444 	 */
445 	strlcpy(buf, "barbapapa", sizeof(buf));
446 	len = strlen(buf);
447 	buf[3] = '\0';
448 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1)) e(0);
449 	len = strlen(buf);
450 
451 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
452 	if (oldlen != len + 1) e(0);
453 
454 	memset(buf, 0x07, sizeof(buf));
455 	oldlen = sizeof(buf);
456 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
457 	if (oldlen != len + 1) e(0);
458 	if (strcmp(buf, "bar")) e(0);
459 	if (buf[len + 1] != 0x07) e(0);
460 
461 	/* Test the maximum string length. */
462 	strlcpy(buf, "0123456789abcdef", sizeof(buf));
463 	len = strlen(buf);
464 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != -1) e(0);
465 	if (errno != EINVAL) e(0);
466 	if (sysctl(mib, 3, NULL, NULL, buf, len) != -1) e(0);
467 	if (errno != EINVAL) e(0);
468 
469 	buf[--len] = '\0';
470 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != 0) e(0);
471 	memset(buf, 0x07, sizeof(buf));
472 	oldlen = sizeof(buf);
473 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
474 	if (oldlen != len + 1) e(0);
475 	if (strcmp(buf, "0123456789abcde")) e(0);
476 	if (buf[len + 1] != 0x07) e(0);
477 
478 	/*
479 	 * Clearing out the field with zero-length data is not possible,
480 	 * because zero-length updates are disregarded at a higher level.
481 	 */
482 	if (sysctl(mib, 3, NULL, NULL, "", 0) != 0) e(0);
483 	memset(buf, 0x07, sizeof(buf));
484 	oldlen = sizeof(buf);
485 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
486 	if (oldlen != len + 1) e(0);
487 	if (strcmp(buf, "0123456789abcde")) e(0);
488 
489 	/* To clear the field, the null terminator is required. */
490 	if (sysctl(mib, 3, NULL, NULL, "", 1) != 0) e(0);
491 	memset(buf, 0x07, sizeof(buf));
492 	oldlen = sizeof(buf);
493 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
494 	if (oldlen != 1) e(0);
495 	if (buf[0] != '\0') e(0);
496 	if (buf[1] != 0x07) e(0);
497 
498 	/*
499 	 * Test reading and writing structures.  Structures are just blobs of
500 	 * data, with no special handling by default.  They can only be read
501 	 * and written all at once.
502 	 */
503 	mib[2] = TEST_STRUCT;
504 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
505 	if (oldlen != 12) e(0);
506 	len = oldlen;
507 
508 	for (i = 0; i < len + 1; i++)
509 		buf[i] = i + 1;
510 	if (sysctl(mib, 3, NULL, NULL, buf, len - 1) != -1) e(0);
511 	if (errno != EINVAL) e(0);
512 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != -1) e(0);
513 	if (errno != EINVAL) e(0);
514 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
515 
516 	memset(buf, 0x7f, sizeof(buf));
517 	oldlen = len - 1;
518 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
519 	if (errno != ENOMEM) e(0);
520 	if (oldlen != len) e(0);
521 	for (i = 0; i < len - 1; i++)
522 		if (buf[i] != i + 1) e(0);
523 	if (buf[i] != 0x7f) e(0);
524 
525 	memset(buf, 0x7f, sizeof(buf));
526 	oldlen = len + 1;
527 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
528 	if (oldlen != len) e(0);
529 	for (i = 0; i < len; i++)
530 		if (buf[i] != i + 1) e(0);
531 	if (buf[i] != 0x7f) e(0);
532 
533 	memset(buf, 0x7f, sizeof(buf));
534 	oldlen = len;
535 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
536 	for (i = 0; i < len; i++)
537 		if (buf[i] != i + 1) e(0);
538 	if (buf[len] != 0x7f) e(0);
539 
540 	/* Null characters are not treated in any special way. */
541 	for (i = 0; i < len; i++)
542 		buf[i] = !!i;
543 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
544 
545 	oldlen = len;
546 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
547 	if (oldlen != len) e(0);
548 	for (i = 0; i < len; i++)
549 		if (buf[i] != !!i) e(0);
550 	if (buf[len] != 0x7f) e(0);
551 
552 	memset(buf, 0, len);
553 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
554 
555 	oldlen = len;
556 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
557 	if (oldlen != len) e(0);
558 	for (i = 0; i < len; i++)
559 		if (buf[i] != 0) e(0);
560 	if (buf[len] != 0x7f) e(0);
561 
562 	/*
563 	 * Test private read and free-for-all write operations.  For starters,
564 	 * this test should run with superuser privileges, and thus should be
565 	 * able to read and write private fields.
566 	 */
567 	mib[2] = TEST_PRIVATE;
568 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
569 	if (oldlen != sizeof(va[0])) e(0);
570 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
571 	if (va[0] != -5375) e(0);
572 	if (sysctl(mib, 3, NULL, NULL, va, sizeof(va[0])) != 0) e(0);
573 
574 	mib[2] = TEST_SECRET;
575 	mib[3] = SECRET_VALUE;
576 	oldlen = sizeof(va[0]);
577 	if (sysctl(mib, 4, va, &oldlen, NULL, 0) != 0) e(0);
578 	if (va[0] != 12345) e(0);
579 	if (sysctl(mib, 4, NULL, NULL, va, sizeof(va[0])) != -1) e(0);
580 	if (errno != EPERM) e(0);
581 
582 	mib[3]++;
583 	i = 0;
584 	oldlen = sizeof(i);
585 	if (sysctl(mib, 4, &i, &oldlen, NULL, 0) != -1) e(0);
586 	if (errno != ENOENT) e(0);
587 
588 	/* Use a child process to test operations without root privileges. */
589 	pid = test_nonroot(sub87a);
590 
591 	/* The change made by the child should be visible to the parent. */
592 	mib[2] = TEST_ANYWRITE;
593 	va[0] = 0;
594 	oldlen = sizeof(va[0]);
595 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
596 	if (oldlen != sizeof(va[0])) e(0);
597 	if (va[0] != pid) e(0);
598 }
599 
600 /*
601  * Test queries from an unprivileged process.
602  */
603 static void
604 sub87b(void)
605 {
606 	struct sysctlnode scn[32];
607 	unsigned int count;
608 	size_t oldlen;
609 	int i, mib[4];
610 
611 	/* Query minix.test and make sure we do not get privileged values. */
612 	mib[0] = CTL_MINIX;
613 	mib[1] = MINIX_TEST;
614 	mib[2] = CTL_QUERY;
615 
616 	oldlen = sizeof(scn);
617 	if (sysctl(mib, 3, scn, &oldlen, NULL, 0) != 0) e(0);
618 	if (oldlen % sizeof(scn[0])) e(0);
619 	count = oldlen / sizeof(scn[0]);
620 	if (count < 8) e(0);
621 
622 	/*
623 	 * Do not bother doing the entire check again, but test enough to
624 	 * inspire confidence that only the right values are hidden.
625 	 */
626 	if (scn[0].sysctl_num != TEST_INT) e(0);
627 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
628 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
629 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE | CTLFLAG_HEX)) e(0);
630 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
631 	if (strcmp(scn[0].sysctl_name, "int")) e(0);
632 	if (scn[0].sysctl_ver == 0) e(0);
633 	if (scn[0].sysctl_size != sizeof(int)) e(0);
634 	if (scn[0].sysctl_idata != 0x01020304) e(0);
635 
636 	for (i = 0; i < count; i++)
637 		if (scn[i].sysctl_num == TEST_PRIVATE)
638 			break;
639 	if (i == count) e(0);
640 	if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_INT) e(0);
641 	if ((SYSCTL_FLAGS(scn[i].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
642 	    (CTLFLAG_READWRITE | CTLFLAG_PRIVATE | CTLFLAG_IMMEDIATE)) e(0);
643 	if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
644 	if (strcmp(scn[i].sysctl_name, "private")) e(0);
645 	if (scn[i].sysctl_size != sizeof(int)) e(0);
646 	if (scn[i].sysctl_idata != 0) e(0); /* private */
647 
648 	for (i = 0; i < count; i++)
649 		if (scn[i].sysctl_num == TEST_SECRET)
650 			break;
651 	if (i == count) e(0);
652 	if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_NODE) e(0);
653 	if ((SYSCTL_FLAGS(scn[i].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
654 	    (CTLFLAG_READONLY | CTLFLAG_PRIVATE)) e(0);
655 	if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
656 	if (strcmp(scn[i].sysctl_name, "secret")) e(0);
657 	if (scn[i].sysctl_ver == 0) e(0);
658 	if (scn[i].sysctl_size != sizeof(scn[0])) e(0);
659 	if (scn[i].sysctl_csize != 0) e(0); /* private */
660 	if (scn[i].sysctl_clen != 0) e(0); /* private */
661 
662 	/* Make sure that a query on minix.test.secret fails. */
663 	mib[2] = TEST_SECRET;
664 	mib[3] = CTL_QUERY;
665 	if (sysctl(mib, 4, NULL, &oldlen, NULL, 0) != -1) e(0);
666 	if (errno != EPERM) e(0);
667 }
668 
669 /*
670  * Test sysctl(2) queries.
671  */
672 static void
673 test87b(void)
674 {
675 	struct sysctlnode scn[32];
676 	unsigned int count;
677 	size_t len, oldlen;
678 	u_quad_t q;
679 	bool b;
680 	int i, mib[4];
681 
682 	subtest = 1;
683 
684 	/* We should be able to query the root key. */
685 	mib[0] = CTL_QUERY;
686 
687 	oldlen = 0;
688 	if (sysctl(mib, 1, NULL, &oldlen, NULL, 0) != 0) e(0);
689 	if (oldlen <= sizeof(scn[0])) e(0);
690 	if (oldlen % sizeof(scn[0])) e(0);
691 
692 	oldlen = sizeof(scn[0]);
693 	if (sysctl(mib, 1, scn, &oldlen, NULL, 0) != -1) e(0);
694 	if (errno != ENOMEM);
695 	if (oldlen <= sizeof(scn[0])) e(0);
696 	if (oldlen % sizeof(scn[0])) e(0);
697 
698 	/*
699 	 * We assume that the root node's first child is always CTL_KERN, which
700 	 * must be read-only and may have only the CTLFLAG_PERMANENT flag set.
701 	 */
702 	if (scn[0].sysctl_num != CTL_KERN) e(0);
703 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_NODE) e(0);
704 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
705 	    CTLFLAG_READONLY) e(0);
706 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
707 	if (strcmp(scn[0].sysctl_name, "kern")) e(0);
708 	if (scn[0].sysctl_ver == 0) e(0);
709 	if (scn[0].sysctl_size != sizeof(scn[0])) e(0);
710 	if ((int)scn[0].sysctl_csize <= 0) e(0);
711 	if ((int)scn[0].sysctl_clen <= 0) e(0);
712 	if (scn[0].sysctl_csize < scn[0].sysctl_clen) e(0);
713 
714 	/* Now do a more complete test on the minix.test subtree. */
715 	mib[0] = CTL_MINIX;
716 	mib[1] = MINIX_TEST;
717 
718 	/*
719 	 * Initialize a few immediate fields to nonzero so that we can test
720 	 * that their values are returned as a result of the query.
721 	 */
722 	mib[2] = TEST_BOOL;
723 	b = true;
724 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
725 
726 	mib[2] = TEST_QUAD;
727 	q = ~0;
728 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
729 
730 	mib[2] = CTL_QUERY;
731 
732 	oldlen = 1;
733 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
734 	if (oldlen % sizeof(scn[0])) e(0);
735 	if (oldlen >= sizeof(scn)) e(0);
736 	len = oldlen;
737 	count = len / sizeof(scn[0]);
738 	if (count < 8) e(0);
739 
740 	memset(scn, 0x7e, sizeof(scn));
741 	if (sysctl(mib, 3, scn, &oldlen, NULL, 0) != 0) e(0);
742 	if (oldlen != len) e(0);
743 	if (scn[count].sysctl_name[0] != 0x7e) e(0);
744 
745 	/*
746 	 * Again, we rely on the MIB service returning entries in ascending
747 	 * order for at least the static nodes.  We do not make assumptions
748 	 * about whether dynamic nodes are merged in or (as is the case as of
749 	 * writing) returned after the static nodes.  At this point there
750 	 * should be no dynamic nodes here yet anyway.  We mostly ignore
751 	 * CTLFLAG_PERMANENT in order to facilitate running this test on a
752 	 * remotely mounted subtree.
753 	 */
754 	if (scn[0].sysctl_num != TEST_INT) e(0);
755 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
756 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
757 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE | CTLFLAG_HEX)) e(0);
758 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
759 	if (strcmp(scn[0].sysctl_name, "int")) e(0);
760 	if (scn[0].sysctl_ver == 0) e(0);
761 	if (scn[0].sysctl_size != sizeof(int)) e(0);
762 	if (scn[0].sysctl_idata != 0x01020304) e(0);
763 
764 	if (scn[1].sysctl_num != TEST_BOOL) e(0);
765 	if (SYSCTL_TYPE(scn[1].sysctl_flags) != CTLTYPE_BOOL) e(0);
766 	if ((SYSCTL_FLAGS(scn[1].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
767 	    (CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE)) e(0);
768 	if (SYSCTL_VERS(scn[1].sysctl_flags) != SYSCTL_VERSION) e(0);
769 	if (strcmp(scn[1].sysctl_name, "bool")) e(0);
770 	if (scn[1].sysctl_ver == 0) e(0);
771 	if (scn[1].sysctl_size != sizeof(bool)) e(0);
772 	if (scn[1].sysctl_bdata != true) e(0);
773 
774 	if (scn[2].sysctl_num != TEST_QUAD) e(0);
775 	if (SYSCTL_TYPE(scn[2].sysctl_flags) != CTLTYPE_QUAD) e(0);
776 	if ((SYSCTL_FLAGS(scn[2].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
777 	    (CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE)) e(0);
778 	if (SYSCTL_VERS(scn[2].sysctl_flags) != SYSCTL_VERSION) e(0);
779 	if (strcmp(scn[2].sysctl_name, "quad")) e(0);
780 	if (scn[2].sysctl_ver == 0) e(0);
781 	if (scn[2].sysctl_size != sizeof(u_quad_t)) e(0);
782 	if (scn[2].sysctl_qdata != q) e(0);
783 
784 	if (scn[3].sysctl_num != TEST_STRING) e(0);
785 	if (SYSCTL_TYPE(scn[3].sysctl_flags) != CTLTYPE_STRING) e(0);
786 	if ((SYSCTL_FLAGS(scn[3].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
787 	    CTLFLAG_READWRITE) e(0);
788 	if (SYSCTL_VERS(scn[3].sysctl_flags) != SYSCTL_VERSION) e(0);
789 	if (strcmp(scn[3].sysctl_name, "string")) e(0);
790 	if (scn[3].sysctl_ver == 0) e(0);
791 	if (scn[3].sysctl_size != 16) e(0);
792 
793 	if (scn[4].sysctl_num != TEST_STRUCT) e(0);
794 	if (SYSCTL_TYPE(scn[4].sysctl_flags) != CTLTYPE_STRUCT) e(0);
795 	if ((SYSCTL_FLAGS(scn[4].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
796 	    CTLFLAG_READWRITE) e(0);
797 	if (SYSCTL_VERS(scn[4].sysctl_flags) != SYSCTL_VERSION) e(0);
798 	if (strcmp(scn[4].sysctl_name, "struct")) e(0);
799 	if (scn[4].sysctl_ver == 0) e(0);
800 	if (scn[4].sysctl_size != 12) e(0);
801 
802 	if (scn[5].sysctl_num != TEST_PRIVATE) e(0);
803 	if (SYSCTL_TYPE(scn[5].sysctl_flags) != CTLTYPE_INT) e(0);
804 	if ((SYSCTL_FLAGS(scn[5].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
805 	    (CTLFLAG_READWRITE | CTLFLAG_PRIVATE | CTLFLAG_IMMEDIATE)) e(0);
806 	if (SYSCTL_VERS(scn[5].sysctl_flags) != SYSCTL_VERSION) e(0);
807 	if (strcmp(scn[5].sysctl_name, "private")) e(0);
808 	if (scn[5].sysctl_ver == 0) e(0);
809 	if (scn[5].sysctl_size != sizeof(int)) e(0);
810 	if (scn[5].sysctl_idata != -5375) e(0);
811 
812 	if (scn[6].sysctl_num != TEST_ANYWRITE) e(0);
813 	if (SYSCTL_TYPE(scn[6].sysctl_flags) != CTLTYPE_INT) e(0);
814 	if ((SYSCTL_FLAGS(scn[6].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
815 	    (CTLFLAG_READWRITE | CTLFLAG_ANYWRITE | CTLFLAG_IMMEDIATE)) e(0);
816 	if (SYSCTL_VERS(scn[6].sysctl_flags) != SYSCTL_VERSION) e(0);
817 	if (strcmp(scn[6].sysctl_name, "anywrite")) e(0);
818 	if (scn[6].sysctl_ver == 0) e(0);
819 	if (scn[6].sysctl_size != sizeof(int)) e(0);
820 
821 	i = (scn[7].sysctl_num == TEST_DYNAMIC) ? 8 : 7;
822 
823 	if (scn[i].sysctl_num != TEST_SECRET) e(0);
824 	if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_NODE) e(0);
825 	if ((SYSCTL_FLAGS(scn[i].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
826 	    (CTLFLAG_READONLY | CTLFLAG_PRIVATE)) e(0);
827 	if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
828 	if (strcmp(scn[i].sysctl_name, "secret")) e(0);
829 	if (scn[i].sysctl_ver == 0) e(0);
830 	if (scn[i].sysctl_size != sizeof(scn[0])) e(0);
831 	if (scn[i].sysctl_csize != 1) e(0);
832 	if (scn[i].sysctl_clen != 1) e(0);
833 
834 	/*
835 	 * Now that we know how many entries there are in minix.test, also look
836 	 * at whether the right child length is returned in a query on its
837 	 * parent.  While doing that, see whether data structure versioning
838 	 * works as expected as well.  MINIX_TEST is hardcoded to zero so we
839 	 * expect it to be the first entry returned from a query.
840 	 */
841 	mib[1] = CTL_QUERY;
842 
843 	memset(scn, 0, sizeof(scn));
844 	scn[1].sysctl_flags = SYSCTL_VERS_0;
845 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1])) != -1) e(0);
846 	if (errno != EINVAL) e(0);
847 	scn[1].sysctl_flags = SYSCTL_VERS_1;
848 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1]) - 1) != -1)
849 		e(0);
850 	if (errno != EINVAL) e(0);
851 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1]) + 1) != -1)
852 		e(0);
853 	if (errno != EINVAL) e(0);
854 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1])) != 0) e(0);
855 	if (oldlen == 0) e(0);
856 	if (oldlen % sizeof(scn[0])) e(0);
857 
858 	oldlen = sizeof(scn[0]);
859 	scn[1].sysctl_flags = SYSCTL_VERS_0;
860 	if (sysctl(mib, 2, scn, &oldlen, &scn[1], sizeof(scn[1])) != -1) e(0);
861 	if (errno != EINVAL) e(0);
862 	oldlen = sizeof(scn[0]);
863 	scn[1].sysctl_flags = SYSCTL_VERS_1;
864 	if (sysctl(mib, 2, scn, &oldlen, &scn[1], sizeof(scn[1])) != 0 &&
865 	    errno != ENOMEM) e(0);
866 	if (oldlen == 0) e(0);
867 	if (oldlen % sizeof(scn[0])) e(0);
868 
869 	if (scn[0].sysctl_num != MINIX_TEST) e(0);
870 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_NODE) e(0);
871 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
872 	    (CTLFLAG_READWRITE | CTLFLAG_HIDDEN)) e(0);
873 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
874 	if (strcmp(scn[0].sysctl_name, "test")) e(0);
875 	if (scn[0].sysctl_ver == 0) e(0);
876 	if (scn[0].sysctl_size != sizeof(scn[0])) e(0);
877 	if ((int)scn[0].sysctl_clen != count) e(0);
878 	if (scn[0].sysctl_csize < scn[0].sysctl_clen) e(0);
879 
880 	/*
881 	 * Test querying minix.test.secret, which should have exactly one node.
882 	 * At the same time, test bad pointers.
883 	 */
884 	mib[1] = MINIX_TEST;
885 	mib[2] = TEST_SECRET;
886 	mib[3] = CTL_QUERY;
887 	oldlen = sizeof(scn);
888 	if (sysctl(mib, 4, NULL, &oldlen, bad_ptr, sizeof(scn[0])) != -1) e(0);
889 	if (errno != EFAULT) e(0);
890 
891 	oldlen = sizeof(scn[0]) * 2;
892 	if (sysctl(mib, 4, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
893 	if (errno != EFAULT) e(0);
894 
895 	memset(scn, 0x7, sizeof(scn[0]) * 2);
896 	oldlen = sizeof(scn[0]) * 2;
897 	if (sysctl(mib, 4, scn, &oldlen, NULL, 0) != 0) e(0);
898 	if (oldlen != sizeof(scn[0])) e(0);
899 
900 	if (scn[0].sysctl_num != SECRET_VALUE) e(0);
901 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
902 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
903 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE)) e(0);
904 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
905 	if (strcmp(scn[0].sysctl_name, "value")) e(0);
906 	if (scn[0].sysctl_ver == 0) e(0);
907 	if (scn[0].sysctl_size != sizeof(int)) e(0);
908 	if (scn[0].sysctl_idata != 12345) e(0);
909 	if (scn[1].sysctl_name[0] != 0x07) e(0);
910 
911 	/* Use a child process to test queries without root privileges. */
912 	(void)test_nonroot(sub87b);
913 
914 	/* Do some more path-related error code tests unrelated to the rest. */
915 	mib[1] = INT_MAX;
916 	mib[2] = CTL_QUERY;
917 	oldlen = sizeof(scn[0]);
918 	if (sysctl(mib, 3, &scn, &oldlen, NULL, 0) != -1) e(0);
919 	if (errno != ENOENT) e(0);
920 
921 	mib[1] = MINIX_TEST;
922 	mib[2] = TEST_INT;
923 	mib[3] = CTL_QUERY;
924 	oldlen = sizeof(scn[0]);
925 	if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
926 	if (errno != ENOTDIR) e(0); /* ..and not EPERM (_INT is read-only) */
927 
928 	mib[2] = TEST_BOOL;
929 	oldlen = sizeof(scn[0]);
930 	if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
931 	if (errno != ENOTDIR) e(0); /* (_BOOL is read-write) */
932 
933 	mib[2] = CTL_QUERY;
934 	oldlen = sizeof(scn[0]);
935 	if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
936 	if (errno != EINVAL) e(0);
937 }
938 
939 /*
940  * Attempt to create a node, using a given node template, identifier, and name
941  * string.  If other_id is nonnegative, the creation is expected to fail due to
942  * a collision with an existing node, which should have the ID other_id and the
943  * name string in other_name.  Otherwise, the creation may succeed or fail, and
944  * the caller must perform the appropriate checks.  On success, return the new
945  * node identifier.  On failure, return -1, with errno set.
946  */
947 static int
948 create_node(const int * path, unsigned int pathlen, struct sysctlnode * tmpscn,
949 	int id, const char * name, int other_id, const char * other_name)
950 {
951 	struct sysctlnode scn, oldscn;
952 	size_t oldlen;
953 	int r, mib[CTL_MAXNAME];
954 
955 	assert(pathlen < CTL_MAXNAME);
956 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
957 	mib[pathlen] = CTL_CREATE;
958 
959 	memcpy(&scn, tmpscn, sizeof(scn));
960 	scn.sysctl_num = id;
961 	strlcpy(scn.sysctl_name, name, sizeof(scn.sysctl_name));
962 	oldlen = sizeof(oldscn);
963 	r = sysctl(mib, pathlen + 1, &oldscn, &oldlen, &scn, sizeof(scn));
964 	if (other_id >= 0) { /* conflict expected */
965 		if (oldlen != sizeof(oldscn)) e(0);
966 		if (r != -1) e(0);
967 		if (errno != EEXIST) e(0);
968 		if (oldscn.sysctl_num != other_id) e(0);
969 		if (strcmp(oldscn.sysctl_name, other_name)) e(0);
970 		return -1;
971 	} else {
972 		if (r != 0)
973 			return r;
974 		if (oldlen != sizeof(oldscn)) e(0);
975 		return oldscn.sysctl_num;
976 	}
977 }
978 
979 /*
980  * Destroy a node by identifier in the given named node directory.  Return 0 on
981  * success.  Return -1 on failure, with errno set.
982  */
983 static int
984 destroy_node(const int * path, unsigned int pathlen, int id)
985 {
986 	struct sysctlnode scn;
987 	int mib[CTL_MAXNAME];
988 
989 	assert(pathlen < CTL_MAXNAME);
990 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
991 	mib[pathlen] = CTL_DESTROY;
992 
993 	memset(&scn, 0, sizeof(scn));
994 	scn.sysctl_flags = SYSCTL_VERSION;
995 	scn.sysctl_num = id;
996 
997 	return sysctl(mib, pathlen + 1, NULL, NULL, &scn, sizeof(scn));
998 }
999 
1000 /*
1001  * Obtain the node data for one particular node in a node directory, by its
1002  * parent path and identifier.  Return 0 on success, with the node details
1003  * stored in 'scn', or -1 on failure.
1004  */
1005 static int
1006 query_node(const int * path, unsigned int pathlen, int id,
1007 	struct sysctlnode * scn)
1008 {
1009 	struct sysctlnode scnset[32];
1010 	size_t oldlen;
1011 	unsigned int i;
1012 	int r, mib[CTL_MAXNAME];
1013 
1014 	assert(pathlen < CTL_MAXNAME);
1015 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
1016 	mib[pathlen] = CTL_QUERY;
1017 
1018 	oldlen = sizeof(scnset);
1019 	if ((r = sysctl(mib, pathlen + 1, scnset, &oldlen, NULL, 0)) != 0 &&
1020 	    errno != ENOMEM) e(0);
1021 	if (oldlen == 0 || oldlen % sizeof(scnset[0])) e(0);
1022 	for (i = 0; i < oldlen / sizeof(scnset[0]); i++)
1023 		if (scnset[i].sysctl_num == id)
1024 			break;
1025 	if (i == oldlen / sizeof(scnset[0])) {
1026 		if (r != 0) e(0); /* if this triggers, make scnset[] bigger! */
1027 		return -1;
1028 	}
1029 	memcpy(scn, &scnset[i], sizeof(*scn));
1030 	return 0;
1031 }
1032 
1033 /*
1034  * Test unprivileged node creation.
1035  */
1036 static void
1037 sub87c(void)
1038 {
1039 	struct sysctlnode scn;
1040 	int mib[4];
1041 
1042 	mib[0] = CTL_MINIX;
1043 	mib[1] = MINIX_TEST;
1044 	mib[2] = TEST_DYNAMIC;
1045 	mib[3] = CTL_CREATE;
1046 
1047 	memset(&scn, 0, sizeof(scn));
1048 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
1049 	    CTLFLAG_READONLY | CTLTYPE_INT;
1050 	scn.sysctl_size = sizeof(int);
1051 	scn.sysctl_num = CTL_CREATE;
1052 	scn.sysctl_idata = 777;
1053 	strlcpy(scn.sysctl_name, "nonroot", sizeof(scn.sysctl_name));
1054 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1055 	if (errno != EPERM) e(0);
1056 
1057 	mib[0] = CTL_CREATE;
1058 	scn.sysctl_num = CTL_MINIX + 1;
1059 	if (sysctl(mib, 1, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1060 	if (errno != EPERM) e(0);
1061 }
1062 
1063 /*
1064  * Test sysctl(2) node creation.
1065  */
1066 static void
1067 test87c(void)
1068 {
1069 	static const uint32_t badflags[] = {
1070 		SYSCTL_VERS_MASK, SYSCTL_TYPEMASK, CTLFLAG_PERMANENT,
1071 		CTLFLAG_ROOT, CTLFLAG_ANYNUMBER, CTLFLAG_ALIAS, CTLFLAG_MMAP,
1072 		CTLFLAG_OWNDESC
1073 	};
1074 	static const size_t badintsizes[] = {
1075 		0, 1, sizeof(int) - 1, sizeof(int) + 1, sizeof(int) * 2,
1076 		sizeof(int) * 4, SSIZE_MAX, SIZE_MAX
1077 	};
1078 	static const char *goodnames[] = {
1079 		"_", "a", "test_name", "_____foo", "bar_0_1_2_3", "_2bornot2b",
1080 		"abcdefghijklmnopqrstuvwxyz12345",
1081 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ67890",
1082 	};
1083 	static const char *badnames[] = {
1084 		"", "0", "test.name", "2bornot2b", "@a", "b[", "c`d", "{",
1085 		"\n", "\xff", "dir/name", "foo:bar",
1086 		"abcdefghijklmnopqrstuvwxyz123456"
1087 	};
1088 	struct sysctlnode scn, pscn, oldscn, newscn, tmpscn, scnset[32];
1089 	size_t oldlen, len;
1090 	char buf[32], seen[5];
1091 	bool b;
1092 	u_quad_t q;
1093 	int i, mib[CTL_MAXNAME], id[3];
1094 
1095 	subtest = 2;
1096 
1097 	/*
1098 	 * On the first run of this test, this call with actually destroy a
1099 	 * static node.  On subsequent runs, it may clean up the most likely
1100 	 * leftover from a previous failed test.
1101 	 */
1102 	mib[0] = CTL_MINIX;
1103 	mib[1] = MINIX_TEST;
1104 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
1105 
1106 	/* Get child statistics about the parent node, for later comparison. */
1107 	if (query_node(mib, 1, MINIX_TEST, &pscn) != 0) e(0);
1108 	if (pscn.sysctl_clen == 0) e(0);
1109 	if (pscn.sysctl_csize <= pscn.sysctl_clen) e(0);
1110 
1111 	/* Start by testing if we can actually create a node at all. */
1112 	mib[2] = CTL_CREATE;
1113 	memset(&scn, 0, sizeof(scn));
1114 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
1115 	    CTLFLAG_READONLY | CTLTYPE_INT;
1116 	scn.sysctl_size = sizeof(int);
1117 	scn.sysctl_num = TEST_DYNAMIC;
1118 	scn.sysctl_idata = 777;
1119 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
1120 	oldlen = sizeof(newscn);
1121 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1122 	if (oldlen != sizeof(newscn)) e(0);
1123 
1124 	memcpy(&tmpscn, &scn, sizeof(scn));
1125 
1126 	if (newscn.sysctl_num != TEST_DYNAMIC) e(0);
1127 	if (SYSCTL_TYPE(newscn.sysctl_flags) != CTLTYPE_INT) e(0);
1128 	if (SYSCTL_FLAGS(newscn.sysctl_flags) !=
1129 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE)) e(0);
1130 	if (SYSCTL_VERS(newscn.sysctl_flags) != SYSCTL_VERSION) e(0);
1131 	if (strcmp(newscn.sysctl_name, "dynamic")) e(0);
1132 	if (newscn.sysctl_ver == 0) e(0);
1133 	if (newscn.sysctl_size != sizeof(int)) e(0);
1134 	if (newscn.sysctl_idata != 777) e(0);
1135 
1136 	/* Can we also read its value? */
1137 	mib[2] = TEST_DYNAMIC;
1138 	i = 0;
1139 	oldlen = sizeof(i);
1140 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1141 	if (oldlen != sizeof(i)) e(0);
1142 	if (i != 777) e(0);
1143 
1144 	/* For now, we assume that basic node destruction works. */
1145 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1146 
1147 	/* Try some variants of invalid new node data. */
1148 	mib[2] = CTL_CREATE;
1149 	memcpy(&scn, &tmpscn, sizeof(scn));
1150 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
1151 	if (errno != EINVAL) e(0);
1152 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn) - 1) != -1) e(0);
1153 	if (errno != EINVAL) e(0);
1154 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn) + 1) != -1) e(0);
1155 	if (errno != EINVAL) e(0);
1156 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
1157 	if (errno != EFAULT) e(0);
1158 
1159 	/* Try with an invalid flags field. */
1160 	scn.sysctl_flags =
1161 	    (scn.sysctl_flags & ~SYSCTL_VERS_MASK) | SYSCTL_VERS_0;
1162 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1163 	if (errno != EINVAL) e(0);
1164 
1165 	scn.sysctl_flags &= ~SYSCTL_TYPEMASK; /* type 0 does not exist */
1166 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1167 	if (errno != EINVAL) e(0);
1168 
1169 	for (i = 0; i < __arraycount(badflags); i++) {
1170 		memcpy(&scn, &tmpscn, sizeof(scn));
1171 		scn.sysctl_flags |= badflags[i];
1172 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1173 		if (errno != EINVAL) e(i);
1174 	}
1175 
1176 	/* Try successful creation (and destruction) once more. */
1177 	memcpy(&scn, &tmpscn, sizeof(scn));
1178 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1179 
1180 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1181 
1182 	/* Try a combination of most valid flags. */
1183 	memcpy(&scn, &tmpscn, sizeof(scn));
1184 	scn.sysctl_flags &= ~CTLFLAG_READONLY; /* noop */
1185 	scn.sysctl_flags |= CTLFLAG_READWRITE | CTLFLAG_ANYWRITE |
1186 	    CTLFLAG_PRIVATE | CTLFLAG_HEX | CTLFLAG_HIDDEN | CTLFLAG_UNSIGNED;
1187 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1188 
1189 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1190 
1191 	/* Try invalid integer sizes.  We will get to other types in a bit. */
1192 	for (i = 0; i < __arraycount(badintsizes); i++) {
1193 		memcpy(&scn, &tmpscn, sizeof(scn));
1194 		scn.sysctl_size = badintsizes[i];
1195 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1196 		if (errno != EINVAL) e(i);
1197 	}
1198 
1199 	/*
1200 	 * For the value, we can supply IMMEDIATE, OWNDATA, or neither.  For
1201 	 * IMMEDIATE, the integer value is taken directly from sysctl_idata.
1202 	 * If OWNDATA is set, sysctl_data may be set, in which case the integer
1203 	 * value is copied in from there.  If sysctl_data is NULL, the integer
1204 	 * is initalized to zero.  If neither flag is set, sysctl_data must be
1205 	 * NULL, since we do not support kernel addresses, and the integer will
1206 	 * similarly be initialized to zero.  If both flags are set, the call
1207 	 * fails with EINVAL.
1208 	 */
1209 	memcpy(&scn, &tmpscn, sizeof(scn));
1210 	scn.sysctl_flags |= CTLFLAG_OWNDATA; /* both flags are now set */
1211 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1212 	if (errno != EINVAL) e(0);
1213 
1214 	scn.sysctl_flags &= ~(CTLFLAG_IMMEDIATE | CTLFLAG_OWNDATA);
1215 	scn.sysctl_data = &i;
1216 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1217 	if (errno != EINVAL) e(0);
1218 
1219 	scn.sysctl_data = NULL;
1220 	oldlen = sizeof(newscn);
1221 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1222 	if (oldlen != sizeof(newscn)) e(0);
1223 	if (newscn.sysctl_flags & CTLFLAG_IMMEDIATE) e(0);
1224 	if (!(newscn.sysctl_flags & CTLFLAG_OWNDATA)) e(0); /* auto-set */
1225 	if (newscn.sysctl_idata != 0) e(0);
1226 
1227 	mib[2] = TEST_DYNAMIC;
1228 	oldlen = sizeof(i);
1229 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1230 	if (oldlen != sizeof(i)) e(0);
1231 	if (i != 0) e(0);
1232 
1233 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1234 
1235 	mib[2] = CTL_CREATE;
1236 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1237 	scn.sysctl_data = NULL;
1238 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1239 
1240 	mib[2] = TEST_DYNAMIC;
1241 	i = -1;
1242 	oldlen = sizeof(i);
1243 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1244 	if (oldlen != sizeof(i)) e(0);
1245 	if (i != 0) e(0);
1246 
1247 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1248 
1249 	mib[2] = CTL_CREATE;
1250 	scn.sysctl_data = bad_ptr;
1251 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1252 	if (errno != EFAULT) e(0);
1253 
1254 	i = 999;
1255 	scn.sysctl_data = (void *)&i;
1256 	oldlen = sizeof(newscn);
1257 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1258 	if (oldlen != sizeof(newscn)) e(0);
1259 	if ((newscn.sysctl_flags & (CTLFLAG_IMMEDIATE | CTLFLAG_OWNDATA)) !=
1260 	    CTLFLAG_OWNDATA) e(0);
1261 	if (newscn.sysctl_idata != 0) e(0);
1262 
1263 	mib[2] = TEST_DYNAMIC;
1264 	oldlen = sizeof(i);
1265 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1266 	if (oldlen != sizeof(i)) e(0);
1267 	if (i != 999) e(0);
1268 
1269 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1270 
1271 	/* The user may never supply a function pointer or a parent. */
1272 	mib[2] = CTL_CREATE;
1273 	memcpy(&scn, &tmpscn, sizeof(scn));
1274 	scn.sysctl_func = (sysctlfn)test87c;
1275 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1276 	if (errno != EINVAL) e(0);
1277 
1278 	memcpy(&scn, &tmpscn, sizeof(scn));
1279 	scn.sysctl_parent = &scn;
1280 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1281 	if (errno != EINVAL) e(0);
1282 
1283 	/* Test some good and bad node names. */
1284 	for (i = 0; i < __arraycount(goodnames); i++) {
1285 		memcpy(&scn, &tmpscn, sizeof(scn));
1286 		len = strlen(goodnames[i]);
1287 		memcpy(scn.sysctl_name, goodnames[i], len);
1288 		memset(&scn.sysctl_name[len], 0, SYSCTL_NAMELEN - len);
1289 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(i);
1290 
1291 		if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(i);
1292 	}
1293 
1294 	for (i = 0; i < __arraycount(badnames); i++) {
1295 		memcpy(&scn, &tmpscn, sizeof(scn));
1296 		len = strlen(badnames[i]);
1297 		memcpy(scn.sysctl_name, badnames[i], len);
1298 		memset(&scn.sysctl_name[len], 0, SYSCTL_NAMELEN - len);
1299 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1300 		if (errno != EINVAL) e(i);
1301 	}
1302 
1303 	/*
1304 	 * Check for ID and name conflicts with existing nodes, starting with
1305 	 * the basics.
1306 	 */
1307 	memcpy(&scn, &tmpscn, sizeof(scn));
1308 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1309 
1310 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1311 	if (errno != EEXIST) e(0);
1312 
1313 	oldlen = sizeof(oldscn);
1314 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1315 	if (errno != EEXIST) e(0);
1316 	if (oldlen != sizeof(oldscn)) e(0);
1317 	if (oldscn.sysctl_ver == 0) e(0);
1318 	oldscn.sysctl_ver = 0;
1319 	if (memcmp(&oldscn, &tmpscn, sizeof(oldscn))) e(0);
1320 
1321 	oldlen = sizeof(oldscn) - 1;
1322 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1323 	if (errno != EEXIST) e(0); /* ..we should not get ENOMEM now */
1324 	if (oldlen != sizeof(oldscn)) e(0);
1325 
1326 	oldlen = sizeof(oldscn);
1327 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1328 	if (errno != EEXIST) e(0); /* ..we should not get EFAULT now */
1329 	if (oldlen != 0) e(0); /* this is arguably an implementation detail */
1330 
1331 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1332 
1333 	/* Test ID and name conflicts against static nodes. */
1334 	if (create_node(mib, 2, &tmpscn, TEST_INT, "dynamic", TEST_INT,
1335 	    "int") != -1) e(0);
1336 	if (create_node(mib, 2, &tmpscn, TEST_SECRET, "dynamic", TEST_SECRET,
1337 	    "secret") != -1) e(0);
1338 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "quad", TEST_QUAD,
1339 	    "quad") != -1) e(0);
1340 
1341 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
1342 	    NULL) != TEST_DYNAMIC) e(0);
1343 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1344 
1345 	/* Test unique ID generation and LL back insertion. */
1346 	if ((id[0] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id0", -1,
1347 	    NULL)) == -1) e(0);
1348 	if ((id[1] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id1", -1,
1349 	    NULL)) == -1) e(0);
1350 	if ((id[2] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id2", -1,
1351 	    NULL)) == -1) e(0);
1352 	if (id[0] < CREATE_BASE || id[1] < CREATE_BASE || id[2] < CREATE_BASE)
1353 		e(0);
1354 	if (id[0] == id[1] || id[1] == id[2] || id[0] == id[2]) e(0);
1355 
1356 	if (destroy_node(mib, 2, id[1]) != 0) e(0);
1357 
1358 	/* Test ID and name conflicts against dynamic nodes. */
1359 	if (create_node(mib, 2, &tmpscn, id[0], "id1", id[0],
1360 	    "id0") != -1) e(0);
1361 	if (create_node(mib, 2, &tmpscn, id[2], "id1", id[2],
1362 	    "id2") != -1) e(0);
1363 	if (create_node(mib, 2, &tmpscn, id[1], "id0", id[0],
1364 	    "id0") != -1) e(0);
1365 	if (create_node(mib, 2, &tmpscn, id[1], "id2", id[2],
1366 	    "id2") != -1) e(0);
1367 
1368 	/* Test name conflicts before and after LL insertion point. */
1369 	if (create_node(mib, 2, &tmpscn, CTL_CREATE, "id0", id[0],
1370 	    "id0") != -1) e(0);
1371 	if (create_node(mib, 2, &tmpscn, CTL_CREATE, "id2", id[2],
1372 	    "id2") != -1) e(0);
1373 
1374 	/* Test recreation by ID and LL middle insertion. */
1375 	if (create_node(mib, 2, &tmpscn, id[1], "id1", -1, NULL) == -1) e(0);
1376 	if (destroy_node(mib, 2, id[1]) != 0) e(0);
1377 
1378 	/* Test dynamic recreation and more LL middle insertion. */
1379 	if ((id[1] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id1", -1,
1380 	    NULL)) == -1) e(0);
1381 	if (id[1] < CREATE_BASE) e(0);
1382 	if (id[1] == id[0] || id[1] == id[2]) e(0);
1383 
1384 	/* Test LL front insertion. */
1385 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
1386 	    NULL) == -1) e(0);
1387 
1388 	/* Ensure that all dynamic nodes show up in a query. */
1389 	mib[2] = CTL_QUERY;
1390 	oldlen = sizeof(scnset);
1391 	memset(seen, 0, sizeof(seen));
1392 	memset(scnset, 0, sizeof(scnset));
1393 	if (sysctl(mib, 3, scnset, &oldlen, NULL, 0) != 0) e(0);
1394 	if (oldlen % sizeof(scn)) e(0);
1395 	for (i = 0; (unsigned int)i < oldlen / sizeof(scn); i++) {
1396 		if (scnset[i].sysctl_num == TEST_INT) {
1397 			if (strcmp(scnset[i].sysctl_name, "int")) e(0);
1398 			seen[0]++;
1399 		} else if (scnset[i].sysctl_num == TEST_DYNAMIC) {
1400 			if (strcmp(scnset[i].sysctl_name, "dynamic")) e(0);
1401 			seen[1]++;
1402 		} else if (scnset[i].sysctl_num == id[0]) {
1403 			if (strcmp(scnset[i].sysctl_name, "id0")) e(0);
1404 			seen[2]++;
1405 		} else if (scnset[i].sysctl_num == id[1]) {
1406 			if (strcmp(scnset[i].sysctl_name, "id1")) e(0);
1407 			seen[3]++;
1408 		} else if (scnset[i].sysctl_num == id[2]) {
1409 			if (strcmp(scnset[i].sysctl_name, "id2")) e(0);
1410 			seen[4]++;
1411 		}
1412 	}
1413 	for (i = 0; i < 5; i++)
1414 		if (seen[i] != 1) e(i);
1415 
1416 	/* Compare the parent's statistics with those obtained earlier. */
1417 	if (query_node(mib, 1, MINIX_TEST, &scn) != 0) e(0);
1418 	if (scn.sysctl_clen != pscn.sysctl_clen + 4) e(0);
1419 	if (scn.sysctl_csize != pscn.sysctl_csize + 4) e(0);
1420 
1421 	/* Clean up. */
1422 	if (destroy_node(mib, 2, id[0]) != 0) e(0);
1423 	if (destroy_node(mib, 2, id[1]) != 0) e(0);
1424 	if (destroy_node(mib, 2, id[2]) != 0) e(0);
1425 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1426 
1427 	/* Copy-out errors should not result in the node not being created. */
1428 	mib[2] = CTL_CREATE;
1429 	memcpy(&scn, &tmpscn, sizeof(scn));
1430 	oldlen = sizeof(newscn) - 1;
1431 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1432 	if (errno != ENOMEM) e(0);
1433 	if (oldlen != sizeof(newscn)) e(0);
1434 
1435 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1436 
1437 	oldlen = sizeof(newscn);
1438 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1439 	if (errno != EFAULT) e(0);
1440 
1441 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1442 
1443 	oldlen = sizeof(newscn) + 1;
1444 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1445 	if (oldlen != sizeof(newscn)) e(0);
1446 
1447 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1448 
1449 	/*
1450 	 * Now that we are done with the integer template, try other data
1451 	 * types, starting with booleans.  A big part of these tests is that
1452 	 * the creation results in a usable node, regardless of the way its
1453 	 * contents were initialized.
1454 	 */
1455 	tmpscn.sysctl_flags =
1456 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_BOOL;
1457 	tmpscn.sysctl_size = sizeof(b);
1458 	tmpscn.sysctl_data = NULL;
1459 
1460 	mib[2] = CTL_CREATE;
1461 	memcpy(&scn, &tmpscn, sizeof(scn));
1462 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1463 
1464 	mib[2] = TEST_DYNAMIC;
1465 	oldlen = sizeof(b);
1466 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1467 	if (oldlen != sizeof(b)) e(0);
1468 	if (b != false) e(0);
1469 
1470 	b = true;
1471 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
1472 
1473 	oldlen = sizeof(b);
1474 	b = false;
1475 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1476 	if (oldlen != sizeof(b)) e(0);
1477 	if (b != true) e(0);
1478 
1479 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1480 
1481 	mib[2] = CTL_CREATE;
1482 	memcpy(&scn, &tmpscn, sizeof(scn));
1483 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1484 	scn.sysctl_bdata = true;
1485 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1486 
1487 	mib[2] = TEST_DYNAMIC;
1488 	oldlen = sizeof(b);
1489 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1490 	if (oldlen != sizeof(b)) e(0);
1491 	if (b != true) e(0);
1492 
1493 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1494 
1495 	mib[2] = CTL_CREATE;
1496 	scn.sysctl_bdata = false;
1497 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1498 
1499 	mib[2] = TEST_DYNAMIC;
1500 	oldlen = sizeof(b);
1501 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1502 	if (oldlen != sizeof(b)) e(0);
1503 	if (b != false) e(0);
1504 
1505 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1506 
1507 	mib[2] = CTL_CREATE;
1508 	memcpy(&scn, &tmpscn, sizeof(scn));
1509 	scn.sysctl_data = &b;
1510 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1511 	if (errno != EINVAL) e(0);
1512 
1513 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1514 	scn.sysctl_size++;
1515 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1516 	if (errno != EINVAL) e(0);
1517 
1518 	scn.sysctl_size--;
1519 	scn.sysctl_data = bad_ptr;
1520 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1521 	if (errno != EFAULT) e(0);
1522 
1523 	b = true;
1524 	scn.sysctl_data = &b;
1525 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1526 
1527 	mib[2] = TEST_DYNAMIC;
1528 	oldlen = sizeof(b);
1529 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1530 	if (oldlen != sizeof(b)) e(0);
1531 	if (b != true) e(0);
1532 
1533 	b = false;
1534 	oldlen = sizeof(b);
1535 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1536 	if (oldlen != sizeof(b)) e(0);
1537 	if (b != true) e(0);
1538 
1539 	b = false;
1540 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
1541 
1542 	oldlen = sizeof(b);
1543 	b = true;
1544 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1545 	if (oldlen != sizeof(b)) e(0);
1546 	if (b != false) e(0);
1547 
1548 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1549 
1550 	/* Test quads next. */
1551 	tmpscn.sysctl_flags =
1552 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_QUAD;
1553 	tmpscn.sysctl_size = sizeof(q);
1554 
1555 	mib[2] = CTL_CREATE;
1556 	memcpy(&scn, &tmpscn, sizeof(scn));
1557 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1558 
1559 	mib[2] = TEST_DYNAMIC;
1560 	oldlen = sizeof(q);
1561 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1562 	if (oldlen != sizeof(q)) e(0);
1563 	if (q != 0) e(0);
1564 
1565 	q = ~0ULL;
1566 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
1567 
1568 	oldlen = sizeof(q);
1569 	q = 0;
1570 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1571 	if (oldlen != sizeof(q)) e(0);
1572 	if (q != ~0ULL) e(0);
1573 
1574 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1575 
1576 	mib[2] = CTL_CREATE;
1577 	memcpy(&scn, &tmpscn, sizeof(scn));
1578 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1579 	scn.sysctl_qdata = 1ULL << 48;
1580 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1581 
1582 	mib[2] = TEST_DYNAMIC;
1583 	oldlen = sizeof(q);
1584 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1585 	if (oldlen != sizeof(q)) e(0);
1586 	if (q != (1ULL << 48)) e(0);
1587 
1588 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1589 
1590 	mib[2] = CTL_CREATE;
1591 	memcpy(&scn, &tmpscn, sizeof(scn));
1592 	scn.sysctl_data = &q;
1593 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1594 	if (errno != EINVAL) e(0);
1595 
1596 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1597 	scn.sysctl_size <<= 1;
1598 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1599 	if (errno != EINVAL) e(0);
1600 
1601 	scn.sysctl_size >>= 1;
1602 	scn.sysctl_data = bad_ptr;
1603 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1604 	if (errno != EFAULT) e(0);
1605 
1606 	q = 123ULL << 31;
1607 	scn.sysctl_data = &q;
1608 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1609 
1610 	mib[2] = TEST_DYNAMIC;
1611 	oldlen = sizeof(q);
1612 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1613 	if (oldlen != sizeof(q)) e(0);
1614 	if (q != (123ULL << 31)) e(0);
1615 
1616 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1617 
1618 	/* Test strings. */
1619 	tmpscn.sysctl_flags =
1620 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_STRING;
1621 	tmpscn.sysctl_size = 7;
1622 
1623 	mib[2] = CTL_CREATE;
1624 	memcpy(&scn, &tmpscn, sizeof(scn));
1625 	scn.sysctl_data = buf;
1626 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1627 	if (errno != EINVAL) e(0);
1628 
1629 	scn.sysctl_data = NULL;
1630 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1631 
1632 	mib[2] = TEST_DYNAMIC;
1633 	memset(buf, 0x7f, sizeof(buf));
1634 	oldlen = sizeof(buf);
1635 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1636 	if (oldlen != 1) e(0);
1637 	if (buf[0] != '\0') e(0);
1638 	if (buf[1] != 0x7f) e(0);
1639 
1640 	if (sysctl(mib, 3, NULL, NULL, "woobie!", 8) != -1) e(0);
1641 	if (errno != EINVAL) e(0);
1642 	if (sysctl(mib, 3, NULL, NULL, "woobie!", 7) != -1) e(0);
1643 	if (errno != EINVAL) e(0);
1644 	if (sysctl(mib, 3, NULL, NULL, "woobie", 7) != 0) e(0);
1645 
1646 	memset(buf, 0x7f, sizeof(buf));
1647 	oldlen = sizeof(buf);
1648 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1649 	if (oldlen != 7) e(0);
1650 	if (strcmp(buf, "woobie")) e(0);
1651 	if (buf[7] != 0x7f) e(0);
1652 
1653 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1654 
1655 	mib[2] = CTL_CREATE;
1656 	memcpy(&scn, &tmpscn, sizeof(scn));
1657 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1658 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1659 	if (errno != EINVAL) e(0);
1660 
1661 	memcpy(&scn, &tmpscn, sizeof(scn));
1662 	scn.sysctl_size = 0;
1663 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1664 	if (errno != EINVAL) e(0);
1665 
1666 	scn.sysctl_data = buf;
1667 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1668 	if (errno != EINVAL) e(0);
1669 
1670 	memcpy(&scn, &tmpscn, sizeof(scn));
1671 	scn.sysctl_size = (size_t)SSIZE_MAX + 1;
1672 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1673 	if (errno != EINVAL) e(0);
1674 
1675 	memcpy(&scn, &tmpscn, sizeof(scn));
1676 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1677 	scn.sysctl_data = bad_ptr;
1678 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1679 	if (errno != EFAULT) e(0);
1680 
1681 	memcpy(&scn, &tmpscn, sizeof(scn));
1682 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1683 	scn.sysctl_data = "abc123?";
1684 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1685 	if (errno != EINVAL) e(0);
1686 
1687 	scn.sysctl_data = "abc123";
1688 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1689 
1690 	mib[2] = TEST_DYNAMIC;
1691 	memset(buf, 0x7f, sizeof(buf));
1692 	oldlen = sizeof(buf);
1693 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1694 	if (oldlen != 7) e(0);
1695 	if (strcmp(buf, "abc123")) e(0);
1696 	if (buf[7] != 0x7f) e(0);
1697 
1698 	if (sysctl(mib, 3, NULL, NULL, "", 1) != 0) e(0);
1699 
1700 	memset(buf, 0x7f, sizeof(buf));
1701 	oldlen = sizeof(buf);
1702 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1703 	if (oldlen != 1) e(0);
1704 	if (buf[0] != '\0') e(0);
1705 	if (buf[1] != 0x7f) e(0);
1706 
1707 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1708 
1709 	mib[2] = CTL_CREATE;
1710 	scn.sysctl_data = "";
1711 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1712 
1713 	mib[2] = TEST_DYNAMIC;
1714 	memset(buf, 0x7f, sizeof(buf));
1715 	oldlen = sizeof(buf);
1716 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1717 	if (oldlen != 1) e(0);
1718 	if (buf[0] != '\0') e(0);
1719 	if (buf[7] != 0x7f) e(0);
1720 
1721 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1722 
1723 	/*
1724 	 * For strings, a zero node size means that the string length
1725 	 * determines the buffer size.
1726 	 */
1727 	mib[2] = CTL_CREATE;
1728 	scn.sysctl_size = 0;
1729 	scn.sysctl_data = NULL;
1730 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1731 	if (errno != EINVAL) e(0);
1732 
1733 	scn.sysctl_data = bad_ptr;
1734 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1735 	if (errno != EFAULT) e(0);
1736 
1737 	scn.sysctl_data = "This is a string initializer."; /* size 29+1 */
1738 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1739 
1740 	mib[2] = TEST_DYNAMIC;
1741 	memset(buf, 0x7f, sizeof(buf));
1742 	oldlen = sizeof(buf);
1743 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1744 	if (oldlen != strlen(scn.sysctl_data) + 1) e(0);
1745 	if (buf[oldlen - 1] != '\0') e(0);
1746 	if (buf[oldlen] != 0x7f) e(0);
1747 
1748 	if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
1749 	if (newscn.sysctl_size != strlen(scn.sysctl_data) + 1) e(0);
1750 
1751 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1752 
1753 	/* Test structs. */
1754 	tmpscn.sysctl_flags =
1755 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_STRUCT;
1756 	tmpscn.sysctl_size = 21;
1757 
1758 	mib[2] = CTL_CREATE;
1759 	memcpy(&scn, &tmpscn, sizeof(scn));
1760 	scn.sysctl_data = buf;
1761 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1762 	if (errno != EINVAL) e(0);
1763 
1764 	scn.sysctl_data = NULL;
1765 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1766 
1767 	mib[2] = TEST_DYNAMIC;
1768 	memset(buf, 0x7f, sizeof(buf));
1769 	oldlen = sizeof(buf);
1770 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1771 	if (oldlen != 21) e(0);
1772 	for (i = 0; i < 21; i++)
1773 		if (buf[i] != 0) e(i);
1774 	if (buf[i] != 0x7f) e(0);
1775 
1776 	memset(buf, 'x', 32);
1777 	if (sysctl(mib, 3, NULL, NULL, buf, 20) != -1) e(0);
1778 	if (errno != EINVAL) e(0);
1779 	if (sysctl(mib, 3, NULL, NULL, buf, 22) != -1) e(0);
1780 	if (errno != EINVAL) e(0);
1781 	if (sysctl(mib, 3, NULL, NULL, buf, 21) != 0) e(0);
1782 
1783 	memset(buf, 0x7f, sizeof(buf));
1784 	oldlen = sizeof(buf);
1785 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1786 	if (oldlen != 21) e(0);
1787 	for (i = 0; i < 21; i++)
1788 		if (buf[i] != 'x') e(i);
1789 	if (buf[i] != 0x7f) e(0);
1790 
1791 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1792 
1793 	mib[2] = CTL_CREATE;
1794 	memcpy(&scn, &tmpscn, sizeof(scn));
1795 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1796 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1797 	if (errno != EINVAL) e(0);
1798 
1799 	memcpy(&scn, &tmpscn, sizeof(scn));
1800 	scn.sysctl_size = 0;
1801 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1802 	if (errno != EINVAL) e(0);
1803 
1804 	scn.sysctl_data = buf;
1805 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1806 	if (errno != EINVAL) e(0);
1807 
1808 	memcpy(&scn, &tmpscn, sizeof(scn));
1809 	scn.sysctl_size = (size_t)SSIZE_MAX + 1;
1810 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1811 	if (errno != EINVAL) e(0);
1812 
1813 	memcpy(&scn, &tmpscn, sizeof(scn));
1814 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1815 	scn.sysctl_data = bad_ptr;
1816 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1817 	if (errno != EFAULT) e(0);
1818 
1819 	memcpy(&scn, &tmpscn, sizeof(scn));
1820 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1821 	for (i = 0; i < sizeof(buf); i++)
1822 		buf[i] = i;
1823 	scn.sysctl_data = buf;
1824 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1825 
1826 	mib[2] = TEST_DYNAMIC;
1827 	memset(buf, 0x7f, sizeof(buf));
1828 	oldlen = sizeof(buf);
1829 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1830 	if (oldlen != 21) e(0);
1831 	for (i = 0; i < 21; i++)
1832 		if (buf[i] != i) e(i);
1833 	if (buf[i] != 0x7f) e(0);
1834 
1835 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1836 
1837 	/* Finally, test node-type nodes. */
1838 	tmpscn.sysctl_flags =
1839 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
1840 	tmpscn.sysctl_size = 0;
1841 
1842 	mib[2] = CTL_CREATE;
1843 	memcpy(&scn, &tmpscn, sizeof(scn));
1844 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1845 
1846 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1847 
1848 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1849 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1850 	if (errno != EINVAL) e(0);
1851 
1852 	memcpy(&scn, &tmpscn, sizeof(scn));
1853 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1854 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1855 	if (errno != EINVAL) e(0);
1856 
1857 	scn.sysctl_size = sizeof(scn);
1858 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1859 	if (errno != EINVAL) e(0);
1860 
1861 	scn.sysctl_flags &= ~CTLFLAG_IMMEDIATE;
1862 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1863 	if (errno != EINVAL) e(0);
1864 
1865 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1866 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1867 	if (errno != EINVAL) e(0);
1868 
1869 	memcpy(&scn, &tmpscn, sizeof(scn));
1870 	scn.sysctl_csize = 8;
1871 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1872 	if (errno != EINVAL) e(0);
1873 
1874 	memcpy(&scn, &tmpscn, sizeof(scn));
1875 	scn.sysctl_clen = 1;
1876 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1877 	if (errno != EINVAL) e(0);
1878 
1879 	memcpy(&scn, &tmpscn, sizeof(scn));
1880 	scn.sysctl_child = &scn;
1881 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1882 	if (errno != EINVAL) e(0);
1883 
1884 	memcpy(&scn, &tmpscn, sizeof(scn));
1885 	scn.sysctl_parent = &scn;
1886 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1887 	if (errno != EINVAL) e(0);
1888 
1889 	memcpy(&scn, &tmpscn, sizeof(scn));
1890 	scn.sysctl_func = (sysctlfn)test87c;
1891 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1892 	if (errno != EINVAL) e(0);
1893 
1894 	memcpy(&scn, &tmpscn, sizeof(scn));
1895 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1896 
1897 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1898 	if (scn.sysctl_csize != 0) e(0);
1899 	if (scn.sysctl_clen != 0) e(0);
1900 
1901 	mib[2] = TEST_DYNAMIC;
1902 
1903 	for (i = 3; i < CTL_MAXNAME; i++) {
1904 		memcpy(&scn, &tmpscn, sizeof(scn));
1905 		if (i % 2)
1906 			scn.sysctl_num = i - 3;
1907 		else
1908 			scn.sysctl_num = CTL_CREATE;
1909 		/*
1910 		 * Test both names with different length (depthN vs depthNN)
1911 		 * and cross-directory name duplicates (depth7.depth7).
1912 		 */
1913 		snprintf(scn.sysctl_name, sizeof(scn.sysctl_name), "depth%u",
1914 		    7 + i / 2);
1915 		mib[i] = CTL_CREATE;
1916 
1917 		oldlen = sizeof(newscn);
1918 		if (sysctl(mib, i + 1, &newscn, &oldlen, &scn,
1919 		    sizeof(scn)) != 0) e(0);
1920 		mib[i] = newscn.sysctl_num;
1921 	}
1922 
1923 	id[0] = mib[i - 1];
1924 	mib[i - 1] = CTL_CREATE;
1925 	memset(&scn, 0, sizeof(scn));
1926 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READONLY |
1927 	    CTLFLAG_OWNDATA | CTLTYPE_STRING;
1928 	scn.sysctl_num = id[0] + 1;
1929 	scn.sysctl_data = "bar";
1930 	scn.sysctl_size = strlen(scn.sysctl_data) + 1;
1931 	strlcpy(scn.sysctl_name, "foo", sizeof(scn.sysctl_name));
1932 	if (sysctl(mib, i, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1933 	mib[i - 1] = id[0] + 1;
1934 
1935 	oldlen = sizeof(buf);
1936 	if (sysctl(mib, i, buf, &oldlen, NULL, 0) != 0) e(0);
1937 	if (oldlen != strlen(scn.sysctl_data) + 1) e(0);
1938 	if (strcmp(buf, scn.sysctl_data)) e(0);
1939 
1940 	if (query_node(mib, i - 2, mib[i - 2], &scn) != 0) e(0);
1941 	if (scn.sysctl_csize != 2) e(0);
1942 	if (scn.sysctl_clen != 2) e(0);
1943 
1944 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1945 	if (scn.sysctl_csize != 1) e(0);
1946 	if (scn.sysctl_clen != 1) e(0);
1947 
1948 	if (destroy_node(mib, i - 1, mib[i - 1]) != 0) e(0);
1949 	mib[i - 1]--;
1950 
1951 	for (i--; i > 2; i--)
1952 		if (destroy_node(mib, i, mib[i]) != 0) e(0);
1953 
1954 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1955 	if (scn.sysctl_csize != 0) e(0);
1956 	if (scn.sysctl_clen != 0) e(0);
1957 
1958 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1959 
1960 	/*
1961 	 * Finally, ensure that unprivileged processes cannot create nodes,
1962 	 * even in the most friendly place possible.
1963 	 */
1964 	mib[2] = CTL_CREATE;
1965 	memcpy(&scn, &tmpscn, sizeof(scn));
1966 	scn.sysctl_flags |= CTLFLAG_ANYWRITE;
1967 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1968 
1969 	(void)test_nonroot(sub87c);
1970 
1971 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1972 
1973 	/*
1974 	 * Now that we are done, compare the parent's statistics with those
1975 	 * obtained earlier once more.  There must be no differences.
1976 	 */
1977 	if (query_node(mib, 1, MINIX_TEST, &scn) != 0) e(0);
1978 	if (scn.sysctl_clen != pscn.sysctl_clen) e(0);
1979 	if (scn.sysctl_csize != pscn.sysctl_csize) e(0);
1980 
1981 	/* Do some more path-related error code tests unrelated to the rest. */
1982 	memcpy(&scn, &tmpscn, sizeof(scn));
1983 	mib[1] = INT_MAX;
1984 	if (create_node(mib, 2, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1985 	if (errno != ENOENT) e(0);
1986 
1987 	mib[1] = MINIX_TEST;
1988 	mib[2] = TEST_INT;
1989 	if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1990 	if (errno != ENOTDIR) e(0);
1991 
1992 	mib[2] = TEST_BOOL;
1993 	if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1994 	if (errno != ENOTDIR) e(0);
1995 
1996 	mib[2] = CTL_CREATE;
1997 	if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1998 	if (errno != EINVAL) e(0);
1999 
2000 	/* Finally, try to create a node in a read-only directory node. */
2001 	mib[2] = TEST_SECRET;
2002 	if (create_node(mib, 3, &scn, -1, "d", -1, NULL) != -1) e(0);
2003 	if (errno != EPERM) e(0);
2004 }
2005 
2006 /*
2007  * Test unprivileged node destruction.
2008  */
2009 static void
2010 sub87d(void)
2011 {
2012 	struct sysctlnode scn;
2013 	int mib[3];
2014 
2015 	mib[0] = CTL_MINIX;
2016 	mib[1] = MINIX_TEST;
2017 	mib[2] = CTL_DESTROY;
2018 
2019 	memset(&scn, 0, sizeof(scn));
2020 	scn.sysctl_flags = SYSCTL_VERSION;
2021 	scn.sysctl_num = TEST_ANYWRITE;
2022 
2023 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2024 	if (errno != EPERM) e(0);
2025 
2026 	mib[0] = CTL_DESTROY;
2027 	scn.sysctl_num = CTL_MINIX;
2028 	if (sysctl(mib, 1, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2029 	if (errno != EPERM) e(0);
2030 }
2031 
2032 /*
2033  * Test sysctl(2) node destruction.
2034  */
2035 static void
2036 test87d(void)
2037 {
2038 	struct sysctlnode scn, oldscn, newscn, tmpscn;
2039 	size_t oldlen;
2040 	char buf[16];
2041 	int i, r, mib[4], id[15];
2042 
2043 	subtest = 3;
2044 
2045 	mib[0] = CTL_MINIX;
2046 	mib[1] = MINIX_TEST;
2047 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
2048 
2049 	/* Start with the path-related error code tests this time. */
2050 	mib[1] = INT_MAX;
2051 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2052 	if (errno != ENOENT) e(0);
2053 
2054 	mib[1] = MINIX_TEST;
2055 	mib[2] = TEST_INT;
2056 	if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2057 	if (errno != ENOTDIR) e(0);
2058 
2059 	mib[2] = TEST_BOOL;
2060 	if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2061 	if (errno != ENOTDIR) e(0);
2062 
2063 	mib[2] = CTL_DESTROY;
2064 	if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2065 	if (errno != EINVAL) e(0);
2066 
2067 	/* Actual API tests. */
2068 	mib[1] = MINIX_TEST;
2069 	mib[2] = CTL_CREATE;
2070 	memset(&scn, 0, sizeof(scn));
2071 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2072 	    CTLFLAG_READONLY | CTLTYPE_INT;
2073 	scn.sysctl_size = sizeof(int);
2074 	scn.sysctl_num = TEST_DYNAMIC;
2075 	scn.sysctl_idata = 31415926;
2076 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2077 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2078 
2079 	memcpy(&tmpscn, &scn, sizeof(scn));
2080 
2081 	mib[2] = CTL_DESTROY;
2082 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
2083 	if (errno != EINVAL) e(0);
2084 
2085 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
2086 	if (errno != EFAULT) e(0);
2087 
2088 	memset(&scn, 0, sizeof(scn));
2089 	scn.sysctl_flags = SYSCTL_VERS_0;
2090 	scn.sysctl_num = TEST_DYNAMIC;
2091 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2092 	if (errno != EINVAL) e(0);
2093 
2094 	scn.sysctl_flags = SYSCTL_VERSION;
2095 	scn.sysctl_num = INT_MAX; /* anything not valid */
2096 	oldlen = sizeof(scn);
2097 	if (sysctl(mib, 3, NULL, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2098 	if (errno != ENOENT) e(0);
2099 	if (oldlen != 0) e(0);
2100 
2101 	scn.sysctl_num = TEST_PERM;
2102 	oldlen = sizeof(scn);
2103 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2104 	if (errno != EPERM) e(0);
2105 	if (oldlen != 0) e(0);
2106 
2107 	scn.sysctl_num = TEST_SECRET;
2108 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2109 	if (errno != ENOTEMPTY) e(0);
2110 
2111 	scn.sysctl_num = -1;
2112 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2113 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2114 	if (errno != ENOENT) e(0);
2115 
2116 	scn.sysctl_num = TEST_DYNAMIC;
2117 	strlcpy(scn.sysctl_name, "dynami", sizeof(scn.sysctl_name));
2118 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2119 	if (errno != EINVAL) e(0);
2120 
2121 	strlcpy(scn.sysctl_name, "dynamic2", sizeof(scn.sysctl_name));
2122 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2123 	if (errno != EINVAL) e(0);
2124 
2125 	memset(scn.sysctl_name, 'd', sizeof(scn.sysctl_name));
2126 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2127 	if (errno != EINVAL) e(0);
2128 
2129 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2130 	oldlen = sizeof(oldscn);
2131 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
2132 	if (oldlen != sizeof(oldscn)) e(0);
2133 	if (oldscn.sysctl_ver == 0) e(0);
2134 	oldscn.sysctl_ver = 0;
2135 	if (memcmp(&oldscn, &tmpscn, sizeof(oldscn))) e(0);
2136 
2137 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2138 	if (errno != ENOENT) e(0);
2139 
2140 	/*
2141 	 * We already tested destruction of one static node, by destroying
2142 	 * TEST_DYNAMIC on the first run.  We now do a second deletion of a
2143 	 * static node, TEST_DESTROY2, to test proper adjustment of parent
2144 	 * stats.  We do a third static node deletion (on TEST_DESTROY1) later,
2145 	 * to see that static nodes with dynamic descriptions can be freed.
2146 	 */
2147 	if (query_node(mib, 1, MINIX_TEST, &oldscn) != 0) e(0);
2148 
2149 	memset(&scn, 0, sizeof(scn));
2150 	scn.sysctl_flags = SYSCTL_VERSION;
2151 	scn.sysctl_num = TEST_DESTROY2;
2152 	r = sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn));
2153 	if (r != 0 && r != -1) e(0);
2154 	if (r == -1 && errno != ENOENT) e(0);
2155 
2156 	if (query_node(mib, 1, MINIX_TEST, &newscn) != 0) e(0);
2157 
2158 	if (newscn.sysctl_csize != oldscn.sysctl_csize) e(0);
2159 	if (newscn.sysctl_clen != oldscn.sysctl_clen - !r) e(0);
2160 
2161 	/* Try to destroy a (static) node in a read-only directory node. */
2162 	mib[2] = TEST_SECRET;
2163 	if (destroy_node(mib, 3, SECRET_VALUE) != -1) e(0);
2164 	if (errno != EPERM) e(0);
2165 
2166 	/*
2167 	 * Errors during data copy-out of the destroyed node should not undo
2168 	 * its destruction.
2169 	 */
2170 	mib[2] = CTL_CREATE;
2171 	memcpy(&scn, &tmpscn, sizeof(scn));
2172 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2173 
2174 	mib[2] = TEST_DYNAMIC;
2175 	i = 0;
2176 	oldlen = sizeof(i);
2177 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
2178 	if (oldlen != sizeof(i)) e(0);
2179 	if (i != 31415926) e(0);
2180 
2181 	mib[2] = CTL_DESTROY;
2182 	oldlen = sizeof(scn);
2183 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2184 	if (errno != EFAULT) e(0);
2185 
2186 	mib[2] = TEST_DYNAMIC;
2187 	i = 0;
2188 	oldlen = sizeof(i);
2189 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
2190 	if (errno != ENOENT) e(0);
2191 	if (oldlen != 0) e(0);
2192 	if (i != 0) e(0);
2193 
2194 	mib[2] = CTL_CREATE;
2195 	memcpy(&scn, &tmpscn, sizeof(scn));
2196 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2197 
2198 	mib[2] = CTL_DESTROY;
2199 	oldlen = sizeof(scn) - 1;
2200 	if (sysctl(mib, 3, &scn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2201 	if (errno != ENOMEM) e(0);
2202 
2203 	mib[2] = TEST_DYNAMIC;
2204 	oldlen = sizeof(i);
2205 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
2206 	if (errno != ENOENT) e(0);
2207 
2208 	/*
2209 	 * Now create and destroy a whole bunch of nodes in a subtree, mostly
2210 	 * test linked list manipulation, but also to ensure that a nonempty
2211 	 * tree node cannot be destroyed.
2212 	 */
2213 	memset(&scn, 0, sizeof(scn));
2214 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
2215 	if (create_node(mib, 2, &scn, TEST_DYNAMIC, "dynamic", -1, NULL) == -1)
2216 		e(0);
2217 
2218 	for (i = 0; i < 15; i++) {
2219 		snprintf(buf, sizeof(buf), "node%d", i);
2220 		if ((id[i] = create_node(mib, 3, &scn, -1, buf, -1,
2221 		    NULL)) == -1) e(i);
2222 
2223 		if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(i);
2224 		if (errno != ENOTEMPTY) e(i);
2225 	}
2226 
2227 	for (i = 0; i < 15; i += 2)
2228 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2229 
2230 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2231 	if (errno != ENOTEMPTY) e(0);
2232 
2233 	for (i = 0; i < 15; i += 2) {
2234 		snprintf(buf, sizeof(buf), "node%d", i);
2235 		if ((id[i] = create_node(mib, 3, &scn, -1, buf, -1,
2236 		    NULL)) == -1) e(i);
2237 	}
2238 
2239 	for (i = 0; i < 3; i++)
2240 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2241 
2242 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2243 	if (errno != ENOTEMPTY) e(0);
2244 
2245 	for (i = 12; i < 15; i++)
2246 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2247 
2248 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2249 	if (errno != ENOTEMPTY) e(0);
2250 
2251 	for (i = 6; i < 9; i++)
2252 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2253 
2254 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2255 	if (errno != ENOTEMPTY) e(0);
2256 
2257 	for (i = 3; i < 6; i++)
2258 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2259 
2260 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2261 	if (errno != ENOTEMPTY) e(0);
2262 
2263 	for (i = 9; i < 12; i++)
2264 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2265 
2266 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2267 
2268 	/* Finally, ensure that unprivileged users cannot destroy nodes. */
2269 	(void)test_nonroot(sub87d);
2270 }
2271 
2272 /*
2273  * Get or a set the description for a particular node.  Compare the results
2274  * with the given description.  Return 0 on success, or -1 on failure with
2275  * errno set.
2276  */
2277 static int
2278 describe_node(const int * path, unsigned int pathlen, int id,
2279 	const char * desc, int set)
2280 {
2281 	char buf[256], *p;
2282 	struct sysctlnode scn;
2283 	struct sysctldesc *scd;
2284 	size_t oldlen;
2285 	int mib[CTL_MAXNAME];
2286 
2287 	if (pathlen >= CTL_MAXNAME) e(0);
2288 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
2289 	mib[pathlen] = CTL_DESCRIBE;
2290 
2291 	memset(&scn, 0, sizeof(scn));
2292 	memset(buf, 0, sizeof(buf));
2293 	oldlen = sizeof(buf);
2294 	scn.sysctl_flags = SYSCTL_VERSION;
2295 	scn.sysctl_num = id;
2296 	if (set)
2297 		scn.sysctl_desc = desc;
2298 	if (sysctl(mib, pathlen + 1, buf, &oldlen, &scn, sizeof(scn)) != 0)
2299 		return -1;
2300 
2301 	scd = (struct sysctldesc *)buf;
2302 	if (scd->descr_num != id) e(0);
2303 	if (scd->descr_ver == 0) e(0);
2304 	if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2305 	if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2306 	if (strcmp(scd->descr_str, desc)) e(0);
2307 	if (oldlen != (size_t)((char *)NEXT_DESCR(scd) - buf)) e(0);
2308 	for (p = scd->descr_str + scd->descr_len; p != &buf[oldlen]; p++)
2309 		if (*p != '\0') e(0);
2310 	return 0;
2311 }
2312 
2313 /*
2314  * Test getting descriptions from an unprivileged process.
2315  */
2316 static void
2317 sub87e(void)
2318 {
2319 	static char buf[2048];
2320 	char seen[32], *p;
2321 	struct sysctldesc *scd, *endscd;
2322 	size_t oldlen;
2323 	int mib[4];
2324 
2325 	mib[0] = CTL_MINIX;
2326 	mib[1] = MINIX_TEST;
2327 	mib[2] = CTL_DESCRIBE;
2328 
2329 	memset(buf, 0, sizeof(buf));
2330 	oldlen = sizeof(buf);
2331 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2332 	if (oldlen == 0) e(0);
2333 
2334 	scd = (struct sysctldesc *)buf;
2335 	endscd = (struct sysctldesc *)&buf[oldlen];
2336 	memset(seen, 0, sizeof(seen));
2337 
2338 	while (scd < endscd) {
2339 		if (scd->descr_num >= __arraycount(seen)) e(0);
2340 		if (seen[scd->descr_num]++) e(0);
2341 
2342 		if (scd->descr_ver == 0) e(0);
2343 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2344 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2345 
2346 		p = scd->descr_str + scd->descr_len;
2347 		while (p != (char *)NEXT_DESCR(scd))
2348 			if (*p++ != '\0') e(0);
2349 
2350 		scd = NEXT_DESCR(scd);
2351 	}
2352 	if (scd != endscd) e(0);
2353 
2354 	if (!seen[TEST_INT]) e(0);
2355 	if (!seen[TEST_BOOL]) e(0);
2356 	if (!seen[TEST_QUAD]) e(0);
2357 	if (!seen[TEST_STRING]) e(0);
2358 	if (!seen[TEST_STRUCT]) e(0);
2359 	if (seen[TEST_PRIVATE]) e(0);
2360 	if (!seen[TEST_ANYWRITE]) e(0);
2361 	if (seen[TEST_SECRET]) e(0);
2362 	if (!seen[TEST_PERM]) e(0);
2363 
2364 	if (describe_node(mib, 2, TEST_INT, "Value test field", 0) != 0) e(0);
2365 	if (describe_node(mib, 2, TEST_PRIVATE, "", 0) != -1) e(0);
2366 	if (errno != EPERM) e(0);
2367 	if (describe_node(mib, 2, TEST_SECRET, "", 0) != -1) e(0);
2368 	if (errno != EPERM) e(0);
2369 	if (describe_node(mib, 2, TEST_PERM, "", 0) != 0) e(0);
2370 
2371 	mib[2] = TEST_SECRET;
2372 	mib[3] = CTL_DESCRIBE;
2373 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
2374 	if (errno != EPERM) e(0);
2375 
2376 	if (describe_node(mib, 3, SECRET_VALUE, "", 0) != -1) e(0);
2377 	if (errno != EPERM) e(0);
2378 }
2379 
2380 /*
2381  * Test sysctl(2) node descriptions, part 1: getting descriptions.
2382  */
2383 static void
2384 test87e(void)
2385 {
2386 	static char buf[2048];
2387 	char seen[32], *p;
2388 	struct sysctldesc *scd, *endscd;
2389 	struct sysctlnode scn;
2390 	size_t oldlen, len, sublen;
2391 	int mib[4];
2392 
2393 	subtest = 4;
2394 
2395 	mib[0] = CTL_MINIX;
2396 	mib[1] = MINIX_TEST;
2397 	mib[2] = CTL_DESCRIBE;
2398 	memset(&scn, 0, sizeof(scn));
2399 
2400 	/* Start with tests for getting a description listing. */
2401 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != 0) e(0);
2402 
2403 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
2404 	if (oldlen == 0) e(0);
2405 	len = oldlen;
2406 
2407 	memset(buf, 0, sizeof(buf));
2408 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2409 	if (oldlen != len) e(0);
2410 
2411 	scd = (struct sysctldesc *)buf;
2412 	endscd = (struct sysctldesc *)&buf[len];
2413 	memset(seen, 0, sizeof(seen));
2414 
2415 	sublen = (size_t)((char *)NEXT_DESCR(scd) - buf);
2416 
2417 	while (scd < endscd) {
2418 		if (scd->descr_num >= __arraycount(seen)) e(0);
2419 		if (seen[scd->descr_num]++) e(0);
2420 
2421 		if (scd->descr_ver == 0) e(0);
2422 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2423 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2424 
2425 		/*
2426 		 * This is not supposed to be complete.  We test different
2427 		 * string lengths, private fields, and empty descriptions.
2428 		 */
2429 		switch (scd->descr_num) {
2430 		case TEST_INT:
2431 			if (strcmp(scd->descr_str, "Value test field")) e(0);
2432 			break;
2433 		case TEST_BOOL:
2434 			if (strcmp(scd->descr_str, "Boolean test field")) e(0);
2435 			break;
2436 		case TEST_QUAD:
2437 			if (strcmp(scd->descr_str, "Quad test field")) e(0);
2438 			break;
2439 		case TEST_STRING:
2440 			if (strcmp(scd->descr_str, "String test field")) e(0);
2441 			break;
2442 		case TEST_PRIVATE:
2443 			if (strcmp(scd->descr_str, "Private test field")) e(0);
2444 			break;
2445 		case TEST_SECRET:
2446 			if (strcmp(scd->descr_str, "Private subtree")) e(0);
2447 			break;
2448 		case TEST_PERM:
2449 			if (strcmp(scd->descr_str, "")) e(0);
2450 			break;
2451 		}
2452 
2453 		/*
2454 		 * If there are padding bytes, they must be zero, whether it is
2455 		 * because we set them or the MIB service copied out zeroes.
2456 		 */
2457 		p = scd->descr_str + scd->descr_len;
2458 		while (p != (char *)NEXT_DESCR(scd))
2459 			if (*p++ != '\0') e(0);
2460 
2461 		scd = NEXT_DESCR(scd);
2462 	}
2463 	if (scd != endscd) e(0);
2464 
2465 	if (!seen[TEST_INT]) e(0);
2466 	if (!seen[TEST_BOOL]) e(0);
2467 	if (!seen[TEST_QUAD]) e(0);
2468 	if (!seen[TEST_STRING]) e(0);
2469 	if (!seen[TEST_STRUCT]) e(0);
2470 	if (!seen[TEST_PRIVATE]) e(0);
2471 	if (!seen[TEST_ANYWRITE]) e(0);
2472 	if (!seen[TEST_SECRET]) e(0);
2473 	if (!seen[TEST_PERM]) e(0);
2474 
2475 	memset(buf, 0, sizeof(buf));
2476 	oldlen = sublen;
2477 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
2478 	if (errno != ENOMEM) e(0);
2479 
2480 	scd = (struct sysctldesc *)buf;
2481 	if (scd->descr_num != TEST_INT) e(0);
2482 	if (scd->descr_ver == 0) e(0);
2483 	if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2484 	if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2485 	if (strcmp(scd->descr_str, "Value test field")) e(0);
2486 
2487 	/* Next up, tests for getting a particular node's description. */
2488 	memset(buf, 0, sizeof(buf));
2489 	oldlen = sizeof(buf);
2490 	if (sysctl(mib, 3, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
2491 	if (errno != EFAULT) e(0);
2492 
2493 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn) - 1) != -1) e(0);
2494 	if (errno != EINVAL) e(0);
2495 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn) + 1) != -1) e(0);
2496 	if (errno != EINVAL) e(0);
2497 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
2498 	if (errno != EFAULT) e(0);
2499 
2500 	memset(&scn, 0, sizeof(scn));
2501 	scn.sysctl_flags = SYSCTL_VERS_0;
2502 	scn.sysctl_num = INT_MAX;
2503 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2504 	if (errno != EINVAL) e(0);
2505 
2506 	scn.sysctl_flags = SYSCTL_VERSION;
2507 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2508 	if (errno != ENOENT) e(0);
2509 
2510 	scn.sysctl_num = TEST_BOOL;
2511 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2512 
2513 	oldlen = sizeof(buf);
2514 	scn.sysctl_num = TEST_INT;
2515 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2516 	if (errno != EFAULT) e(0);
2517 
2518 	oldlen = sublen - 1;
2519 	scn.sysctl_num = TEST_INT;
2520 	if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2521 	if (errno != ENOMEM) e(0);
2522 	if (oldlen != sublen) e(0);
2523 
2524 	if (describe_node(mib, 2, TEST_INT, "Value test field", 0) != 0) e(0);
2525 	if (describe_node(mib, 2, TEST_QUAD, "Quad test field", 0) != 0) e(0);
2526 	if (describe_node(mib, 2, TEST_PRIVATE, "Private test field",
2527 	    0) != 0) e(0);
2528 	if (describe_node(mib, 2, TEST_SECRET, "Private subtree",
2529 	    0) != 0) e(0);
2530 	if (describe_node(mib, 2, TEST_PERM, "", 0) != 0) e(0);
2531 
2532 	/*
2533 	 * Make sure that unprivileged users cannot access privileged nodes'
2534 	 * descriptions.  It doesn't sound too bad to me if they could, but
2535 	 * these are apparently the rules..
2536 	 */
2537 	(void)test_nonroot(sub87e);
2538 
2539 	/* Do some more path-related error code tests unrelated to the rest. */
2540 	mib[1] = INT_MAX;
2541 	if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != -1) e(0);
2542 	if (errno != ENOENT) e(0);
2543 
2544 	mib[1] = MINIX_TEST;
2545 	mib[2] = TEST_INT;
2546 	if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2547 	if (errno != ENOTDIR) e(0);
2548 
2549 	mib[2] = TEST_BOOL;
2550 	if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2551 	if (errno != ENOTDIR) e(0);
2552 
2553 	mib[2] = CTL_DESCRIBE;
2554 	if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2555 	if (errno != EINVAL) e(0);
2556 }
2557 
2558 /*
2559  * Test setting descriptions from an unprivileged process.
2560  */
2561 static void
2562 sub87f(void)
2563 {
2564 	struct sysctlnode scn;
2565 	int mib[3];
2566 
2567 	mib[0] = CTL_MINIX;
2568 	mib[1] = MINIX_TEST;
2569 	mib[2] = CTL_DESCRIBE;
2570 
2571 	memset(&scn, 0, sizeof(scn));
2572 	scn.sysctl_flags = SYSCTL_VERSION;
2573 	scn.sysctl_num = TEST_DYNAMIC;
2574 	scn.sysctl_desc = "Description.";
2575 
2576 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2577 	if (errno != EPERM) e(0);
2578 }
2579 
2580 /*
2581  * Test sysctl(2) node descriptions, part 2: setting descriptions.
2582  */
2583 static void
2584 test87f(void)
2585 {
2586 	static char buf[2048];
2587 	char seen, *p;
2588 	struct sysctlnode scn, tmpscn, scnset[3];
2589 	struct sysctldesc *scd, *endscd, *scdset[2];
2590 	size_t oldlen, len;
2591 	int i, r, mib[4], id[2];
2592 
2593 	subtest = 5;
2594 
2595 	/*
2596 	 * All tests that experiment with dynamic nodes must start with trying
2597 	 * to destroy the TEST_DYNAMIC node first, as tests may be run
2598 	 * individually, and this node exists as a static node after booting.
2599 	 */
2600 	mib[0] = CTL_MINIX;
2601 	mib[1] = MINIX_TEST;
2602 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
2603 
2604 	/*
2605 	 * First try setting and retrieving the description of a dynamic node
2606 	 * in a directory full of static nodes.
2607 	 */
2608 	mib[2] = CTL_CREATE;
2609 	memset(&scn, 0, sizeof(scn));
2610 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2611 	    CTLFLAG_READONLY | CTLTYPE_INT;
2612 	scn.sysctl_size = sizeof(int);
2613 	scn.sysctl_num = TEST_DYNAMIC;
2614 	scn.sysctl_idata = 27182818;
2615 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2616 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2617 
2618 	memcpy(&tmpscn, &scn, sizeof(tmpscn));
2619 
2620 	/* We should get an empty description for the node in a listing. */
2621 	mib[2] = CTL_DESCRIBE;
2622 	memset(buf, 0, sizeof(buf));
2623 	oldlen = sizeof(buf);
2624 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2625 
2626 	scd = (struct sysctldesc *)buf;
2627 	endscd = (struct sysctldesc *)&buf[oldlen];
2628 	seen = 0;
2629 
2630 	while (scd < endscd) {
2631 		if (scd->descr_num == TEST_DYNAMIC) {
2632 			if (seen++) e(0);
2633 
2634 			if (scd->descr_len != 1) e(0);
2635 			if (scd->descr_str[0] != '\0') e(0);
2636 		}
2637 
2638 		if (scd->descr_ver == 0) e(0);
2639 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2640 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2641 
2642 		p = scd->descr_str + scd->descr_len;
2643 		while (p != (char *)NEXT_DESCR(scd))
2644 			if (*p++ != '\0') e(0);
2645 
2646 		scd = NEXT_DESCR(scd);
2647 	}
2648 	if (scd != endscd) e(0);
2649 
2650 	if (!seen) e(0);
2651 
2652 	/* We should get an empty description quering the node directly. */
2653 	if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != 0) e(0);
2654 
2655 	/* Attempt to set a description with a bad description pointer. */
2656 	if (describe_node(mib, 2, TEST_DYNAMIC, bad_ptr, 1) != -1) e(0);
2657 	if (errno != EFAULT) e(0);
2658 
2659 	/* Attempt to set a description that is longer than allowed. */
2660 	memset(buf, 'A', sizeof(buf) - 1);
2661 	buf[sizeof(buf) - 1] = '\0';
2662 	if (describe_node(mib, 2, TEST_DYNAMIC, buf, 1) != -1) e(0);
2663 	if (errno != EINVAL) e(0);
2664 
2665 	/* Now actually set a description. */
2666 	if (describe_node(mib, 2, TEST_DYNAMIC, "Dynamic node", 1) != 0) e(0);
2667 	len = strlen("Dynamic node") + 1;
2668 
2669 	/* We should get the new description for the node in a listing. */
2670 	memset(buf, 0, sizeof(buf));
2671 	oldlen = sizeof(buf);
2672 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2673 
2674 	scd = (struct sysctldesc *)buf;
2675 	endscd = (struct sysctldesc *)&buf[oldlen];
2676 	seen = 0;
2677 
2678 	while (scd < endscd) {
2679 		if (scd->descr_num == TEST_DYNAMIC) {
2680 			if (seen++) e(0);
2681 
2682 			if (scd->descr_len != len) e(0);
2683 			if (strcmp(scd->descr_str, "Dynamic node")) e(0);
2684 		}
2685 
2686 		if (scd->descr_ver == 0) e(0);
2687 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2688 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2689 
2690 		p = scd->descr_str + scd->descr_len;
2691 		while (p != (char *)NEXT_DESCR(scd))
2692 			if (*p++ != '\0') e(0);
2693 
2694 		scd = NEXT_DESCR(scd);
2695 	}
2696 	if (scd != endscd) e(0);
2697 
2698 	if (!seen) e(0);
2699 
2700 	/* We should get the new description quering the node directly. */
2701 	if (describe_node(mib, 2, TEST_DYNAMIC, "Dynamic node", 0) != 0) e(0);
2702 
2703 	mib[2] = CTL_DESCRIBE;
2704 	memset(&scn, 0, sizeof(scn));
2705 	scn.sysctl_flags = SYSCTL_VERS_0;
2706 	scn.sysctl_num = TEST_INT;
2707 	scn.sysctl_desc = "Test description";
2708 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2709 	if (errno != EINVAL) e(0);
2710 
2711 	/* It is not possible to replace an existing static description. */
2712 	scn.sysctl_flags = SYSCTL_VERSION;
2713 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2714 	if (errno != EPERM) e(0);
2715 
2716 	/* Nonexistent nodes cannot be given a description. */
2717 	scn.sysctl_num = INT_MAX;
2718 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2719 	if (errno != ENOENT) e(0);
2720 
2721 	/* It is not possible to replace an existing dynamic description. */
2722 	scn.sysctl_num = TEST_DYNAMIC;
2723 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2724 	if (errno != EPERM) e(0);
2725 
2726 	/* It is not possible to set a description on a permanent node. */
2727 	scn.sysctl_num = TEST_PERM;
2728 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2729 	if (errno != EPERM) e(0);
2730 
2731 	/* Verify that TEST_DYNAMIC now has CTLFLAG_OWNDESC set. */
2732 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
2733 	if (!(scn.sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2734 
2735 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2736 
2737 	/*
2738 	 * Set a description on a static node, ensure that CTLFLAG_OWNDESC is
2739 	 * set, and then destroy the static node.  This should still free the
2740 	 * memory allocated for the description.  We cannot test whether the
2741 	 * memory is really freed, but at least we can trigger this case at
2742 	 * all, and leave the rest up to memory checkers or whatever.  Since we
2743 	 * destroy the static node, we can not do this more than once, and thus
2744 	 * we skip this test if the static node does not exist.
2745 	 */
2746 	r = describe_node(mib, 2, TEST_DESTROY1, "Destroy me", 1);
2747 
2748 	if (r == -1 && errno != ENOENT) e(0);
2749 	else if (r == 0) {
2750 		if (query_node(mib, 2, TEST_DESTROY1, &scn) != 0) e(0);
2751 		if (!(scn.sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2752 
2753 		if (describe_node(mib, 2, TEST_DESTROY1, "Destroy me", 0) != 0)
2754 			e(0);
2755 
2756 		if (destroy_node(mib, 2, TEST_DESTROY1) != 0) e(0);
2757 	}
2758 
2759 	/*
2760 	 * Test queries and description listings in subtrees.
2761 	 */
2762 	mib[2] = CTL_CREATE;
2763 	memset(&scn, 0, sizeof(scn));
2764 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
2765 	scn.sysctl_num = TEST_DYNAMIC;
2766 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2767 	scn.sysctl_desc = "This will not be set.";
2768 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2769 
2770 	/* Setting sysctl_desc should have no effect during creation. */
2771 	if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != 0) e(0);
2772 
2773 	mib[2] = TEST_DYNAMIC;
2774 	id[0] = create_node(mib, 3, &tmpscn, CTL_CREATE, "NodeA", -1, NULL);
2775 	if (id[0] < 0) e(0);
2776 	id[1] = create_node(mib, 3, &tmpscn, CTL_CREATE, "NodeB", -1, NULL);
2777 	if (id[1] < 0) e(0);
2778 	if (id[0] == id[1]) e(0);
2779 
2780 	mib[3] = CTL_QUERY;
2781 	oldlen = sizeof(scnset);
2782 	if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2783 	if (oldlen != sizeof(scnset[0]) * 2) e(0);
2784 	i = (scnset[0].sysctl_num != id[0]);
2785 	if (scnset[i].sysctl_num != id[0]) e(0);
2786 	if (scnset[1 - i].sysctl_num != id[1]) e(0);
2787 	if (scnset[i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2788 	if (scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2789 
2790 	mib[3] = CTL_DESCRIBE;
2791 	memset(buf, 0, sizeof(buf));
2792 	oldlen = sizeof(buf);
2793 	if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2794 	if (oldlen == 0) e(0);
2795 
2796 	scdset[0] = (struct sysctldesc *)buf;
2797 	scdset[1] = NEXT_DESCR(scdset[0]);
2798 	if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2799 	i = (scdset[0]->descr_num != id[0]);
2800 	if (scdset[i]->descr_num != id[0]) e(0);
2801 	if (scdset[i]->descr_ver == 0) e(0);
2802 	if (scdset[i]->descr_len != 1) e(0);
2803 	if (scdset[i]->descr_str[0] != '\0') e(0);
2804 	if (scdset[1 - i]->descr_num != id[1]) e(0);
2805 	if (scdset[1 - i]->descr_ver == 0) e(0);
2806 	if (scdset[1 - i]->descr_len != 1) e(0);
2807 	if (scdset[1 - i]->descr_str[0] != '\0') e(0);
2808 
2809 	if (describe_node(mib, 3, id[0], "Description A", 1) != 0) e(0);
2810 
2811 	mib[3] = CTL_QUERY;
2812 	oldlen = sizeof(scnset);
2813 	if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2814 	if (oldlen != sizeof(scnset[0]) * 2) e(0);
2815 	i = (scnset[0].sysctl_num != id[0]);
2816 	if (scnset[i].sysctl_num != id[0]) e(0);
2817 	if (scnset[1 - i].sysctl_num != id[1]) e(0);
2818 	if (!(scnset[i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2819 	if (scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2820 
2821 	mib[3] = CTL_DESCRIBE;
2822 	memset(buf, 0, sizeof(buf));
2823 	oldlen = sizeof(buf);
2824 	if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2825 	if (oldlen == 0) e(0);
2826 
2827 	scdset[0] = (struct sysctldesc *)buf;
2828 	scdset[1] = NEXT_DESCR(scdset[0]);
2829 	if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2830 	i = (scdset[0]->descr_num != id[0]);
2831 	if (scdset[i]->descr_num != id[0]) e(0);
2832 	if (scdset[i]->descr_ver == 0) e(0);
2833 	if (strcmp(scdset[i]->descr_str, "Description A")) e(0);
2834 	if (scdset[i]->descr_len != strlen(scdset[i]->descr_str) + 1) e(0);
2835 	if (scdset[1 - i]->descr_num != id[1]) e(0);
2836 	if (scdset[1 - i]->descr_ver == 0) e(0);
2837 	if (scdset[1 - i]->descr_len != 1) e(0);
2838 	if (scdset[1 - i]->descr_str[0] != '\0') e(0);
2839 
2840 	if (describe_node(mib, 3, id[1], "Description B", 1) != 0) e(0);
2841 
2842 	mib[3] = CTL_QUERY;
2843 	oldlen = sizeof(scnset);
2844 	if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2845 	if (oldlen != sizeof(scnset[0]) * 2) e(0);
2846 	i = (scnset[0].sysctl_num != id[0]);
2847 	if (scnset[i].sysctl_num != id[0]) e(0);
2848 	if (scnset[1 - i].sysctl_num != id[1]) e(0);
2849 	if (!(scnset[i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2850 	if (!(scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2851 
2852 	mib[3] = CTL_DESCRIBE;
2853 	memset(buf, 0, sizeof(buf));
2854 	oldlen = sizeof(buf);
2855 	if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2856 	if (oldlen == 0) e(0);
2857 
2858 	scdset[0] = (struct sysctldesc *)buf;
2859 	scdset[1] = NEXT_DESCR(scdset[0]);
2860 	if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2861 	i = (scdset[0]->descr_num != id[0]);
2862 	if (scdset[i]->descr_num != id[0]) e(0);
2863 	if (scdset[i]->descr_ver == 0) e(0);
2864 	if (strcmp(scdset[i]->descr_str, "Description A")) e(0);
2865 	if (scdset[i]->descr_len != strlen(scdset[i]->descr_str) + 1) e(0);
2866 	if (scdset[1 - i]->descr_num != id[1]) e(0);
2867 	if (scdset[1 - i]->descr_ver == 0) e(0);
2868 	if (strcmp(scdset[1 - i]->descr_str, "Description B")) e(0);
2869 	if (scdset[1 - i]->descr_len != strlen(scdset[1 - i]->descr_str) + 1)
2870 		e(0);
2871 
2872 	if (destroy_node(mib, 3, id[0]) != 0) e(0);
2873 	if (destroy_node(mib, 3, id[1]) != 0) e(0);
2874 
2875 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2876 
2877 	/*
2878 	 * Test that the resulting description is copied out after setting it,
2879 	 * and that copy failures do not undo the description getting set.
2880 	 */
2881 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2882 	    NULL) == -1) e(0);
2883 
2884 	mib[2] = CTL_DESCRIBE;
2885 	memset(&scn, 0, sizeof(scn));
2886 	scn.sysctl_flags = SYSCTL_VERSION;
2887 	scn.sysctl_num = TEST_DYNAMIC;
2888 	scn.sysctl_desc = "Testing..";
2889 	memset(buf, 0, sizeof(buf));
2890 	oldlen = sizeof(buf);
2891 	if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != 0) e(0);
2892 	if (oldlen == 0) e(0);
2893 	len = oldlen;
2894 
2895 	scd = (struct sysctldesc *)buf;
2896 	if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2897 	if (scd->descr_len != strlen(scn.sysctl_desc) + 1) e(0);
2898 	if (strcmp(scd->descr_str, scn.sysctl_desc)) e(0);
2899 	if (oldlen != (size_t)((char *)NEXT_DESCR(scd) - buf)) e(0);
2900 	p = scd->descr_str + scd->descr_len;
2901 	while (p != (char *)NEXT_DESCR(scd))
2902 		if (*p++ != '\0') e(0);
2903 
2904 	if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2905 
2906 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2907 
2908 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2909 	    NULL) == -1) e(0);
2910 
2911 	memset(buf, 0, sizeof(buf));
2912 	oldlen = len - 1;
2913 	if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2914 	if (errno != ENOMEM) e(0);
2915 	if (oldlen != len) e(0);
2916 
2917 	if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2918 
2919 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2920 
2921 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2922 	    NULL) == -1) e(0);
2923 
2924 	memset(buf, 0, sizeof(buf));
2925 	oldlen = len;
2926 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2927 	if (errno != EFAULT) e(0);
2928 
2929 	if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2930 
2931 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2932 
2933 	/* Finally, ensure that unprivileged users cannot set descriptions. */
2934 	memcpy(&scn, &tmpscn, sizeof(scn));
2935 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2936 	    CTLFLAG_READWRITE | CTLFLAG_ANYWRITE | CTLTYPE_INT;
2937 	if (create_node(mib, 2, &scn, TEST_DYNAMIC, "dynamic", -1,
2938 	    NULL) == -1) e(0);
2939 
2940 	(void)test_nonroot(sub87f);
2941 
2942 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2943 }
2944 
2945 /*
2946  * Set or test buffer contents.  When setting, the buffer is filled with a
2947  * sequence of bytes that is a) free of null characters and b) likely to cause
2948  * detection of wrongly copied subsequences.  When testing, for any size up to
2949  * the size used to set the buffer contents, 0 is returned if the buffer
2950  * contents match expectations, or -1 if they do not.
2951  */
2952 static int
2953 test_buf(char * buf, unsigned char c, size_t size, int set)
2954 {
2955 	unsigned char *ptr;
2956 	int step;
2957 
2958 	ptr = (unsigned char *)buf;
2959 
2960 	for (step = 1; size > 0; size--) {
2961 		if (set)
2962 			*ptr++ = c;
2963 		else if (*ptr++ != c)
2964 			return -1;
2965 
2966 		c += step;
2967 		if (c == 0) {
2968 			if (++step == 256)
2969 				step = 1;
2970 			c += step;
2971 		}
2972 	}
2973 
2974 	return 0;
2975 }
2976 
2977 /*
2978  * Test large data sizes from an unprivileged process.
2979  */
2980 static void
2981 sub87g(void)
2982 {
2983 	char *ptr;
2984 	size_t size, oldlen;
2985 	int id, mib[3];
2986 
2987 	size = getpagesize() * 3;
2988 
2989 	if ((ptr = mmap(NULL, size, PROT_READ, MAP_ANON | MAP_PRIVATE, -1,
2990 	    0)) == MAP_FAILED) e(0);
2991 	memset(ptr, 0x2f, size);
2992 
2993 	mib[0] = CTL_MINIX;
2994 	mib[1] = MINIX_TEST;
2995 	mib[2] = TEST_DYNAMIC;
2996 	oldlen = size - 2;
2997 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
2998 	if (oldlen != size - 2) e(0);
2999 	if (test_buf(ptr, 'D', size - 2, 0) != 0) e(0);
3000 
3001 	/*
3002 	 * Given the large data size, we currently expect this attempt to
3003 	 * write to the structure to be blocked by the MIB service.
3004 	 */
3005 	if (sysctl(mib, 3, NULL, NULL, ptr, oldlen) != -1) e(0);
3006 	if (errno != EPERM) e(0);
3007 
3008 	/* Get the ID of the second dynamic node. */
3009 	mib[2] = TEST_ANYWRITE;
3010 	oldlen = sizeof(id);
3011 	if (sysctl(mib, 3, &id, &oldlen, NULL, 0) != 0) e(0);
3012 	if (oldlen != sizeof(id)) e(0);
3013 	if (id < 0) e(0);
3014 
3015 	/*
3016 	 * Test data size limits for strings as well, although here we can also
3017 	 * ensure that we hit the right check by testing with a shorter string.
3018 	 */
3019 	mib[2] = id;
3020 	oldlen = size;
3021 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3022 	if (oldlen != size) e(0);
3023 	if (test_buf(ptr, 'f', size - 1, 0) != 0) e(0);
3024 	if (ptr[size - 1] != '\0') e(0);
3025 
3026 	test_buf(ptr, 'h', size - 1, 1);
3027 	if (sysctl(mib, 3, NULL, NULL, ptr, size) != -1) e(0);
3028 	if (errno != EPERM) e(0);
3029 
3030 	if (sysctl(mib, 3, NULL, NULL, ptr, getpagesize() - 1) != 0) e(0);
3031 
3032 	if (munmap(ptr, size) != 0) e(0);
3033 }
3034 
3035 /*
3036  * Test large data sizes and mid-data page faults.
3037  */
3038 static void
3039 test87g(void)
3040 {
3041 	struct sysctlnode scn, newscn;
3042 	char *ptr;
3043 	size_t pgsz, size, oldlen;
3044 	int id, mib[3];
3045 
3046 	subtest = 6;
3047 
3048 	/*
3049 	 * No need to go overboard with sizes here; it will just cause the MIB
3050 	 * service's memory usage to grow - permanently.  Three pages followed
3051 	 * by an unmapped page is plenty for this test.
3052 	 */
3053 	pgsz = getpagesize();
3054 	size = pgsz * 3;
3055 
3056 	if ((ptr = mmap(NULL, size + pgsz, PROT_READ, MAP_ANON | MAP_PRIVATE,
3057 	    -1, 0)) == MAP_FAILED) e(0);
3058 	if (munmap(ptr + size, pgsz) != 0) e(0);
3059 
3060 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
3061 
3062 	/* Test string creation initializers with an accurate length. */
3063 	mib[0] = CTL_MINIX;
3064 	mib[1] = MINIX_TEST;
3065 	mib[2] = CTL_CREATE;
3066 	memset(&scn, 0, sizeof(scn));
3067 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3068 	    CTLFLAG_READWRITE | CTLTYPE_STRING;
3069 	scn.sysctl_num = TEST_DYNAMIC;
3070 	scn.sysctl_data = ptr;
3071 	scn.sysctl_size = size;
3072 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
3073 	test_buf(ptr, 'a', size, 1);
3074 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3075 	if (errno != EINVAL) e(0); /* no null terminator */
3076 
3077 	scn.sysctl_size++;
3078 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3079 	if (errno != EFAULT) e(0);
3080 
3081 	scn.sysctl_size--;
3082 	ptr[size - 1] = '\0';
3083 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3084 
3085 	mib[2] = TEST_DYNAMIC;
3086 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
3087 	if (oldlen != size) e(0);
3088 
3089 	memset(ptr, 0, size);
3090 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3091 	if (oldlen != size) e(0);
3092 	if (ptr[size - 1] != '\0') e(0);
3093 	if (test_buf(ptr, 'a', size - 1, 0) != 0) e(0);
3094 
3095 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3096 
3097 	/* Test string creation initializers with no length. */
3098 	mib[2] = CTL_CREATE;
3099 	scn.sysctl_size = 0;
3100 	test_buf(ptr, 'b', size, 1);
3101 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3102 	if (errno != EFAULT) e(0);
3103 
3104 	test_buf(ptr, 'b', size - 1, 1);
3105 	ptr[size - 1] = '\0';
3106 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3107 
3108 	if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
3109 	if (newscn.sysctl_size != size) e(0);
3110 
3111 	mib[2] = TEST_DYNAMIC;
3112 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
3113 	if (oldlen != size) e(0);
3114 
3115 	memset(ptr, 0x7e, size);
3116 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3117 	if (oldlen != size) e(0);
3118 	if (ptr[size - 1] != '\0') e(0);
3119 	if (test_buf(ptr, 'b', size - 1, 0) != 0) e(0);
3120 
3121 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3122 
3123 	/*
3124 	 * Test string creation initializers with a length exceeding the string
3125 	 * length.  If the string is properly null terminated, this should not
3126 	 * result in a fault.
3127 	 */
3128 	mib[2] = CTL_CREATE;
3129 	scn.sysctl_size = size;
3130 	scn.sysctl_data = &ptr[size - pgsz - 5];
3131 	test_buf(&ptr[size - pgsz - 5], 'c', pgsz + 5, 1);
3132 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3133 	if (errno != EFAULT) e(0);
3134 
3135 	ptr[size - 1] = '\0';
3136 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3137 
3138 	if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
3139 	if (newscn.sysctl_size != size) e(0);
3140 
3141 	mib[2] = TEST_DYNAMIC;
3142 	oldlen = size - pgsz - 6;
3143 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3144 	if (oldlen != pgsz + 5) e(0);
3145 	/* We rely on only the actual string getting copied out here. */
3146 	if (memcmp(ptr, &ptr[size - pgsz - 5], pgsz + 5)) e(0);
3147 
3148 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3149 
3150 	/* Test structure creation initializers. */
3151 	mib[2] = CTL_CREATE;
3152 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3153 	    CTLFLAG_ANYWRITE | CTLFLAG_READWRITE | CTLTYPE_STRUCT;
3154 	scn.sysctl_size = size - 2;
3155 	scn.sysctl_data = &ptr[3];
3156 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3157 	if (errno != EFAULT) e(0);
3158 
3159 	scn.sysctl_data = &ptr[2];
3160 	test_buf(&ptr[2], 'd', size - 2, 1);
3161 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3162 
3163 	mib[2] = TEST_DYNAMIC;
3164 	memset(ptr, 0x3b, size);
3165 	oldlen = size - 2;
3166 	if (sysctl(mib, 3, &ptr[3], &oldlen, NULL, 0) != -1) e(0);
3167 	if (errno != EFAULT) e(0);
3168 	oldlen = size - 2;
3169 	if (sysctl(mib, 3, &ptr[2], &oldlen, NULL, 0) != 0) e(0);
3170 	if (oldlen != size - 2) e(0);
3171 	if (test_buf(&ptr[2], 'd', size - 2, 0) != 0) e(0);
3172 
3173 	/*
3174 	 * Test setting new values.  We already have a structure node, so let's
3175 	 * start there.
3176 	 */
3177 	test_buf(&ptr[2], 'D', size - 2, 1);
3178 	if (sysctl(mib, 3, NULL, NULL, &ptr[3], size - 2) != -1) e(0);
3179 	if (errno != EFAULT) e(0);
3180 
3181 	/* Did the mid-data fault cause a partial update?  It better not. */
3182 	memset(ptr, 0x4c, size);
3183 	oldlen = size - 2;
3184 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3185 	if (oldlen != size - 2) e(0);
3186 	if (test_buf(ptr, 'd', size - 2, 0) != 0) e(0);
3187 
3188 	test_buf(&ptr[2], 'D', size - 2, 1);
3189 	if (sysctl(mib, 3, NULL, NULL, &ptr[2], size - 2) != 0) e(0);
3190 
3191 	memset(ptr, 0x5d, size);
3192 	oldlen = size - 2;
3193 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3194 	if (oldlen != size - 2) e(0);
3195 	if (test_buf(ptr, 'D', size - 2, 0) != 0) e(0);
3196 
3197 	/*
3198 	 * We are going to reuse TEST_DYNAMIC for the non-root test later, so
3199 	 * create a new node for string tests.
3200 	 */
3201 	mib[2] = CTL_CREATE;
3202 	memset(&scn, 0, sizeof(scn));
3203 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3204 	    CTLFLAG_ANYWRITE | CTLFLAG_READWRITE | CTLTYPE_STRING;
3205 	scn.sysctl_num = CTL_CREATE;
3206 	scn.sysctl_size = size;
3207 	scn.sysctl_data = ptr;
3208 	test_buf(ptr, 'e', size - 1, 1);
3209 	ptr[size - 1] = '\0';
3210 	strlcpy(scn.sysctl_name, "dynamic2", sizeof(scn.sysctl_name));
3211 	oldlen = sizeof(newscn);
3212 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3213 	if (oldlen != sizeof(newscn)) e(0);
3214 	id = newscn.sysctl_num;
3215 	if (id < 0) e(0);
3216 
3217 	/*
3218 	 * Test setting a short but faulty string, ensuring that no partial
3219 	 * update on the field contents takes place.
3220 	 */
3221 	mib[2] = id;
3222 	memcpy(&ptr[size - 3], "XYZ", 3);
3223 	if (sysctl(mib, 3, NULL, NULL, &ptr[size - 3], 4) != -1) e(0);
3224 	if (errno != EFAULT) e(0);
3225 
3226 	oldlen = size;
3227 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3228 	if (oldlen != size) e(0);
3229 	if (test_buf(ptr, 'e', size - 1, 0) != 0) e(0);
3230 	if (ptr[size - 1] != '\0') e(0);
3231 
3232 	memcpy(&ptr[size - 3], "XYZ", 3);
3233 	if (sysctl(mib, 3, NULL, NULL, &ptr[size - 3], 3) != 0) e(0);
3234 
3235 	oldlen = size;
3236 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3237 	if (oldlen != 4) e(0);
3238 	if (strcmp(ptr, "XYZ")) e(0);
3239 
3240 	test_buf(&ptr[1], 'f', size - 1, 1);
3241 	if (sysctl(mib, 3, NULL, NULL, &ptr[1], size - 1) != 0) e(0);
3242 
3243 	test_buf(&ptr[1], 'G', size - 1, 1);
3244 	if (sysctl(mib, 3, NULL, NULL, &ptr[1], size) != -1) e(0);
3245 	if (errno != EFAULT) e(0);
3246 
3247 	oldlen = size;
3248 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3249 	if (oldlen != size) e(0);
3250 	if (test_buf(ptr, 'f', size - 1, 0) != 0) e(0);
3251 	if (ptr[size - 1] != '\0') e(0);
3252 
3253 	/*
3254 	 * Test descriptions as well.  First, the MIB service does not allow
3255 	 * for overly long descriptions, although the limit is not exposed.
3256 	 * Three memory pages worth of text is way too long though.
3257 	 */
3258 	memset(ptr, 'A', size);
3259 	if (describe_node(mib, 2, id, ptr, 1) != -1) e(0);
3260 	if (errno != EINVAL) e(0); /* not EFAULT, should never get that far */
3261 
3262 	ptr[size - 1] = '\0';
3263 	if (describe_node(mib, 2, id, ptr, 1) != -1) e(0);
3264 	if (errno != EINVAL) e(0);
3265 
3266 	if (describe_node(mib, 2, id, "", 0) != 0) e(0);
3267 
3268 	/*
3269 	 * Second, the description routine must deal with faults occurring
3270 	 * while it is trying to find the string end.
3271 	 */
3272 	ptr[size - 2] = 'B';
3273 	ptr[size - 1] = 'C';
3274 	if (describe_node(mib, 2, id, &ptr[size - 3], 1) != -1) e(0);
3275 	if (errno != EFAULT) e(0);
3276 
3277 	if (describe_node(mib, 2, id, "", 0) != 0) e(0);
3278 
3279 	ptr[size - 1] = '\0';
3280 	if (describe_node(mib, 2, id, &ptr[size - 3], 1) != 0) e(0);
3281 
3282 	if (describe_node(mib, 2, id, "AB", 0) != 0) e(0);
3283 
3284 	/* Pass the second dynamic node ID to the unprivileged child. */
3285 	mib[2] = TEST_ANYWRITE;
3286 	if (sysctl(mib, 3, NULL, NULL, &id, sizeof(id)) != 0) e(0);
3287 
3288 	(void)test_nonroot(sub87g);
3289 
3290 	mib[2] = id;
3291 	oldlen = size;
3292 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3293 	if (oldlen != pgsz) e(0);
3294 	if (test_buf(ptr, 'h', pgsz - 1, 1) != 0) e(0);
3295 	if (ptr[pgsz - 1] != '\0') e(0);
3296 
3297 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3298 	if (destroy_node(mib, 2, id) != 0) e(0);
3299 
3300 	munmap(ptr, size);
3301 }
3302 
3303 /*
3304  * Verify whether the given node on the given path has the given node version.
3305  * Return 0 if the version matches, or -1 if it does not or a failure occurred.
3306  */
3307 static int
3308 check_version(const int * path, unsigned int pathlen, int id, uint32_t ver)
3309 {
3310 	struct sysctlnode scn;
3311 	struct sysctldesc scd;
3312 	size_t oldlen;
3313 	int r, mib[CTL_MAXNAME];
3314 
3315 	assert(pathlen < CTL_MAXNAME);
3316 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
3317 	mib[pathlen] = CTL_DESCRIBE;
3318 
3319 	/*
3320 	 * For some reason, when retrieving a particular description (as
3321 	 * opposed to setting one), the node version number is not checked.
3322 	 * In order to test this, we deliberately pass in a node version number
3323 	 * that, if checked, would eventually cause failures.
3324 	 */
3325 	memset(&scn, 0, sizeof(scn));
3326 	scn.sysctl_flags = SYSCTL_VERSION;
3327 	scn.sysctl_num = id;
3328 	scn.sysctl_ver = 1;
3329 	oldlen = sizeof(scd);
3330 	r = sysctl(mib, pathlen + 1, &scd, &oldlen, &scn, sizeof(scn));
3331 	if (r == -1 && errno != ENOMEM) e(0);
3332 
3333 	return (scd.descr_ver == ver) ? 0 : -1;
3334 }
3335 
3336 /*
3337  * Test sysctl(2) node versioning.
3338  */
3339 static void
3340 test87h(void)
3341 {
3342 	struct sysctlnode scn, oldscn;
3343 	size_t oldlen;
3344 	uint32_t ver[4];
3345 	int mib[4], id[4];
3346 
3347 	/*
3348 	 * The other tests have already tested sufficiently that a zero version
3349 	 * is always accepted in calls.  Here, we test that node versions
3350 	 * actually change when creating and destroying nodes, and that the
3351 	 * right version test is implemented for all of the four node meta-
3352 	 * operations (query, create, destroy, describe).  Why did we not do
3353 	 * this earlier, you ask?  Well, versioning was implemented later on.
3354 	 */
3355 	subtest = 7;
3356 
3357 	/*
3358 	 * Test versioning with node creation.
3359 	 */
3360 	mib[0] = CTL_MINIX;
3361 	mib[1] = MINIX_TEST;
3362 	mib[2] = CTL_CREATE;
3363 	memset(&scn, 0, sizeof(scn));
3364 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
3365 	scn.sysctl_num = CTL_CREATE;
3366 	strlcpy(scn.sysctl_name, "NodeA", sizeof(scn.sysctl_name));
3367 	oldlen = sizeof(oldscn);
3368 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3369 	if (oldlen != sizeof(oldscn)) e(0);
3370 	id[0] = oldscn.sysctl_num;
3371 	ver[0] = oldscn.sysctl_ver;
3372 	if (ver[0] == 0) e(0);
3373 
3374 	if (check_version(mib, 0, CTL_MINIX, ver[0]) != 0) e(0);
3375 	if (check_version(mib, 1, MINIX_TEST, ver[0]) != 0) e(0);
3376 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3377 
3378 	strlcpy(scn.sysctl_name, "NodeB", sizeof(scn.sysctl_name));
3379 	oldlen = sizeof(oldscn);
3380 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3381 	if (oldlen != sizeof(oldscn)) e(0);
3382 	id[1] = oldscn.sysctl_num;
3383 	ver[1] = oldscn.sysctl_ver;
3384 	if (ver[1] == 0) e(0);
3385 	if (ver[1] != NEXT_VER(ver[0])) e(0);
3386 
3387 	if (check_version(mib, 0, CTL_MINIX, ver[1]) != 0) e(0);
3388 	if (check_version(mib, 1, MINIX_TEST, ver[1]) != 0) e(0);
3389 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3390 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3391 
3392 	/* A version that is too high should be rejected. */
3393 	mib[2] = id[0];
3394 	mib[3] = CTL_CREATE;
3395 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
3396 	    CTLFLAG_READWRITE | CTLTYPE_INT;
3397 	scn.sysctl_size = sizeof(int);
3398 	scn.sysctl_ver = NEXT_VER(ver[1]);
3399 	strlcpy(scn.sysctl_name, "ValueA", sizeof(scn.sysctl_name));
3400 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3401 	if (errno != EINVAL) e(0);
3402 
3403 	/* The version of the parent node should be accepted. */
3404 	scn.sysctl_ver = ver[0]; /* different from the root node version */
3405 	oldlen = sizeof(oldscn);
3406 	if (sysctl(mib, 4, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3407 	if (oldlen != sizeof(oldscn)) e(0);
3408 	id[2] = oldscn.sysctl_num;
3409 	ver[2] = oldscn.sysctl_ver;
3410 	if (ver[2] == 0) e(0);
3411 	if (ver[2] != NEXT_VER(ver[1])) e(0);
3412 
3413 	if (check_version(mib, 0, CTL_MINIX, ver[2]) != 0) e(0);
3414 	if (check_version(mib, 1, MINIX_TEST, ver[2]) != 0) e(0);
3415 	if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3416 	if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3417 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3418 
3419 	/* A version that is too low (old) should be rejected. */
3420 	mib[2] = id[1];
3421 
3422 	scn.sysctl_ver = ver[0];
3423 	strlcpy(scn.sysctl_name, "ValueB", sizeof(scn.sysctl_name));
3424 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3425 	if (errno != EINVAL) e(0);
3426 
3427 	/* The version of the root node should be accepted. */
3428 	scn.sysctl_ver = ver[2]; /* different from the parent node version */
3429 	oldlen = sizeof(oldscn);
3430 	if (sysctl(mib, 4, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3431 	if (oldlen != sizeof(oldscn)) e(0);
3432 	id[3] = oldscn.sysctl_num;
3433 	ver[3] = oldscn.sysctl_ver;
3434 	if (ver[3] == 0) e(0);
3435 	if (ver[3] != NEXT_VER(ver[2])) e(0);
3436 
3437 	if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3438 	if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3439 	if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3440 	if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3441 	if (check_version(mib, 3, id[3], ver[3]) != 0) e(0);
3442 	mib[2] = id[0];
3443 	if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3444 
3445 	/*
3446 	 * Test versioning with node queries.
3447 	 */
3448 	mib[3] = CTL_QUERY;
3449 	memset(&scn, 0, sizeof(scn));
3450 	scn.sysctl_flags = SYSCTL_VERSION;
3451 	scn.sysctl_ver = ver[0]; /* previous parent version */
3452 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3453 	if (errno != EINVAL) e(0);
3454 
3455 	scn.sysctl_ver = ver[2]; /* parent version */
3456 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3457 
3458 	scn.sysctl_ver = ver[2]; /* root version */
3459 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3460 
3461 	scn.sysctl_ver = NEXT_VER(ver[3]); /* nonexistent version */
3462 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3463 	if (errno != EINVAL) e(0);
3464 
3465 	/*
3466 	 * Test versioning with node description.
3467 	 */
3468 	mib[2] = CTL_DESCRIBE;
3469 	scn.sysctl_num = id[0];
3470 	scn.sysctl_ver = ver[3]; /* root and parent, but not target version */
3471 	scn.sysctl_desc = "Parent A";
3472 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3473 	if (errno != EINVAL) e(0);
3474 
3475 	scn.sysctl_ver = ver[1]; /* another bad version */
3476 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3477 	if (errno != EINVAL) e(0);
3478 
3479 	scn.sysctl_ver = ver[2]; /* target version */
3480 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3481 
3482 	/* Neither querying nor description should have changed versions. */
3483 	if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3484 	if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3485 	if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3486 	if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3487 	mib[2] = id[1];
3488 	if (check_version(mib, 3, id[3], ver[3]) != 0) e(0);
3489 	mib[2] = id[0];
3490 	if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3491 
3492 	/*
3493 	 * Test versioning with node destruction.
3494 	 */
3495 	mib[3] = CTL_DESTROY;
3496 	memset(&scn, 0, sizeof(scn));
3497 	scn.sysctl_flags = SYSCTL_VERSION;
3498 	scn.sysctl_num = id[2];
3499 	scn.sysctl_ver = ver[3]; /* root but not target version */
3500 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3501 	if (errno != EINVAL) e(0);
3502 
3503 	scn.sysctl_ver = ver[2]; /* target (and parent) version */
3504 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3505 
3506 	/* Fortunately, versions are predictable. */
3507 	ver[0] = NEXT_VER(ver[3]);
3508 
3509 	if (check_version(mib, 0, CTL_MINIX, ver[0]) != 0) e(0);
3510 	if (check_version(mib, 1, MINIX_TEST, ver[0]) != 0) e(0);
3511 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3512 	if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3513 
3514 	mib[2] = id[1];
3515 	scn.sysctl_num = id[3];
3516 	scn.sysctl_ver = ver[0]; /* root but not target version */
3517 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3518 	if (errno != EINVAL) e(0);
3519 
3520 	scn.sysctl_ver = ver[3]; /* target (and parent) version */
3521 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3522 
3523 	ver[1] = NEXT_VER(ver[0]);
3524 
3525 	if (check_version(mib, 0, CTL_MINIX, ver[1]) != 0) e(0);
3526 	if (check_version(mib, 1, MINIX_TEST, ver[1]) != 0) e(0);
3527 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3528 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3529 
3530 	mib[2] = CTL_DESTROY;
3531 	scn.sysctl_num = id[0];
3532 	scn.sysctl_ver = ver[1]; /* root and parent, but not target version */
3533 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3534 	if (errno != EINVAL) e(0);
3535 
3536 	scn.sysctl_ver = ver[0]; /* target version */
3537 	oldlen = sizeof(oldscn);
3538 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3539 	if (oldlen != sizeof(oldscn)) e(0);
3540 	if (oldscn.sysctl_num != id[0]) e(0);
3541 	if (oldscn.sysctl_ver != ver[0]) e(0);
3542 
3543 	ver[2] = NEXT_VER(ver[1]);
3544 
3545 	if (check_version(mib, 0, CTL_MINIX, ver[2]) != 0) e(0);
3546 	if (check_version(mib, 1, MINIX_TEST, ver[2]) != 0) e(0);
3547 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3548 
3549 	/* For the last destruction, just see if we get the old version. */
3550 	scn.sysctl_num = id[1];
3551 	scn.sysctl_ver = 0;
3552 	oldlen = sizeof(oldscn);
3553 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3554 	if (oldlen != sizeof(oldscn)) e(0);
3555 	if (oldscn.sysctl_num != id[1]) e(0);
3556 	if (oldscn.sysctl_ver != ver[1]) e(0);
3557 
3558 	ver[3] = NEXT_VER(ver[2]);
3559 
3560 	if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3561 	if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3562 }
3563 
3564 /*
3565  * Perform pre-test initialization.
3566  */
3567 static void
3568 test87_init(void)
3569 {
3570 	size_t oldlen;
3571 	int mib[3];
3572 
3573 	subtest = 99;
3574 
3575 	if ((bad_ptr = mmap(NULL, getpagesize(), PROT_READ,
3576 	    MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) e(0);
3577 	if (munmap(bad_ptr, getpagesize()) != 0) e(0);
3578 
3579 	mib[0] = CTL_MINIX;
3580 	mib[1] = MINIX_MIB;
3581 	mib[2] = MIB_NODES;
3582 	oldlen = sizeof(nodes);
3583 	if (sysctl(mib, 3, &nodes, &oldlen, NULL, 0) != 0) e(0);
3584 	if (oldlen != sizeof(nodes)) e(0);
3585 
3586 	mib[2] = MIB_OBJECTS;
3587 	oldlen = sizeof(objects);
3588 	if (sysctl(mib, 3, &objects, &oldlen, NULL, 0) != 0) e(0);
3589 	if (oldlen != sizeof(objects)) e(0);
3590 }
3591 
3592 /*
3593  * Perform post-test checks.
3594  */
3595 static void
3596 test87_check(void)
3597 {
3598 	unsigned int newnodes, newobjects;
3599 	size_t oldlen;
3600 	int mib[3];
3601 
3602 	subtest = 99;
3603 
3604 	mib[0] = CTL_MINIX;
3605 	mib[1] = MINIX_MIB;
3606 	mib[2] = MIB_NODES;
3607 	oldlen = sizeof(newnodes);
3608 	if (sysctl(mib, 3, &newnodes, &oldlen, NULL, 0) != 0) e(0);
3609 	if (oldlen != sizeof(newnodes)) e(0);
3610 
3611 	/*
3612 	 * Upon the first run, the total number of nodes must actually go down,
3613 	 * as we destroy number of static nodes.  Upon subsequent runs, the
3614 	 * number of nodes should remain stable.  Thus, we can safely test that
3615 	 * the number of nodes has not gone up as a result of the test.
3616 	 */
3617 	if (newnodes > nodes) e(0);
3618 
3619 	mib[2] = MIB_OBJECTS;
3620 	oldlen = sizeof(newobjects);
3621 	if (sysctl(mib, 3, &newobjects, &oldlen, NULL, 0) != 0) e(0);
3622 	if (oldlen != sizeof(newobjects)) e(0);
3623 
3624 	/*
3625 	 * The number of dynamically allocated objects should remain the same
3626 	 * across the test.
3627 	 */
3628 	if (newobjects != objects) e(0);
3629 }
3630 
3631 /*
3632  * Test program for sysctl(2).
3633  */
3634 int
3635 main(int argc, char ** argv)
3636 {
3637 	int i, m;
3638 
3639 	start(87);
3640 
3641 	if (argc == 2)
3642 		m = atoi(argv[1]);
3643 	else
3644 		m = 0xFF;
3645 
3646 	test87_init();
3647 
3648 	for (i = 0; i < ITERATIONS; i++) {
3649 		if (m & 0x001) test87a();
3650 		if (m & 0x002) test87b();
3651 		if (m & 0x004) test87c();
3652 		if (m & 0x008) test87d();
3653 		if (m & 0x010) test87e();
3654 		if (m & 0x020) test87f();
3655 		if (m & 0x040) test87g();
3656 		if (m & 0x080) test87h();
3657 	}
3658 
3659 	test87_check();
3660 
3661 	quit();
3662 }
3663