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