Remove building with NOCRYPTO option
[minix.git] / minix / tests / test87.c
blob02e043f02bba3e12f6760ea83b56af56124185e6
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>
12 #define ITERATIONS 2
14 #include "common.h"
16 #define NONROOT_USER "bin" /* name of any unprivileged user */
18 #define NEXT_VER(n) (((n) + 1 == 0) ? 1 : ((n) + 1)) /* node version + 1 */
20 static void *bad_ptr; /* a pointer to unmapped memory */
21 static unsigned int nodes, objects; /* stats for pre/post test check */
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.
28 static pid_t
29 test_nonroot(void (* proc)(void))
31 struct passwd *pw;
32 pid_t pid;
33 int status;
35 pid = fork();
37 switch (pid) {
38 case -1:
39 e(0);
40 break;
41 case 0:
42 errct = 0;
44 if ((pw = getpwnam(NONROOT_USER)) == NULL) e(0);
46 if (setuid(pw->pw_uid) != 0) e(0);
48 proc();
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);
57 return pid;
61 * Test basic operations from an unprivileged process.
63 static void
64 sub87a(void)
66 size_t oldlen;
67 pid_t pid;
68 bool b;
69 int i, mib[4];
71 pid = getpid();
73 mib[0] = CTL_MINIX;
74 mib[1] = MINIX_TEST;
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);
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);
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);
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);
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);
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);
110 if (sysctl(mib, 3, NULL, NULL, &i, sizeof(i)) != -1) e(0);
111 if (errno != EPERM) e(0);
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);
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);
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);
132 i = pid;
133 if (sysctl(mib, 3, NULL, NULL, &i, sizeof(i)) != 0) e(0);
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);
143 * Test the basic sysctl(2) interface.
145 static void
146 test87a(void)
148 char buf[32];
149 size_t len, oldlen;
150 pid_t pid;
151 u_quad_t q;
152 bool b, b2;
153 int i, va[2], lastva = -1 /*gcc*/, mib[CTL_MAXNAME + 1];
155 subtest = 0;
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;
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.
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);
177 if (sysctl(mib, i, NULL, NULL, NULL, 0) != -1) e(0);
178 if (errno != EINVAL) e(0);
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);
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);
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);
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);
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);
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);
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);
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];
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);
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);
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);
271 * Ensure that we cannot overwrite this read-only integer. A write
272 * request must have both a pointer and a nonzero length, though.
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);
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);
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);
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.
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);
306 b = true;
307 if (sysctl(mib, 3, NULL, &oldlen, &b, sizeof(b)) != 0) e(0);
308 if (oldlen != sizeof(b)) e(0);
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);
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);
323 if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b) + 1) != -1) e(0);
324 if (errno != EINVAL) e(0);
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.
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);
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);
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);
347 q = 0x1234567890abcdefULL;
348 if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
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);
356 q = ~0ULL;
357 if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
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);
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);
369 q = 0ULL;
370 if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
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);
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);
384 oldlen = sizeof(buf);
385 if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
386 if (oldlen != len + 1) e(0);
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);
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);
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);
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);
416 * Now put in a shorter string, without null terminator. The string
417 * must be accepted; the null terminator must be added automatically.
419 strlcpy(buf, "foolproof", sizeof(buf));
420 len = strlen("foo");
421 if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
423 if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
424 if (oldlen != len + 1) e(0);
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);
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);
442 * Passing in more data after the string is fine, but whatever comes
443 * after the first null terminator is disregarded.
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);
451 if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
452 if (oldlen != len + 1) e(0);
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);
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);
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);
479 * Clearing out the field with zero-length data is not possible,
480 * because zero-length updates are disregarded at a higher level.
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);
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);
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.
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;
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);
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);
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);
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);
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);
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);
552 memset(buf, 0, len);
553 if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
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);
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.
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);
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);
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);
588 /* Use a child process to test operations without root privileges. */
589 pid = test_nonroot(sub87a);
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);
601 * Test queries from an unprivileged process.
603 static void
604 sub87b(void)
606 struct sysctlnode scn[32];
607 unsigned int count;
608 size_t oldlen;
609 int i, mib[4];
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;
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);
623 * Do not bother doing the entire check again, but test enough to
624 * inspire confidence that only the right values are hidden.
626 if (scn[0].sysctl_num != TEST_INT) e(0);
627 if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
628 if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
629 (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE | CTLFLAG_HEX)) e(0);
630 if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
631 if (strcmp(scn[0].sysctl_name, "int")) e(0);
632 if (scn[0].sysctl_ver == 0) e(0);
633 if (scn[0].sysctl_size != sizeof(int)) e(0);
634 if (scn[0].sysctl_idata != 0x01020304) e(0);
636 for (i = 0; i < count; i++)
637 if (scn[i].sysctl_num == TEST_PRIVATE)
638 break;
639 if (i == count) e(0);
640 if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_INT) e(0);
641 if ((SYSCTL_FLAGS(scn[i].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
642 (CTLFLAG_READWRITE | CTLFLAG_PRIVATE | CTLFLAG_IMMEDIATE)) e(0);
643 if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
644 if (strcmp(scn[i].sysctl_name, "private")) e(0);
645 if (scn[i].sysctl_size != sizeof(int)) e(0);
646 if (scn[i].sysctl_idata != 0) e(0); /* private */
648 for (i = 0; i < count; i++)
649 if (scn[i].sysctl_num == TEST_SECRET)
650 break;
651 if (i == count) e(0);
652 if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_NODE) e(0);
653 if ((SYSCTL_FLAGS(scn[i].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
654 (CTLFLAG_READONLY | CTLFLAG_PRIVATE)) e(0);
655 if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
656 if (strcmp(scn[i].sysctl_name, "secret")) e(0);
657 if (scn[i].sysctl_ver == 0) e(0);
658 if (scn[i].sysctl_size != sizeof(scn[0])) e(0);
659 if (scn[i].sysctl_csize != 0) e(0); /* private */
660 if (scn[i].sysctl_clen != 0) e(0); /* private */
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);
670 * Test sysctl(2) queries.
672 static void
673 test87b(void)
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];
682 subtest = 1;
684 /* We should be able to query the root key. */
685 mib[0] = CTL_QUERY;
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);
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);
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.
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);
714 /* Now do a more complete test on the minix.test subtree. */
715 mib[0] = CTL_MINIX;
716 mib[1] = MINIX_TEST;
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.
722 mib[2] = TEST_BOOL;
723 b = true;
724 if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
726 mib[2] = TEST_QUAD;
727 q = ~0;
728 if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
730 mib[2] = CTL_QUERY;
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);
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);
746 * Again, we rely on the MIB service returning entries in ascending
747 * order for at least the static nodes. We do not make assumptions
748 * about whether dynamic nodes are merged in or (as is the case as of
749 * writing) returned after the static nodes. At this point there
750 * should be no dynamic nodes here yet anyway. We mostly ignore
751 * CTLFLAG_PERMANENT in order to facilitate running this test on a
752 * remotely mounted subtree.
754 if (scn[0].sysctl_num != TEST_INT) e(0);
755 if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
756 if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
757 (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE | CTLFLAG_HEX)) e(0);
758 if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
759 if (strcmp(scn[0].sysctl_name, "int")) e(0);
760 if (scn[0].sysctl_ver == 0) e(0);
761 if (scn[0].sysctl_size != sizeof(int)) e(0);
762 if (scn[0].sysctl_idata != 0x01020304) e(0);
764 if (scn[1].sysctl_num != TEST_BOOL) e(0);
765 if (SYSCTL_TYPE(scn[1].sysctl_flags) != CTLTYPE_BOOL) e(0);
766 if ((SYSCTL_FLAGS(scn[1].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
767 (CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE)) e(0);
768 if (SYSCTL_VERS(scn[1].sysctl_flags) != SYSCTL_VERSION) e(0);
769 if (strcmp(scn[1].sysctl_name, "bool")) e(0);
770 if (scn[1].sysctl_ver == 0) e(0);
771 if (scn[1].sysctl_size != sizeof(bool)) e(0);
772 if (scn[1].sysctl_bdata != true) e(0);
774 if (scn[2].sysctl_num != TEST_QUAD) e(0);
775 if (SYSCTL_TYPE(scn[2].sysctl_flags) != CTLTYPE_QUAD) e(0);
776 if ((SYSCTL_FLAGS(scn[2].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
777 (CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE)) e(0);
778 if (SYSCTL_VERS(scn[2].sysctl_flags) != SYSCTL_VERSION) e(0);
779 if (strcmp(scn[2].sysctl_name, "quad")) e(0);
780 if (scn[2].sysctl_ver == 0) e(0);
781 if (scn[2].sysctl_size != sizeof(u_quad_t)) e(0);
782 if (scn[2].sysctl_qdata != q) e(0);
784 if (scn[3].sysctl_num != TEST_STRING) e(0);
785 if (SYSCTL_TYPE(scn[3].sysctl_flags) != CTLTYPE_STRING) e(0);
786 if ((SYSCTL_FLAGS(scn[3].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
787 CTLFLAG_READWRITE) e(0);
788 if (SYSCTL_VERS(scn[3].sysctl_flags) != SYSCTL_VERSION) e(0);
789 if (strcmp(scn[3].sysctl_name, "string")) e(0);
790 if (scn[3].sysctl_ver == 0) e(0);
791 if (scn[3].sysctl_size != 16) e(0);
793 if (scn[4].sysctl_num != TEST_STRUCT) e(0);
794 if (SYSCTL_TYPE(scn[4].sysctl_flags) != CTLTYPE_STRUCT) e(0);
795 if ((SYSCTL_FLAGS(scn[4].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
796 CTLFLAG_READWRITE) e(0);
797 if (SYSCTL_VERS(scn[4].sysctl_flags) != SYSCTL_VERSION) e(0);
798 if (strcmp(scn[4].sysctl_name, "struct")) e(0);
799 if (scn[4].sysctl_ver == 0) e(0);
800 if (scn[4].sysctl_size != 12) e(0);
802 if (scn[5].sysctl_num != TEST_PRIVATE) e(0);
803 if (SYSCTL_TYPE(scn[5].sysctl_flags) != CTLTYPE_INT) e(0);
804 if ((SYSCTL_FLAGS(scn[5].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
805 (CTLFLAG_READWRITE | CTLFLAG_PRIVATE | CTLFLAG_IMMEDIATE)) e(0);
806 if (SYSCTL_VERS(scn[5].sysctl_flags) != SYSCTL_VERSION) e(0);
807 if (strcmp(scn[5].sysctl_name, "private")) e(0);
808 if (scn[5].sysctl_ver == 0) e(0);
809 if (scn[5].sysctl_size != sizeof(int)) e(0);
810 if (scn[5].sysctl_idata != -5375) e(0);
812 if (scn[6].sysctl_num != TEST_ANYWRITE) e(0);
813 if (SYSCTL_TYPE(scn[6].sysctl_flags) != CTLTYPE_INT) e(0);
814 if ((SYSCTL_FLAGS(scn[6].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
815 (CTLFLAG_READWRITE | CTLFLAG_ANYWRITE | CTLFLAG_IMMEDIATE)) e(0);
816 if (SYSCTL_VERS(scn[6].sysctl_flags) != SYSCTL_VERSION) e(0);
817 if (strcmp(scn[6].sysctl_name, "anywrite")) e(0);
818 if (scn[6].sysctl_ver == 0) e(0);
819 if (scn[6].sysctl_size != sizeof(int)) e(0);
821 i = (scn[7].sysctl_num == TEST_DYNAMIC) ? 8 : 7;
823 if (scn[i].sysctl_num != TEST_SECRET) e(0);
824 if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_NODE) e(0);
825 if ((SYSCTL_FLAGS(scn[i].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
826 (CTLFLAG_READONLY | CTLFLAG_PRIVATE)) e(0);
827 if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
828 if (strcmp(scn[i].sysctl_name, "secret")) e(0);
829 if (scn[i].sysctl_ver == 0) e(0);
830 if (scn[i].sysctl_size != sizeof(scn[0])) e(0);
831 if (scn[i].sysctl_csize != 1) e(0);
832 if (scn[i].sysctl_clen != 1) e(0);
835 * Now that we know how many entries there are in minix.test, also look
836 * at whether the right child length is returned in a query on its
837 * parent. While doing that, see whether data structure versioning
838 * works as expected as well. MINIX_TEST is hardcoded to zero so we
839 * expect it to be the first entry returned from a query.
841 mib[1] = CTL_QUERY;
843 memset(scn, 0, sizeof(scn));
844 scn[1].sysctl_flags = SYSCTL_VERS_0;
845 if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1])) != -1) e(0);
846 if (errno != EINVAL) e(0);
847 scn[1].sysctl_flags = SYSCTL_VERS_1;
848 if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1]) - 1) != -1)
849 e(0);
850 if (errno != EINVAL) e(0);
851 if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1]) + 1) != -1)
852 e(0);
853 if (errno != EINVAL) e(0);
854 if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1])) != 0) e(0);
855 if (oldlen == 0) e(0);
856 if (oldlen % sizeof(scn[0])) e(0);
858 oldlen = sizeof(scn[0]);
859 scn[1].sysctl_flags = SYSCTL_VERS_0;
860 if (sysctl(mib, 2, scn, &oldlen, &scn[1], sizeof(scn[1])) != -1) e(0);
861 if (errno != EINVAL) e(0);
862 oldlen = sizeof(scn[0]);
863 scn[1].sysctl_flags = SYSCTL_VERS_1;
864 if (sysctl(mib, 2, scn, &oldlen, &scn[1], sizeof(scn[1])) != 0 &&
865 errno != ENOMEM) e(0);
866 if (oldlen == 0) e(0);
867 if (oldlen % sizeof(scn[0])) e(0);
869 if (scn[0].sysctl_num != MINIX_TEST) e(0);
870 if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_NODE) e(0);
871 if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
872 (CTLFLAG_READWRITE | CTLFLAG_HIDDEN)) e(0);
873 if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
874 if (strcmp(scn[0].sysctl_name, "test")) e(0);
875 if (scn[0].sysctl_ver == 0) e(0);
876 if (scn[0].sysctl_size != sizeof(scn[0])) e(0);
877 if ((int)scn[0].sysctl_clen != count) e(0);
878 if (scn[0].sysctl_csize < scn[0].sysctl_clen) e(0);
881 * Test querying minix.test.secret, which should have exactly one node.
882 * At the same time, test bad pointers.
884 mib[1] = MINIX_TEST;
885 mib[2] = TEST_SECRET;
886 mib[3] = CTL_QUERY;
887 oldlen = sizeof(scn);
888 if (sysctl(mib, 4, NULL, &oldlen, bad_ptr, sizeof(scn[0])) != -1) e(0);
889 if (errno != EFAULT) e(0);
891 oldlen = sizeof(scn[0]) * 2;
892 if (sysctl(mib, 4, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
893 if (errno != EFAULT) e(0);
895 memset(scn, 0x7, sizeof(scn[0]) * 2);
896 oldlen = sizeof(scn[0]) * 2;
897 if (sysctl(mib, 4, scn, &oldlen, NULL, 0) != 0) e(0);
898 if (oldlen != sizeof(scn[0])) e(0);
900 if (scn[0].sysctl_num != SECRET_VALUE) e(0);
901 if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
902 if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
903 (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE)) e(0);
904 if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
905 if (strcmp(scn[0].sysctl_name, "value")) e(0);
906 if (scn[0].sysctl_ver == 0) e(0);
907 if (scn[0].sysctl_size != sizeof(int)) e(0);
908 if (scn[0].sysctl_idata != 12345) e(0);
909 if (scn[1].sysctl_name[0] != 0x07) e(0);
911 /* Use a child process to test queries without root privileges. */
912 (void)test_nonroot(sub87b);
914 /* Do some more path-related error code tests unrelated to the rest. */
915 mib[1] = INT_MAX;
916 mib[2] = CTL_QUERY;
917 oldlen = sizeof(scn[0]);
918 if (sysctl(mib, 3, &scn, &oldlen, NULL, 0) != -1) e(0);
919 if (errno != ENOENT) e(0);
921 mib[1] = MINIX_TEST;
922 mib[2] = TEST_INT;
923 mib[3] = CTL_QUERY;
924 oldlen = sizeof(scn[0]);
925 if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
926 if (errno != ENOTDIR) e(0); /* ..and not EPERM (_INT is read-only) */
928 mib[2] = TEST_BOOL;
929 oldlen = sizeof(scn[0]);
930 if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
931 if (errno != ENOTDIR) e(0); /* (_BOOL is read-write) */
933 mib[2] = CTL_QUERY;
934 oldlen = sizeof(scn[0]);
935 if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
936 if (errno != EINVAL) e(0);
940 * Attempt to create a node, using a given node template, identifier, and name
941 * string. If other_id is nonnegative, the creation is expected to fail due to
942 * a collision with an existing node, which should have the ID other_id and the
943 * name string in other_name. Otherwise, the creation may succeed or fail, and
944 * the caller must perform the appropriate checks. On success, return the new
945 * node identifier. On failure, return -1, with errno set.
947 static int
948 create_node(const int * path, unsigned int pathlen, struct sysctlnode * tmpscn,
949 int id, const char * name, int other_id, const char * other_name)
951 struct sysctlnode scn, oldscn;
952 size_t oldlen;
953 int r, mib[CTL_MAXNAME];
955 assert(pathlen < CTL_MAXNAME);
956 memcpy(mib, path, sizeof(mib[0]) * pathlen);
957 mib[pathlen] = CTL_CREATE;
959 memcpy(&scn, tmpscn, sizeof(scn));
960 scn.sysctl_num = id;
961 strlcpy(scn.sysctl_name, name, sizeof(scn.sysctl_name));
962 oldlen = sizeof(oldscn);
963 r = sysctl(mib, pathlen + 1, &oldscn, &oldlen, &scn, sizeof(scn));
964 if (other_id >= 0) { /* conflict expected */
965 if (oldlen != sizeof(oldscn)) e(0);
966 if (r != -1) e(0);
967 if (errno != EEXIST) e(0);
968 if (oldscn.sysctl_num != other_id) e(0);
969 if (strcmp(oldscn.sysctl_name, other_name)) e(0);
970 return -1;
971 } else {
972 if (r != 0)
973 return r;
974 if (oldlen != sizeof(oldscn)) e(0);
975 return oldscn.sysctl_num;
980 * Destroy a node by identifier in the given named node directory. Return 0 on
981 * success. Return -1 on failure, with errno set.
983 static int
984 destroy_node(const int * path, unsigned int pathlen, int id)
986 struct sysctlnode scn;
987 int mib[CTL_MAXNAME];
989 assert(pathlen < CTL_MAXNAME);
990 memcpy(mib, path, sizeof(mib[0]) * pathlen);
991 mib[pathlen] = CTL_DESTROY;
993 memset(&scn, 0, sizeof(scn));
994 scn.sysctl_flags = SYSCTL_VERSION;
995 scn.sysctl_num = id;
997 return sysctl(mib, pathlen + 1, NULL, NULL, &scn, sizeof(scn));
1001 * Obtain the node data for one particular node in a node directory, by its
1002 * parent path and identifier. Return 0 on success, with the node details
1003 * stored in 'scn', or -1 on failure.
1005 static int
1006 query_node(const int * path, unsigned int pathlen, int id,
1007 struct sysctlnode * scn)
1009 struct sysctlnode scnset[32];
1010 size_t oldlen;
1011 unsigned int i;
1012 int r, mib[CTL_MAXNAME];
1014 assert(pathlen < CTL_MAXNAME);
1015 memcpy(mib, path, sizeof(mib[0]) * pathlen);
1016 mib[pathlen] = CTL_QUERY;
1018 oldlen = sizeof(scnset);
1019 if ((r = sysctl(mib, pathlen + 1, scnset, &oldlen, NULL, 0)) != 0 &&
1020 errno != ENOMEM) e(0);
1021 if (oldlen == 0 || oldlen % sizeof(scnset[0])) e(0);
1022 for (i = 0; i < oldlen / sizeof(scnset[0]); i++)
1023 if (scnset[i].sysctl_num == id)
1024 break;
1025 if (i == oldlen / sizeof(scnset[0])) {
1026 if (r != 0) e(0); /* if this triggers, make scnset[] bigger! */
1027 return -1;
1029 memcpy(scn, &scnset[i], sizeof(*scn));
1030 return 0;
1034 * Test unprivileged node creation.
1036 static void
1037 sub87c(void)
1039 struct sysctlnode scn;
1040 int mib[4];
1042 mib[0] = CTL_MINIX;
1043 mib[1] = MINIX_TEST;
1044 mib[2] = TEST_DYNAMIC;
1045 mib[3] = CTL_CREATE;
1047 memset(&scn, 0, sizeof(scn));
1048 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
1049 CTLFLAG_READONLY | CTLTYPE_INT;
1050 scn.sysctl_size = sizeof(int);
1051 scn.sysctl_num = CTL_CREATE;
1052 scn.sysctl_idata = 777;
1053 strlcpy(scn.sysctl_name, "nonroot", sizeof(scn.sysctl_name));
1054 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1055 if (errno != EPERM) e(0);
1057 mib[0] = CTL_CREATE;
1058 scn.sysctl_num = CTL_MINIX + 1;
1059 if (sysctl(mib, 1, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1060 if (errno != EPERM) e(0);
1064 * Test sysctl(2) node creation.
1066 static void
1067 test87c(void)
1069 static const uint32_t badflags[] = {
1070 SYSCTL_VERS_MASK, SYSCTL_TYPEMASK, CTLFLAG_PERMANENT,
1071 CTLFLAG_ROOT, CTLFLAG_ANYNUMBER, CTLFLAG_ALIAS, CTLFLAG_MMAP,
1072 CTLFLAG_OWNDESC
1074 static const size_t badintsizes[] = {
1075 0, 1, sizeof(int) - 1, sizeof(int) + 1, sizeof(int) * 2,
1076 sizeof(int) * 4, SSIZE_MAX, SIZE_MAX
1078 static const char *goodnames[] = {
1079 "_", "a", "test_name", "_____foo", "bar_0_1_2_3", "_2bornot2b",
1080 "abcdefghijklmnopqrstuvwxyz12345",
1081 "ABCDEFGHIJKLMNOPQRSTUVWXYZ67890",
1083 static const char *badnames[] = {
1084 "", "0", "test.name", "2bornot2b", "@a", "b[", "c`d", "{",
1085 "\n", "\xff", "dir/name", "foo:bar",
1086 "abcdefghijklmnopqrstuvwxyz123456"
1088 struct sysctlnode scn, pscn, oldscn, newscn, tmpscn, scnset[32];
1089 size_t oldlen, len;
1090 char buf[32], seen[5];
1091 bool b;
1092 u_quad_t q;
1093 int i, mib[CTL_MAXNAME], id[3];
1095 subtest = 2;
1098 * On the first run of this test, this call with actually destroy a
1099 * static node. On subsequent runs, it may clean up the most likely
1100 * leftover from a previous failed test.
1102 mib[0] = CTL_MINIX;
1103 mib[1] = MINIX_TEST;
1104 (void)destroy_node(mib, 2, TEST_DYNAMIC);
1106 /* Get child statistics about the parent node, for later comparison. */
1107 if (query_node(mib, 1, MINIX_TEST, &pscn) != 0) e(0);
1108 if (pscn.sysctl_clen == 0) e(0);
1109 if (pscn.sysctl_csize <= pscn.sysctl_clen) e(0);
1111 /* Start by testing if we can actually create a node at all. */
1112 mib[2] = CTL_CREATE;
1113 memset(&scn, 0, sizeof(scn));
1114 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
1115 CTLFLAG_READONLY | CTLTYPE_INT;
1116 scn.sysctl_size = sizeof(int);
1117 scn.sysctl_num = TEST_DYNAMIC;
1118 scn.sysctl_idata = 777;
1119 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
1120 oldlen = sizeof(newscn);
1121 if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1122 if (oldlen != sizeof(newscn)) e(0);
1124 memcpy(&tmpscn, &scn, sizeof(scn));
1126 if (newscn.sysctl_num != TEST_DYNAMIC) e(0);
1127 if (SYSCTL_TYPE(newscn.sysctl_flags) != CTLTYPE_INT) e(0);
1128 if (SYSCTL_FLAGS(newscn.sysctl_flags) !=
1129 (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE)) e(0);
1130 if (SYSCTL_VERS(newscn.sysctl_flags) != SYSCTL_VERSION) e(0);
1131 if (strcmp(newscn.sysctl_name, "dynamic")) e(0);
1132 if (newscn.sysctl_ver == 0) e(0);
1133 if (newscn.sysctl_size != sizeof(int)) e(0);
1134 if (newscn.sysctl_idata != 777) e(0);
1136 /* Can we also read its value? */
1137 mib[2] = TEST_DYNAMIC;
1138 i = 0;
1139 oldlen = sizeof(i);
1140 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1141 if (oldlen != sizeof(i)) e(0);
1142 if (i != 777) e(0);
1144 /* For now, we assume that basic node destruction works. */
1145 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1147 /* Try some variants of invalid new node data. */
1148 mib[2] = CTL_CREATE;
1149 memcpy(&scn, &tmpscn, sizeof(scn));
1150 if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
1151 if (errno != EINVAL) e(0);
1152 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn) - 1) != -1) e(0);
1153 if (errno != EINVAL) e(0);
1154 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn) + 1) != -1) e(0);
1155 if (errno != EINVAL) e(0);
1156 if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
1157 if (errno != EFAULT) e(0);
1159 /* Try with an invalid flags field. */
1160 scn.sysctl_flags =
1161 (scn.sysctl_flags & ~SYSCTL_VERS_MASK) | SYSCTL_VERS_0;
1162 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1163 if (errno != EINVAL) e(0);
1165 scn.sysctl_flags &= ~SYSCTL_TYPEMASK; /* type 0 does not exist */
1166 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1167 if (errno != EINVAL) e(0);
1169 for (i = 0; i < __arraycount(badflags); i++) {
1170 memcpy(&scn, &tmpscn, sizeof(scn));
1171 scn.sysctl_flags |= badflags[i];
1172 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1173 if (errno != EINVAL) e(i);
1176 /* Try successful creation (and destruction) once more. */
1177 memcpy(&scn, &tmpscn, sizeof(scn));
1178 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1180 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1182 /* Try a combination of most valid flags. */
1183 memcpy(&scn, &tmpscn, sizeof(scn));
1184 scn.sysctl_flags &= ~CTLFLAG_READONLY; /* noop */
1185 scn.sysctl_flags |= CTLFLAG_READWRITE | CTLFLAG_ANYWRITE |
1186 CTLFLAG_PRIVATE | CTLFLAG_HEX | CTLFLAG_HIDDEN | CTLFLAG_UNSIGNED;
1187 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1189 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1191 /* Try invalid integer sizes. We will get to other types in a bit. */
1192 for (i = 0; i < __arraycount(badintsizes); i++) {
1193 memcpy(&scn, &tmpscn, sizeof(scn));
1194 scn.sysctl_size = badintsizes[i];
1195 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1196 if (errno != EINVAL) e(i);
1200 * For the value, we can supply IMMEDIATE, OWNDATA, or neither. For
1201 * IMMEDIATE, the integer value is taken directly from sysctl_idata.
1202 * If OWNDATA is set, sysctl_data may be set, in which case the integer
1203 * value is copied in from there. If sysctl_data is NULL, the integer
1204 * is initalized to zero. If neither flag is set, sysctl_data must be
1205 * NULL, since we do not support kernel addresses, and the integer will
1206 * similarly be initialized to zero. If both flags are set, the call
1207 * fails with EINVAL.
1209 memcpy(&scn, &tmpscn, sizeof(scn));
1210 scn.sysctl_flags |= CTLFLAG_OWNDATA; /* both flags are now set */
1211 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1212 if (errno != EINVAL) e(0);
1214 scn.sysctl_flags &= ~(CTLFLAG_IMMEDIATE | CTLFLAG_OWNDATA);
1215 scn.sysctl_data = &i;
1216 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1217 if (errno != EINVAL) e(0);
1219 scn.sysctl_data = NULL;
1220 oldlen = sizeof(newscn);
1221 if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1222 if (oldlen != sizeof(newscn)) e(0);
1223 if (newscn.sysctl_flags & CTLFLAG_IMMEDIATE) e(0);
1224 if (!(newscn.sysctl_flags & CTLFLAG_OWNDATA)) e(0); /* auto-set */
1225 if (newscn.sysctl_idata != 0) e(0);
1227 mib[2] = TEST_DYNAMIC;
1228 oldlen = sizeof(i);
1229 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1230 if (oldlen != sizeof(i)) e(0);
1231 if (i != 0) e(0);
1233 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1235 mib[2] = CTL_CREATE;
1236 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1237 scn.sysctl_data = NULL;
1238 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1240 mib[2] = TEST_DYNAMIC;
1241 i = -1;
1242 oldlen = sizeof(i);
1243 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1244 if (oldlen != sizeof(i)) e(0);
1245 if (i != 0) e(0);
1247 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1249 mib[2] = CTL_CREATE;
1250 scn.sysctl_data = bad_ptr;
1251 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1252 if (errno != EFAULT) e(0);
1254 i = 999;
1255 scn.sysctl_data = (void *)&i;
1256 oldlen = sizeof(newscn);
1257 if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1258 if (oldlen != sizeof(newscn)) e(0);
1259 if ((newscn.sysctl_flags & (CTLFLAG_IMMEDIATE | CTLFLAG_OWNDATA)) !=
1260 CTLFLAG_OWNDATA) e(0);
1261 if (newscn.sysctl_idata != 0) e(0);
1263 mib[2] = TEST_DYNAMIC;
1264 oldlen = sizeof(i);
1265 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1266 if (oldlen != sizeof(i)) e(0);
1267 if (i != 999) e(0);
1269 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1271 /* The user may never supply a function pointer or a parent. */
1272 mib[2] = CTL_CREATE;
1273 memcpy(&scn, &tmpscn, sizeof(scn));
1274 scn.sysctl_func = (sysctlfn)test87c;
1275 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1276 if (errno != EINVAL) e(0);
1278 memcpy(&scn, &tmpscn, sizeof(scn));
1279 scn.sysctl_parent = &scn;
1280 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1281 if (errno != EINVAL) e(0);
1283 /* Test some good and bad node names. */
1284 for (i = 0; i < __arraycount(goodnames); i++) {
1285 memcpy(&scn, &tmpscn, sizeof(scn));
1286 len = strlen(goodnames[i]);
1287 memcpy(scn.sysctl_name, goodnames[i], len);
1288 memset(&scn.sysctl_name[len], 0, SYSCTL_NAMELEN - len);
1289 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(i);
1291 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(i);
1294 for (i = 0; i < __arraycount(badnames); i++) {
1295 memcpy(&scn, &tmpscn, sizeof(scn));
1296 len = strlen(badnames[i]);
1297 memcpy(scn.sysctl_name, badnames[i], len);
1298 memset(&scn.sysctl_name[len], 0, SYSCTL_NAMELEN - len);
1299 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1300 if (errno != EINVAL) e(i);
1304 * Check for ID and name conflicts with existing nodes, starting with
1305 * the basics.
1307 memcpy(&scn, &tmpscn, sizeof(scn));
1308 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1310 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1311 if (errno != EEXIST) e(0);
1313 oldlen = sizeof(oldscn);
1314 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1315 if (errno != EEXIST) e(0);
1316 if (oldlen != sizeof(oldscn)) e(0);
1317 if (oldscn.sysctl_ver == 0) e(0);
1318 oldscn.sysctl_ver = 0;
1319 if (memcmp(&oldscn, &tmpscn, sizeof(oldscn))) e(0);
1321 oldlen = sizeof(oldscn) - 1;
1322 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1323 if (errno != EEXIST) e(0); /* ..we should not get ENOMEM now */
1324 if (oldlen != sizeof(oldscn)) e(0);
1326 oldlen = sizeof(oldscn);
1327 if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1328 if (errno != EEXIST) e(0); /* ..we should not get EFAULT now */
1329 if (oldlen != 0) e(0); /* this is arguably an implementation detail */
1331 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1333 /* Test ID and name conflicts against static nodes. */
1334 if (create_node(mib, 2, &tmpscn, TEST_INT, "dynamic", TEST_INT,
1335 "int") != -1) e(0);
1336 if (create_node(mib, 2, &tmpscn, TEST_SECRET, "dynamic", TEST_SECRET,
1337 "secret") != -1) e(0);
1338 if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "quad", TEST_QUAD,
1339 "quad") != -1) e(0);
1341 if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
1342 NULL) != TEST_DYNAMIC) e(0);
1343 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1345 /* Test unique ID generation and LL back insertion. */
1346 if ((id[0] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id0", -1,
1347 NULL)) == -1) e(0);
1348 if ((id[1] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id1", -1,
1349 NULL)) == -1) e(0);
1350 if ((id[2] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id2", -1,
1351 NULL)) == -1) e(0);
1352 if (id[0] < CREATE_BASE || id[1] < CREATE_BASE || id[2] < CREATE_BASE)
1353 e(0);
1354 if (id[0] == id[1] || id[1] == id[2] || id[0] == id[2]) e(0);
1356 if (destroy_node(mib, 2, id[1]) != 0) e(0);
1358 /* Test ID and name conflicts against dynamic nodes. */
1359 if (create_node(mib, 2, &tmpscn, id[0], "id1", id[0],
1360 "id0") != -1) e(0);
1361 if (create_node(mib, 2, &tmpscn, id[2], "id1", id[2],
1362 "id2") != -1) e(0);
1363 if (create_node(mib, 2, &tmpscn, id[1], "id0", id[0],
1364 "id0") != -1) e(0);
1365 if (create_node(mib, 2, &tmpscn, id[1], "id2", id[2],
1366 "id2") != -1) e(0);
1368 /* Test name conflicts before and after LL insertion point. */
1369 if (create_node(mib, 2, &tmpscn, CTL_CREATE, "id0", id[0],
1370 "id0") != -1) e(0);
1371 if (create_node(mib, 2, &tmpscn, CTL_CREATE, "id2", id[2],
1372 "id2") != -1) e(0);
1374 /* Test recreation by ID and LL middle insertion. */
1375 if (create_node(mib, 2, &tmpscn, id[1], "id1", -1, NULL) == -1) e(0);
1376 if (destroy_node(mib, 2, id[1]) != 0) e(0);
1378 /* Test dynamic recreation and more LL middle insertion. */
1379 if ((id[1] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id1", -1,
1380 NULL)) == -1) e(0);
1381 if (id[1] < CREATE_BASE) e(0);
1382 if (id[1] == id[0] || id[1] == id[2]) e(0);
1384 /* Test LL front insertion. */
1385 if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
1386 NULL) == -1) e(0);
1388 /* Ensure that all dynamic nodes show up in a query. */
1389 mib[2] = CTL_QUERY;
1390 oldlen = sizeof(scnset);
1391 memset(seen, 0, sizeof(seen));
1392 memset(scnset, 0, sizeof(scnset));
1393 if (sysctl(mib, 3, scnset, &oldlen, NULL, 0) != 0) e(0);
1394 if (oldlen % sizeof(scn)) e(0);
1395 for (i = 0; (unsigned int)i < oldlen / sizeof(scn); i++) {
1396 if (scnset[i].sysctl_num == TEST_INT) {
1397 if (strcmp(scnset[i].sysctl_name, "int")) e(0);
1398 seen[0]++;
1399 } else if (scnset[i].sysctl_num == TEST_DYNAMIC) {
1400 if (strcmp(scnset[i].sysctl_name, "dynamic")) e(0);
1401 seen[1]++;
1402 } else if (scnset[i].sysctl_num == id[0]) {
1403 if (strcmp(scnset[i].sysctl_name, "id0")) e(0);
1404 seen[2]++;
1405 } else if (scnset[i].sysctl_num == id[1]) {
1406 if (strcmp(scnset[i].sysctl_name, "id1")) e(0);
1407 seen[3]++;
1408 } else if (scnset[i].sysctl_num == id[2]) {
1409 if (strcmp(scnset[i].sysctl_name, "id2")) e(0);
1410 seen[4]++;
1413 for (i = 0; i < 5; i++)
1414 if (seen[i] != 1) e(i);
1416 /* Compare the parent's statistics with those obtained earlier. */
1417 if (query_node(mib, 1, MINIX_TEST, &scn) != 0) e(0);
1418 if (scn.sysctl_clen != pscn.sysctl_clen + 4) e(0);
1419 if (scn.sysctl_csize != pscn.sysctl_csize + 4) e(0);
1421 /* Clean up. */
1422 if (destroy_node(mib, 2, id[0]) != 0) e(0);
1423 if (destroy_node(mib, 2, id[1]) != 0) e(0);
1424 if (destroy_node(mib, 2, id[2]) != 0) e(0);
1425 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1427 /* Copy-out errors should not result in the node not being created. */
1428 mib[2] = CTL_CREATE;
1429 memcpy(&scn, &tmpscn, sizeof(scn));
1430 oldlen = sizeof(newscn) - 1;
1431 if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1432 if (errno != ENOMEM) e(0);
1433 if (oldlen != sizeof(newscn)) e(0);
1435 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1437 oldlen = sizeof(newscn);
1438 if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1439 if (errno != EFAULT) e(0);
1441 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1443 oldlen = sizeof(newscn) + 1;
1444 if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1445 if (oldlen != sizeof(newscn)) e(0);
1447 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1450 * Now that we are done with the integer template, try other data
1451 * types, starting with booleans. A big part of these tests is that
1452 * the creation results in a usable node, regardless of the way its
1453 * contents were initialized.
1455 tmpscn.sysctl_flags =
1456 SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_BOOL;
1457 tmpscn.sysctl_size = sizeof(b);
1458 tmpscn.sysctl_data = NULL;
1460 mib[2] = CTL_CREATE;
1461 memcpy(&scn, &tmpscn, sizeof(scn));
1462 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1464 mib[2] = TEST_DYNAMIC;
1465 oldlen = sizeof(b);
1466 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1467 if (oldlen != sizeof(b)) e(0);
1468 if (b != false) e(0);
1470 b = true;
1471 if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
1473 oldlen = sizeof(b);
1474 b = false;
1475 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1476 if (oldlen != sizeof(b)) e(0);
1477 if (b != true) e(0);
1479 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1481 mib[2] = CTL_CREATE;
1482 memcpy(&scn, &tmpscn, sizeof(scn));
1483 scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1484 scn.sysctl_bdata = true;
1485 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1487 mib[2] = TEST_DYNAMIC;
1488 oldlen = sizeof(b);
1489 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1490 if (oldlen != sizeof(b)) e(0);
1491 if (b != true) e(0);
1493 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1495 mib[2] = CTL_CREATE;
1496 scn.sysctl_bdata = false;
1497 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1499 mib[2] = TEST_DYNAMIC;
1500 oldlen = sizeof(b);
1501 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1502 if (oldlen != sizeof(b)) e(0);
1503 if (b != false) e(0);
1505 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1507 mib[2] = CTL_CREATE;
1508 memcpy(&scn, &tmpscn, sizeof(scn));
1509 scn.sysctl_data = &b;
1510 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1511 if (errno != EINVAL) e(0);
1513 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1514 scn.sysctl_size++;
1515 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1516 if (errno != EINVAL) e(0);
1518 scn.sysctl_size--;
1519 scn.sysctl_data = bad_ptr;
1520 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1521 if (errno != EFAULT) e(0);
1523 b = true;
1524 scn.sysctl_data = &b;
1525 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1527 mib[2] = TEST_DYNAMIC;
1528 oldlen = sizeof(b);
1529 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1530 if (oldlen != sizeof(b)) e(0);
1531 if (b != true) e(0);
1533 b = false;
1534 oldlen = sizeof(b);
1535 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1536 if (oldlen != sizeof(b)) e(0);
1537 if (b != true) e(0);
1539 b = false;
1540 if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
1542 oldlen = sizeof(b);
1543 b = true;
1544 if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1545 if (oldlen != sizeof(b)) e(0);
1546 if (b != false) e(0);
1548 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1550 /* Test quads next. */
1551 tmpscn.sysctl_flags =
1552 SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_QUAD;
1553 tmpscn.sysctl_size = sizeof(q);
1555 mib[2] = CTL_CREATE;
1556 memcpy(&scn, &tmpscn, sizeof(scn));
1557 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1559 mib[2] = TEST_DYNAMIC;
1560 oldlen = sizeof(q);
1561 if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1562 if (oldlen != sizeof(q)) e(0);
1563 if (q != 0) e(0);
1565 q = ~0ULL;
1566 if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
1568 oldlen = sizeof(q);
1569 q = 0;
1570 if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1571 if (oldlen != sizeof(q)) e(0);
1572 if (q != ~0ULL) e(0);
1574 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1576 mib[2] = CTL_CREATE;
1577 memcpy(&scn, &tmpscn, sizeof(scn));
1578 scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1579 scn.sysctl_qdata = 1ULL << 48;
1580 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1582 mib[2] = TEST_DYNAMIC;
1583 oldlen = sizeof(q);
1584 if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1585 if (oldlen != sizeof(q)) e(0);
1586 if (q != (1ULL << 48)) e(0);
1588 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1590 mib[2] = CTL_CREATE;
1591 memcpy(&scn, &tmpscn, sizeof(scn));
1592 scn.sysctl_data = &q;
1593 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1594 if (errno != EINVAL) e(0);
1596 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1597 scn.sysctl_size <<= 1;
1598 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1599 if (errno != EINVAL) e(0);
1601 scn.sysctl_size >>= 1;
1602 scn.sysctl_data = bad_ptr;
1603 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1604 if (errno != EFAULT) e(0);
1606 q = 123ULL << 31;
1607 scn.sysctl_data = &q;
1608 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1610 mib[2] = TEST_DYNAMIC;
1611 oldlen = sizeof(q);
1612 if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1613 if (oldlen != sizeof(q)) e(0);
1614 if (q != (123ULL << 31)) e(0);
1616 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1618 /* Test strings. */
1619 tmpscn.sysctl_flags =
1620 SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_STRING;
1621 tmpscn.sysctl_size = 7;
1623 mib[2] = CTL_CREATE;
1624 memcpy(&scn, &tmpscn, sizeof(scn));
1625 scn.sysctl_data = buf;
1626 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1627 if (errno != EINVAL) e(0);
1629 scn.sysctl_data = NULL;
1630 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1632 mib[2] = TEST_DYNAMIC;
1633 memset(buf, 0x7f, sizeof(buf));
1634 oldlen = sizeof(buf);
1635 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1636 if (oldlen != 1) e(0);
1637 if (buf[0] != '\0') e(0);
1638 if (buf[1] != 0x7f) e(0);
1640 if (sysctl(mib, 3, NULL, NULL, "woobie!", 8) != -1) e(0);
1641 if (errno != EINVAL) e(0);
1642 if (sysctl(mib, 3, NULL, NULL, "woobie!", 7) != -1) e(0);
1643 if (errno != EINVAL) e(0);
1644 if (sysctl(mib, 3, NULL, NULL, "woobie", 7) != 0) e(0);
1646 memset(buf, 0x7f, sizeof(buf));
1647 oldlen = sizeof(buf);
1648 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1649 if (oldlen != 7) e(0);
1650 if (strcmp(buf, "woobie")) e(0);
1651 if (buf[7] != 0x7f) e(0);
1653 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1655 mib[2] = CTL_CREATE;
1656 memcpy(&scn, &tmpscn, sizeof(scn));
1657 scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1658 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1659 if (errno != EINVAL) e(0);
1661 memcpy(&scn, &tmpscn, sizeof(scn));
1662 scn.sysctl_size = 0;
1663 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1664 if (errno != EINVAL) e(0);
1666 scn.sysctl_data = buf;
1667 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1668 if (errno != EINVAL) e(0);
1670 memcpy(&scn, &tmpscn, sizeof(scn));
1671 scn.sysctl_size = (size_t)SSIZE_MAX + 1;
1672 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1673 if (errno != EINVAL) e(0);
1675 memcpy(&scn, &tmpscn, sizeof(scn));
1676 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1677 scn.sysctl_data = bad_ptr;
1678 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1679 if (errno != EFAULT) e(0);
1681 memcpy(&scn, &tmpscn, sizeof(scn));
1682 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1683 scn.sysctl_data = "abc123?";
1684 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1685 if (errno != EINVAL) e(0);
1687 scn.sysctl_data = "abc123";
1688 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1690 mib[2] = TEST_DYNAMIC;
1691 memset(buf, 0x7f, sizeof(buf));
1692 oldlen = sizeof(buf);
1693 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1694 if (oldlen != 7) e(0);
1695 if (strcmp(buf, "abc123")) e(0);
1696 if (buf[7] != 0x7f) e(0);
1698 if (sysctl(mib, 3, NULL, NULL, "", 1) != 0) e(0);
1700 memset(buf, 0x7f, sizeof(buf));
1701 oldlen = sizeof(buf);
1702 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1703 if (oldlen != 1) e(0);
1704 if (buf[0] != '\0') e(0);
1705 if (buf[1] != 0x7f) e(0);
1707 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1709 mib[2] = CTL_CREATE;
1710 scn.sysctl_data = "";
1711 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1713 mib[2] = TEST_DYNAMIC;
1714 memset(buf, 0x7f, sizeof(buf));
1715 oldlen = sizeof(buf);
1716 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1717 if (oldlen != 1) e(0);
1718 if (buf[0] != '\0') e(0);
1719 if (buf[7] != 0x7f) e(0);
1721 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1724 * For strings, a zero node size means that the string length
1725 * determines the buffer size.
1727 mib[2] = CTL_CREATE;
1728 scn.sysctl_size = 0;
1729 scn.sysctl_data = NULL;
1730 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1731 if (errno != EINVAL) e(0);
1733 scn.sysctl_data = bad_ptr;
1734 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1735 if (errno != EFAULT) e(0);
1737 scn.sysctl_data = "This is a string initializer."; /* size 29+1 */
1738 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1740 mib[2] = TEST_DYNAMIC;
1741 memset(buf, 0x7f, sizeof(buf));
1742 oldlen = sizeof(buf);
1743 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1744 if (oldlen != strlen(scn.sysctl_data) + 1) e(0);
1745 if (buf[oldlen - 1] != '\0') e(0);
1746 if (buf[oldlen] != 0x7f) e(0);
1748 if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
1749 if (newscn.sysctl_size != strlen(scn.sysctl_data) + 1) e(0);
1751 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1753 /* Test structs. */
1754 tmpscn.sysctl_flags =
1755 SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_STRUCT;
1756 tmpscn.sysctl_size = 21;
1758 mib[2] = CTL_CREATE;
1759 memcpy(&scn, &tmpscn, sizeof(scn));
1760 scn.sysctl_data = buf;
1761 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1762 if (errno != EINVAL) e(0);
1764 scn.sysctl_data = NULL;
1765 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1767 mib[2] = TEST_DYNAMIC;
1768 memset(buf, 0x7f, sizeof(buf));
1769 oldlen = sizeof(buf);
1770 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1771 if (oldlen != 21) e(0);
1772 for (i = 0; i < 21; i++)
1773 if (buf[i] != 0) e(i);
1774 if (buf[i] != 0x7f) e(0);
1776 memset(buf, 'x', 32);
1777 if (sysctl(mib, 3, NULL, NULL, buf, 20) != -1) e(0);
1778 if (errno != EINVAL) e(0);
1779 if (sysctl(mib, 3, NULL, NULL, buf, 22) != -1) e(0);
1780 if (errno != EINVAL) e(0);
1781 if (sysctl(mib, 3, NULL, NULL, buf, 21) != 0) e(0);
1783 memset(buf, 0x7f, sizeof(buf));
1784 oldlen = sizeof(buf);
1785 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1786 if (oldlen != 21) e(0);
1787 for (i = 0; i < 21; i++)
1788 if (buf[i] != 'x') e(i);
1789 if (buf[i] != 0x7f) e(0);
1791 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1793 mib[2] = CTL_CREATE;
1794 memcpy(&scn, &tmpscn, sizeof(scn));
1795 scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1796 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1797 if (errno != EINVAL) e(0);
1799 memcpy(&scn, &tmpscn, sizeof(scn));
1800 scn.sysctl_size = 0;
1801 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1802 if (errno != EINVAL) e(0);
1804 scn.sysctl_data = buf;
1805 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1806 if (errno != EINVAL) e(0);
1808 memcpy(&scn, &tmpscn, sizeof(scn));
1809 scn.sysctl_size = (size_t)SSIZE_MAX + 1;
1810 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1811 if (errno != EINVAL) e(0);
1813 memcpy(&scn, &tmpscn, sizeof(scn));
1814 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1815 scn.sysctl_data = bad_ptr;
1816 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1817 if (errno != EFAULT) e(0);
1819 memcpy(&scn, &tmpscn, sizeof(scn));
1820 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1821 for (i = 0; i < sizeof(buf); i++)
1822 buf[i] = i;
1823 scn.sysctl_data = buf;
1824 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1826 mib[2] = TEST_DYNAMIC;
1827 memset(buf, 0x7f, sizeof(buf));
1828 oldlen = sizeof(buf);
1829 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1830 if (oldlen != 21) e(0);
1831 for (i = 0; i < 21; i++)
1832 if (buf[i] != i) e(i);
1833 if (buf[i] != 0x7f) e(0);
1835 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1837 /* Finally, test node-type nodes. */
1838 tmpscn.sysctl_flags =
1839 SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
1840 tmpscn.sysctl_size = 0;
1842 mib[2] = CTL_CREATE;
1843 memcpy(&scn, &tmpscn, sizeof(scn));
1844 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1846 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1848 scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1849 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1850 if (errno != EINVAL) e(0);
1852 memcpy(&scn, &tmpscn, sizeof(scn));
1853 scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1854 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1855 if (errno != EINVAL) e(0);
1857 scn.sysctl_size = sizeof(scn);
1858 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1859 if (errno != EINVAL) e(0);
1861 scn.sysctl_flags &= ~CTLFLAG_IMMEDIATE;
1862 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1863 if (errno != EINVAL) e(0);
1865 scn.sysctl_flags |= CTLFLAG_OWNDATA;
1866 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1867 if (errno != EINVAL) e(0);
1869 memcpy(&scn, &tmpscn, sizeof(scn));
1870 scn.sysctl_csize = 8;
1871 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1872 if (errno != EINVAL) e(0);
1874 memcpy(&scn, &tmpscn, sizeof(scn));
1875 scn.sysctl_clen = 1;
1876 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1877 if (errno != EINVAL) e(0);
1879 memcpy(&scn, &tmpscn, sizeof(scn));
1880 scn.sysctl_child = &scn;
1881 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1882 if (errno != EINVAL) e(0);
1884 memcpy(&scn, &tmpscn, sizeof(scn));
1885 scn.sysctl_parent = &scn;
1886 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1887 if (errno != EINVAL) e(0);
1889 memcpy(&scn, &tmpscn, sizeof(scn));
1890 scn.sysctl_func = (sysctlfn)test87c;
1891 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1892 if (errno != EINVAL) e(0);
1894 memcpy(&scn, &tmpscn, sizeof(scn));
1895 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1897 if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1898 if (scn.sysctl_csize != 0) e(0);
1899 if (scn.sysctl_clen != 0) e(0);
1901 mib[2] = TEST_DYNAMIC;
1903 for (i = 3; i < CTL_MAXNAME; i++) {
1904 memcpy(&scn, &tmpscn, sizeof(scn));
1905 if (i % 2)
1906 scn.sysctl_num = i - 3;
1907 else
1908 scn.sysctl_num = CTL_CREATE;
1910 * Test both names with different length (depthN vs depthNN)
1911 * and cross-directory name duplicates (depth7.depth7).
1913 snprintf(scn.sysctl_name, sizeof(scn.sysctl_name), "depth%u",
1914 7 + i / 2);
1915 mib[i] = CTL_CREATE;
1917 oldlen = sizeof(newscn);
1918 if (sysctl(mib, i + 1, &newscn, &oldlen, &scn,
1919 sizeof(scn)) != 0) e(0);
1920 mib[i] = newscn.sysctl_num;
1923 id[0] = mib[i - 1];
1924 mib[i - 1] = CTL_CREATE;
1925 memset(&scn, 0, sizeof(scn));
1926 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READONLY |
1927 CTLFLAG_OWNDATA | CTLTYPE_STRING;
1928 scn.sysctl_num = id[0] + 1;
1929 scn.sysctl_data = "bar";
1930 scn.sysctl_size = strlen(scn.sysctl_data) + 1;
1931 strlcpy(scn.sysctl_name, "foo", sizeof(scn.sysctl_name));
1932 if (sysctl(mib, i, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1933 mib[i - 1] = id[0] + 1;
1935 oldlen = sizeof(buf);
1936 if (sysctl(mib, i, buf, &oldlen, NULL, 0) != 0) e(0);
1937 if (oldlen != strlen(scn.sysctl_data) + 1) e(0);
1938 if (strcmp(buf, scn.sysctl_data)) e(0);
1940 if (query_node(mib, i - 2, mib[i - 2], &scn) != 0) e(0);
1941 if (scn.sysctl_csize != 2) e(0);
1942 if (scn.sysctl_clen != 2) e(0);
1944 if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1945 if (scn.sysctl_csize != 1) e(0);
1946 if (scn.sysctl_clen != 1) e(0);
1948 if (destroy_node(mib, i - 1, mib[i - 1]) != 0) e(0);
1949 mib[i - 1]--;
1951 for (i--; i > 2; i--)
1952 if (destroy_node(mib, i, mib[i]) != 0) e(0);
1954 if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1955 if (scn.sysctl_csize != 0) e(0);
1956 if (scn.sysctl_clen != 0) e(0);
1958 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1961 * Finally, ensure that unprivileged processes cannot create nodes,
1962 * even in the most friendly place possible.
1964 mib[2] = CTL_CREATE;
1965 memcpy(&scn, &tmpscn, sizeof(scn));
1966 scn.sysctl_flags |= CTLFLAG_ANYWRITE;
1967 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1969 (void)test_nonroot(sub87c);
1971 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1974 * Now that we are done, compare the parent's statistics with those
1975 * obtained earlier once more. There must be no differences.
1977 if (query_node(mib, 1, MINIX_TEST, &scn) != 0) e(0);
1978 if (scn.sysctl_clen != pscn.sysctl_clen) e(0);
1979 if (scn.sysctl_csize != pscn.sysctl_csize) e(0);
1981 /* Do some more path-related error code tests unrelated to the rest. */
1982 memcpy(&scn, &tmpscn, sizeof(scn));
1983 mib[1] = INT_MAX;
1984 if (create_node(mib, 2, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1985 if (errno != ENOENT) e(0);
1987 mib[1] = MINIX_TEST;
1988 mib[2] = TEST_INT;
1989 if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1990 if (errno != ENOTDIR) e(0);
1992 mib[2] = TEST_BOOL;
1993 if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1994 if (errno != ENOTDIR) e(0);
1996 mib[2] = CTL_CREATE;
1997 if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1998 if (errno != EINVAL) e(0);
2000 /* Finally, try to create a node in a read-only directory node. */
2001 mib[2] = TEST_SECRET;
2002 if (create_node(mib, 3, &scn, -1, "d", -1, NULL) != -1) e(0);
2003 if (errno != EPERM) e(0);
2007 * Test unprivileged node destruction.
2009 static void
2010 sub87d(void)
2012 struct sysctlnode scn;
2013 int mib[3];
2015 mib[0] = CTL_MINIX;
2016 mib[1] = MINIX_TEST;
2017 mib[2] = CTL_DESTROY;
2019 memset(&scn, 0, sizeof(scn));
2020 scn.sysctl_flags = SYSCTL_VERSION;
2021 scn.sysctl_num = TEST_ANYWRITE;
2023 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2024 if (errno != EPERM) e(0);
2026 mib[0] = CTL_DESTROY;
2027 scn.sysctl_num = CTL_MINIX;
2028 if (sysctl(mib, 1, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2029 if (errno != EPERM) e(0);
2033 * Test sysctl(2) node destruction.
2035 static void
2036 test87d(void)
2038 struct sysctlnode scn, oldscn, newscn, tmpscn;
2039 size_t oldlen;
2040 char buf[16];
2041 int i, r, mib[4], id[15];
2043 subtest = 3;
2045 mib[0] = CTL_MINIX;
2046 mib[1] = MINIX_TEST;
2047 (void)destroy_node(mib, 2, TEST_DYNAMIC);
2049 /* Start with the path-related error code tests this time. */
2050 mib[1] = INT_MAX;
2051 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2052 if (errno != ENOENT) e(0);
2054 mib[1] = MINIX_TEST;
2055 mib[2] = TEST_INT;
2056 if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2057 if (errno != ENOTDIR) e(0);
2059 mib[2] = TEST_BOOL;
2060 if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2061 if (errno != ENOTDIR) e(0);
2063 mib[2] = CTL_DESTROY;
2064 if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2065 if (errno != EINVAL) e(0);
2067 /* Actual API tests. */
2068 mib[1] = MINIX_TEST;
2069 mib[2] = CTL_CREATE;
2070 memset(&scn, 0, sizeof(scn));
2071 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2072 CTLFLAG_READONLY | CTLTYPE_INT;
2073 scn.sysctl_size = sizeof(int);
2074 scn.sysctl_num = TEST_DYNAMIC;
2075 scn.sysctl_idata = 31415926;
2076 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2077 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2079 memcpy(&tmpscn, &scn, sizeof(scn));
2081 mib[2] = CTL_DESTROY;
2082 if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
2083 if (errno != EINVAL) e(0);
2085 if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
2086 if (errno != EFAULT) e(0);
2088 memset(&scn, 0, sizeof(scn));
2089 scn.sysctl_flags = SYSCTL_VERS_0;
2090 scn.sysctl_num = TEST_DYNAMIC;
2091 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2092 if (errno != EINVAL) e(0);
2094 scn.sysctl_flags = SYSCTL_VERSION;
2095 scn.sysctl_num = INT_MAX; /* anything not valid */
2096 oldlen = sizeof(scn);
2097 if (sysctl(mib, 3, NULL, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2098 if (errno != ENOENT) e(0);
2099 if (oldlen != 0) e(0);
2101 scn.sysctl_num = TEST_PERM;
2102 oldlen = sizeof(scn);
2103 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2104 if (errno != EPERM) e(0);
2105 if (oldlen != 0) e(0);
2107 scn.sysctl_num = TEST_SECRET;
2108 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2109 if (errno != ENOTEMPTY) e(0);
2111 scn.sysctl_num = -1;
2112 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2113 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2114 if (errno != ENOENT) e(0);
2116 scn.sysctl_num = TEST_DYNAMIC;
2117 strlcpy(scn.sysctl_name, "dynami", sizeof(scn.sysctl_name));
2118 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2119 if (errno != EINVAL) e(0);
2121 strlcpy(scn.sysctl_name, "dynamic2", sizeof(scn.sysctl_name));
2122 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2123 if (errno != EINVAL) e(0);
2125 memset(scn.sysctl_name, 'd', sizeof(scn.sysctl_name));
2126 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2127 if (errno != EINVAL) e(0);
2129 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2130 oldlen = sizeof(oldscn);
2131 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
2132 if (oldlen != sizeof(oldscn)) e(0);
2133 if (oldscn.sysctl_ver == 0) e(0);
2134 oldscn.sysctl_ver = 0;
2135 if (memcmp(&oldscn, &tmpscn, sizeof(oldscn))) e(0);
2137 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2138 if (errno != ENOENT) e(0);
2141 * We already tested destruction of one static node, by destroying
2142 * TEST_DYNAMIC on the first run. We now do a second deletion of a
2143 * static node, TEST_DESTROY2, to test proper adjustment of parent
2144 * stats. We do a third static node deletion (on TEST_DESTROY1) later,
2145 * to see that static nodes with dynamic descriptions can be freed.
2147 if (query_node(mib, 1, MINIX_TEST, &oldscn) != 0) e(0);
2149 memset(&scn, 0, sizeof(scn));
2150 scn.sysctl_flags = SYSCTL_VERSION;
2151 scn.sysctl_num = TEST_DESTROY2;
2152 r = sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn));
2153 if (r != 0 && r != -1) e(0);
2154 if (r == -1 && errno != ENOENT) e(0);
2156 if (query_node(mib, 1, MINIX_TEST, &newscn) != 0) e(0);
2158 if (newscn.sysctl_csize != oldscn.sysctl_csize) e(0);
2159 if (newscn.sysctl_clen != oldscn.sysctl_clen - !r) e(0);
2161 /* Try to destroy a (static) node in a read-only directory node. */
2162 mib[2] = TEST_SECRET;
2163 if (destroy_node(mib, 3, SECRET_VALUE) != -1) e(0);
2164 if (errno != EPERM) e(0);
2167 * Errors during data copy-out of the destroyed node should not undo
2168 * its destruction.
2170 mib[2] = CTL_CREATE;
2171 memcpy(&scn, &tmpscn, sizeof(scn));
2172 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2174 mib[2] = TEST_DYNAMIC;
2175 i = 0;
2176 oldlen = sizeof(i);
2177 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
2178 if (oldlen != sizeof(i)) e(0);
2179 if (i != 31415926) e(0);
2181 mib[2] = CTL_DESTROY;
2182 oldlen = sizeof(scn);
2183 if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2184 if (errno != EFAULT) e(0);
2186 mib[2] = TEST_DYNAMIC;
2187 i = 0;
2188 oldlen = sizeof(i);
2189 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
2190 if (errno != ENOENT) e(0);
2191 if (oldlen != 0) e(0);
2192 if (i != 0) e(0);
2194 mib[2] = CTL_CREATE;
2195 memcpy(&scn, &tmpscn, sizeof(scn));
2196 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2198 mib[2] = CTL_DESTROY;
2199 oldlen = sizeof(scn) - 1;
2200 if (sysctl(mib, 3, &scn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2201 if (errno != ENOMEM) e(0);
2203 mib[2] = TEST_DYNAMIC;
2204 oldlen = sizeof(i);
2205 if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
2206 if (errno != ENOENT) e(0);
2209 * Now create and destroy a whole bunch of nodes in a subtree, mostly
2210 * test linked list manipulation, but also to ensure that a nonempty
2211 * tree node cannot be destroyed.
2213 memset(&scn, 0, sizeof(scn));
2214 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
2215 if (create_node(mib, 2, &scn, TEST_DYNAMIC, "dynamic", -1, NULL) == -1)
2216 e(0);
2218 for (i = 0; i < 15; i++) {
2219 snprintf(buf, sizeof(buf), "node%d", i);
2220 if ((id[i] = create_node(mib, 3, &scn, -1, buf, -1,
2221 NULL)) == -1) e(i);
2223 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(i);
2224 if (errno != ENOTEMPTY) e(i);
2227 for (i = 0; i < 15; i += 2)
2228 if (destroy_node(mib, 3, id[i]) != 0) e(i);
2230 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2231 if (errno != ENOTEMPTY) e(0);
2233 for (i = 0; i < 15; i += 2) {
2234 snprintf(buf, sizeof(buf), "node%d", i);
2235 if ((id[i] = create_node(mib, 3, &scn, -1, buf, -1,
2236 NULL)) == -1) e(i);
2239 for (i = 0; i < 3; i++)
2240 if (destroy_node(mib, 3, id[i]) != 0) e(i);
2242 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2243 if (errno != ENOTEMPTY) e(0);
2245 for (i = 12; i < 15; i++)
2246 if (destroy_node(mib, 3, id[i]) != 0) e(i);
2248 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2249 if (errno != ENOTEMPTY) e(0);
2251 for (i = 6; i < 9; i++)
2252 if (destroy_node(mib, 3, id[i]) != 0) e(i);
2254 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2255 if (errno != ENOTEMPTY) e(0);
2257 for (i = 3; i < 6; i++)
2258 if (destroy_node(mib, 3, id[i]) != 0) e(i);
2260 if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2261 if (errno != ENOTEMPTY) e(0);
2263 for (i = 9; i < 12; i++)
2264 if (destroy_node(mib, 3, id[i]) != 0) e(i);
2266 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2268 /* Finally, ensure that unprivileged users cannot destroy nodes. */
2269 (void)test_nonroot(sub87d);
2273 * Get or a set the description for a particular node. Compare the results
2274 * with the given description. Return 0 on success, or -1 on failure with
2275 * errno set.
2277 static int
2278 describe_node(const int * path, unsigned int pathlen, int id,
2279 const char * desc, int set)
2281 char buf[256], *p;
2282 struct sysctlnode scn;
2283 struct sysctldesc *scd;
2284 size_t oldlen;
2285 int mib[CTL_MAXNAME];
2287 if (pathlen >= CTL_MAXNAME) e(0);
2288 memcpy(mib, path, sizeof(mib[0]) * pathlen);
2289 mib[pathlen] = CTL_DESCRIBE;
2291 memset(&scn, 0, sizeof(scn));
2292 memset(buf, 0, sizeof(buf));
2293 oldlen = sizeof(buf);
2294 scn.sysctl_flags = SYSCTL_VERSION;
2295 scn.sysctl_num = id;
2296 if (set)
2297 scn.sysctl_desc = desc;
2298 if (sysctl(mib, pathlen + 1, buf, &oldlen, &scn, sizeof(scn)) != 0)
2299 return -1;
2301 scd = (struct sysctldesc *)buf;
2302 if (scd->descr_num != id) e(0);
2303 if (scd->descr_ver == 0) e(0);
2304 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2305 if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2306 if (strcmp(scd->descr_str, desc)) e(0);
2307 if (oldlen != (size_t)((char *)NEXT_DESCR(scd) - buf)) e(0);
2308 for (p = scd->descr_str + scd->descr_len; p != &buf[oldlen]; p++)
2309 if (*p != '\0') e(0);
2310 return 0;
2314 * Test getting descriptions from an unprivileged process.
2316 static void
2317 sub87e(void)
2319 static char buf[2048];
2320 char seen[32], *p;
2321 struct sysctldesc *scd, *endscd;
2322 size_t oldlen;
2323 int mib[4];
2325 mib[0] = CTL_MINIX;
2326 mib[1] = MINIX_TEST;
2327 mib[2] = CTL_DESCRIBE;
2329 memset(buf, 0, sizeof(buf));
2330 oldlen = sizeof(buf);
2331 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2332 if (oldlen == 0) e(0);
2334 scd = (struct sysctldesc *)buf;
2335 endscd = (struct sysctldesc *)&buf[oldlen];
2336 memset(seen, 0, sizeof(seen));
2338 while (scd < endscd) {
2339 if (scd->descr_num >= __arraycount(seen)) e(0);
2340 if (seen[scd->descr_num]++) e(0);
2342 if (scd->descr_ver == 0) e(0);
2343 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2344 if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2346 p = scd->descr_str + scd->descr_len;
2347 while (p != (char *)NEXT_DESCR(scd))
2348 if (*p++ != '\0') e(0);
2350 scd = NEXT_DESCR(scd);
2352 if (scd != endscd) e(0);
2354 if (!seen[TEST_INT]) e(0);
2355 if (!seen[TEST_BOOL]) e(0);
2356 if (!seen[TEST_QUAD]) e(0);
2357 if (!seen[TEST_STRING]) e(0);
2358 if (!seen[TEST_STRUCT]) e(0);
2359 if (seen[TEST_PRIVATE]) e(0);
2360 if (!seen[TEST_ANYWRITE]) e(0);
2361 if (seen[TEST_SECRET]) e(0);
2362 if (!seen[TEST_PERM]) e(0);
2364 if (describe_node(mib, 2, TEST_INT, "Value test field", 0) != 0) e(0);
2365 if (describe_node(mib, 2, TEST_PRIVATE, "", 0) != -1) e(0);
2366 if (errno != EPERM) e(0);
2367 if (describe_node(mib, 2, TEST_SECRET, "", 0) != -1) e(0);
2368 if (errno != EPERM) e(0);
2369 if (describe_node(mib, 2, TEST_PERM, "", 0) != 0) e(0);
2371 mib[2] = TEST_SECRET;
2372 mib[3] = CTL_DESCRIBE;
2373 if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
2374 if (errno != EPERM) e(0);
2376 if (describe_node(mib, 3, SECRET_VALUE, "", 0) != -1) e(0);
2377 if (errno != EPERM) e(0);
2381 * Test sysctl(2) node descriptions, part 1: getting descriptions.
2383 static void
2384 test87e(void)
2386 static char buf[2048];
2387 char seen[32], *p;
2388 struct sysctldesc *scd, *endscd;
2389 struct sysctlnode scn;
2390 size_t oldlen, len, sublen;
2391 int mib[4];
2393 subtest = 4;
2395 mib[0] = CTL_MINIX;
2396 mib[1] = MINIX_TEST;
2397 mib[2] = CTL_DESCRIBE;
2398 memset(&scn, 0, sizeof(scn));
2400 /* Start with tests for getting a description listing. */
2401 if (sysctl(mib, 3, NULL, NULL, NULL, 0) != 0) e(0);
2403 if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
2404 if (oldlen == 0) e(0);
2405 len = oldlen;
2407 memset(buf, 0, sizeof(buf));
2408 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2409 if (oldlen != len) e(0);
2411 scd = (struct sysctldesc *)buf;
2412 endscd = (struct sysctldesc *)&buf[len];
2413 memset(seen, 0, sizeof(seen));
2415 sublen = (size_t)((char *)NEXT_DESCR(scd) - buf);
2417 while (scd < endscd) {
2418 if (scd->descr_num >= __arraycount(seen)) e(0);
2419 if (seen[scd->descr_num]++) e(0);
2421 if (scd->descr_ver == 0) e(0);
2422 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2423 if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2426 * This is not supposed to be complete. We test different
2427 * string lengths, private fields, and empty descriptions.
2429 switch (scd->descr_num) {
2430 case TEST_INT:
2431 if (strcmp(scd->descr_str, "Value test field")) e(0);
2432 break;
2433 case TEST_BOOL:
2434 if (strcmp(scd->descr_str, "Boolean test field")) e(0);
2435 break;
2436 case TEST_QUAD:
2437 if (strcmp(scd->descr_str, "Quad test field")) e(0);
2438 break;
2439 case TEST_STRING:
2440 if (strcmp(scd->descr_str, "String test field")) e(0);
2441 break;
2442 case TEST_PRIVATE:
2443 if (strcmp(scd->descr_str, "Private test field")) e(0);
2444 break;
2445 case TEST_SECRET:
2446 if (strcmp(scd->descr_str, "Private subtree")) e(0);
2447 break;
2448 case TEST_PERM:
2449 if (strcmp(scd->descr_str, "")) e(0);
2450 break;
2454 * If there are padding bytes, they must be zero, whether it is
2455 * because we set them or the MIB service copied out zeroes.
2457 p = scd->descr_str + scd->descr_len;
2458 while (p != (char *)NEXT_DESCR(scd))
2459 if (*p++ != '\0') e(0);
2461 scd = NEXT_DESCR(scd);
2463 if (scd != endscd) e(0);
2465 if (!seen[TEST_INT]) e(0);
2466 if (!seen[TEST_BOOL]) e(0);
2467 if (!seen[TEST_QUAD]) e(0);
2468 if (!seen[TEST_STRING]) e(0);
2469 if (!seen[TEST_STRUCT]) e(0);
2470 if (!seen[TEST_PRIVATE]) e(0);
2471 if (!seen[TEST_ANYWRITE]) e(0);
2472 if (!seen[TEST_SECRET]) e(0);
2473 if (!seen[TEST_PERM]) e(0);
2475 memset(buf, 0, sizeof(buf));
2476 oldlen = sublen;
2477 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
2478 if (errno != ENOMEM) e(0);
2480 scd = (struct sysctldesc *)buf;
2481 if (scd->descr_num != TEST_INT) e(0);
2482 if (scd->descr_ver == 0) e(0);
2483 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2484 if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2485 if (strcmp(scd->descr_str, "Value test field")) e(0);
2487 /* Next up, tests for getting a particular node's description. */
2488 memset(buf, 0, sizeof(buf));
2489 oldlen = sizeof(buf);
2490 if (sysctl(mib, 3, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
2491 if (errno != EFAULT) e(0);
2493 if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn) - 1) != -1) e(0);
2494 if (errno != EINVAL) e(0);
2495 if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn) + 1) != -1) e(0);
2496 if (errno != EINVAL) e(0);
2497 if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
2498 if (errno != EFAULT) e(0);
2500 memset(&scn, 0, sizeof(scn));
2501 scn.sysctl_flags = SYSCTL_VERS_0;
2502 scn.sysctl_num = INT_MAX;
2503 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2504 if (errno != EINVAL) e(0);
2506 scn.sysctl_flags = SYSCTL_VERSION;
2507 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2508 if (errno != ENOENT) e(0);
2510 scn.sysctl_num = TEST_BOOL;
2511 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2513 oldlen = sizeof(buf);
2514 scn.sysctl_num = TEST_INT;
2515 if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2516 if (errno != EFAULT) e(0);
2518 oldlen = sublen - 1;
2519 scn.sysctl_num = TEST_INT;
2520 if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2521 if (errno != ENOMEM) e(0);
2522 if (oldlen != sublen) e(0);
2524 if (describe_node(mib, 2, TEST_INT, "Value test field", 0) != 0) e(0);
2525 if (describe_node(mib, 2, TEST_QUAD, "Quad test field", 0) != 0) e(0);
2526 if (describe_node(mib, 2, TEST_PRIVATE, "Private test field",
2527 0) != 0) e(0);
2528 if (describe_node(mib, 2, TEST_SECRET, "Private subtree",
2529 0) != 0) e(0);
2530 if (describe_node(mib, 2, TEST_PERM, "", 0) != 0) e(0);
2533 * Make sure that unprivileged users cannot access privileged nodes'
2534 * descriptions. It doesn't sound too bad to me if they could, but
2535 * these are apparently the rules..
2537 (void)test_nonroot(sub87e);
2539 /* Do some more path-related error code tests unrelated to the rest. */
2540 mib[1] = INT_MAX;
2541 if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != -1) e(0);
2542 if (errno != ENOENT) e(0);
2544 mib[1] = MINIX_TEST;
2545 mib[2] = TEST_INT;
2546 if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2547 if (errno != ENOTDIR) e(0);
2549 mib[2] = TEST_BOOL;
2550 if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2551 if (errno != ENOTDIR) e(0);
2553 mib[2] = CTL_DESCRIBE;
2554 if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2555 if (errno != EINVAL) e(0);
2559 * Test setting descriptions from an unprivileged process.
2561 static void
2562 sub87f(void)
2564 struct sysctlnode scn;
2565 int mib[3];
2567 mib[0] = CTL_MINIX;
2568 mib[1] = MINIX_TEST;
2569 mib[2] = CTL_DESCRIBE;
2571 memset(&scn, 0, sizeof(scn));
2572 scn.sysctl_flags = SYSCTL_VERSION;
2573 scn.sysctl_num = TEST_DYNAMIC;
2574 scn.sysctl_desc = "Description.";
2576 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2577 if (errno != EPERM) e(0);
2581 * Test sysctl(2) node descriptions, part 2: setting descriptions.
2583 static void
2584 test87f(void)
2586 static char buf[2048];
2587 char seen, *p;
2588 struct sysctlnode scn, tmpscn, scnset[3];
2589 struct sysctldesc *scd, *endscd, *scdset[2];
2590 size_t oldlen, len;
2591 int i, r, mib[4], id[2];
2593 subtest = 5;
2596 * All tests that experiment with dynamic nodes must start with trying
2597 * to destroy the TEST_DYNAMIC node first, as tests may be run
2598 * individually, and this node exists as a static node after booting.
2600 mib[0] = CTL_MINIX;
2601 mib[1] = MINIX_TEST;
2602 (void)destroy_node(mib, 2, TEST_DYNAMIC);
2605 * First try setting and retrieving the description of a dynamic node
2606 * in a directory full of static nodes.
2608 mib[2] = CTL_CREATE;
2609 memset(&scn, 0, sizeof(scn));
2610 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2611 CTLFLAG_READONLY | CTLTYPE_INT;
2612 scn.sysctl_size = sizeof(int);
2613 scn.sysctl_num = TEST_DYNAMIC;
2614 scn.sysctl_idata = 27182818;
2615 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2616 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2618 memcpy(&tmpscn, &scn, sizeof(tmpscn));
2620 /* We should get an empty description for the node in a listing. */
2621 mib[2] = CTL_DESCRIBE;
2622 memset(buf, 0, sizeof(buf));
2623 oldlen = sizeof(buf);
2624 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2626 scd = (struct sysctldesc *)buf;
2627 endscd = (struct sysctldesc *)&buf[oldlen];
2628 seen = 0;
2630 while (scd < endscd) {
2631 if (scd->descr_num == TEST_DYNAMIC) {
2632 if (seen++) e(0);
2634 if (scd->descr_len != 1) e(0);
2635 if (scd->descr_str[0] != '\0') e(0);
2638 if (scd->descr_ver == 0) e(0);
2639 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2640 if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2642 p = scd->descr_str + scd->descr_len;
2643 while (p != (char *)NEXT_DESCR(scd))
2644 if (*p++ != '\0') e(0);
2646 scd = NEXT_DESCR(scd);
2648 if (scd != endscd) e(0);
2650 if (!seen) e(0);
2652 /* We should get an empty description quering the node directly. */
2653 if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != 0) e(0);
2655 /* Attempt to set a description with a bad description pointer. */
2656 if (describe_node(mib, 2, TEST_DYNAMIC, bad_ptr, 1) != -1) e(0);
2657 if (errno != EFAULT) e(0);
2659 /* Attempt to set a description that is longer than allowed. */
2660 memset(buf, 'A', sizeof(buf) - 1);
2661 buf[sizeof(buf) - 1] = '\0';
2662 if (describe_node(mib, 2, TEST_DYNAMIC, buf, 1) != -1) e(0);
2663 if (errno != EINVAL) e(0);
2665 /* Now actually set a description. */
2666 if (describe_node(mib, 2, TEST_DYNAMIC, "Dynamic node", 1) != 0) e(0);
2667 len = strlen("Dynamic node") + 1;
2669 /* We should get the new description for the node in a listing. */
2670 memset(buf, 0, sizeof(buf));
2671 oldlen = sizeof(buf);
2672 if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2674 scd = (struct sysctldesc *)buf;
2675 endscd = (struct sysctldesc *)&buf[oldlen];
2676 seen = 0;
2678 while (scd < endscd) {
2679 if (scd->descr_num == TEST_DYNAMIC) {
2680 if (seen++) e(0);
2682 if (scd->descr_len != len) e(0);
2683 if (strcmp(scd->descr_str, "Dynamic node")) e(0);
2686 if (scd->descr_ver == 0) e(0);
2687 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2688 if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2690 p = scd->descr_str + scd->descr_len;
2691 while (p != (char *)NEXT_DESCR(scd))
2692 if (*p++ != '\0') e(0);
2694 scd = NEXT_DESCR(scd);
2696 if (scd != endscd) e(0);
2698 if (!seen) e(0);
2700 /* We should get the new description quering the node directly. */
2701 if (describe_node(mib, 2, TEST_DYNAMIC, "Dynamic node", 0) != 0) e(0);
2703 mib[2] = CTL_DESCRIBE;
2704 memset(&scn, 0, sizeof(scn));
2705 scn.sysctl_flags = SYSCTL_VERS_0;
2706 scn.sysctl_num = TEST_INT;
2707 scn.sysctl_desc = "Test description";
2708 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2709 if (errno != EINVAL) e(0);
2711 /* It is not possible to replace an existing static description. */
2712 scn.sysctl_flags = SYSCTL_VERSION;
2713 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2714 if (errno != EPERM) e(0);
2716 /* Nonexistent nodes cannot be given a description. */
2717 scn.sysctl_num = INT_MAX;
2718 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2719 if (errno != ENOENT) e(0);
2721 /* It is not possible to replace an existing dynamic description. */
2722 scn.sysctl_num = TEST_DYNAMIC;
2723 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2724 if (errno != EPERM) e(0);
2726 /* It is not possible to set a description on a permanent node. */
2727 scn.sysctl_num = TEST_PERM;
2728 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2729 if (errno != EPERM) e(0);
2731 /* Verify that TEST_DYNAMIC now has CTLFLAG_OWNDESC set. */
2732 if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
2733 if (!(scn.sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2735 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2738 * Set a description on a static node, ensure that CTLFLAG_OWNDESC is
2739 * set, and then destroy the static node. This should still free the
2740 * memory allocated for the description. We cannot test whether the
2741 * memory is really freed, but at least we can trigger this case at
2742 * all, and leave the rest up to memory checkers or whatever. Since we
2743 * destroy the static node, we can not do this more than once, and thus
2744 * we skip this test if the static node does not exist.
2746 r = describe_node(mib, 2, TEST_DESTROY1, "Destroy me", 1);
2748 if (r == -1 && errno != ENOENT) e(0);
2749 else if (r == 0) {
2750 if (query_node(mib, 2, TEST_DESTROY1, &scn) != 0) e(0);
2751 if (!(scn.sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2753 if (describe_node(mib, 2, TEST_DESTROY1, "Destroy me", 0) != 0)
2754 e(0);
2756 if (destroy_node(mib, 2, TEST_DESTROY1) != 0) e(0);
2760 * Test queries and description listings in subtrees.
2762 mib[2] = CTL_CREATE;
2763 memset(&scn, 0, sizeof(scn));
2764 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
2765 scn.sysctl_num = TEST_DYNAMIC;
2766 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2767 scn.sysctl_desc = "This will not be set.";
2768 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2770 /* Setting sysctl_desc should have no effect during creation. */
2771 if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != 0) e(0);
2773 mib[2] = TEST_DYNAMIC;
2774 id[0] = create_node(mib, 3, &tmpscn, CTL_CREATE, "NodeA", -1, NULL);
2775 if (id[0] < 0) e(0);
2776 id[1] = create_node(mib, 3, &tmpscn, CTL_CREATE, "NodeB", -1, NULL);
2777 if (id[1] < 0) e(0);
2778 if (id[0] == id[1]) e(0);
2780 mib[3] = CTL_QUERY;
2781 oldlen = sizeof(scnset);
2782 if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2783 if (oldlen != sizeof(scnset[0]) * 2) e(0);
2784 i = (scnset[0].sysctl_num != id[0]);
2785 if (scnset[i].sysctl_num != id[0]) e(0);
2786 if (scnset[1 - i].sysctl_num != id[1]) e(0);
2787 if (scnset[i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2788 if (scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2790 mib[3] = CTL_DESCRIBE;
2791 memset(buf, 0, sizeof(buf));
2792 oldlen = sizeof(buf);
2793 if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2794 if (oldlen == 0) e(0);
2796 scdset[0] = (struct sysctldesc *)buf;
2797 scdset[1] = NEXT_DESCR(scdset[0]);
2798 if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2799 i = (scdset[0]->descr_num != id[0]);
2800 if (scdset[i]->descr_num != id[0]) e(0);
2801 if (scdset[i]->descr_ver == 0) e(0);
2802 if (scdset[i]->descr_len != 1) e(0);
2803 if (scdset[i]->descr_str[0] != '\0') e(0);
2804 if (scdset[1 - i]->descr_num != id[1]) e(0);
2805 if (scdset[1 - i]->descr_ver == 0) e(0);
2806 if (scdset[1 - i]->descr_len != 1) e(0);
2807 if (scdset[1 - i]->descr_str[0] != '\0') e(0);
2809 if (describe_node(mib, 3, id[0], "Description A", 1) != 0) e(0);
2811 mib[3] = CTL_QUERY;
2812 oldlen = sizeof(scnset);
2813 if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2814 if (oldlen != sizeof(scnset[0]) * 2) e(0);
2815 i = (scnset[0].sysctl_num != id[0]);
2816 if (scnset[i].sysctl_num != id[0]) e(0);
2817 if (scnset[1 - i].sysctl_num != id[1]) e(0);
2818 if (!(scnset[i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2819 if (scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2821 mib[3] = CTL_DESCRIBE;
2822 memset(buf, 0, sizeof(buf));
2823 oldlen = sizeof(buf);
2824 if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2825 if (oldlen == 0) e(0);
2827 scdset[0] = (struct sysctldesc *)buf;
2828 scdset[1] = NEXT_DESCR(scdset[0]);
2829 if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2830 i = (scdset[0]->descr_num != id[0]);
2831 if (scdset[i]->descr_num != id[0]) e(0);
2832 if (scdset[i]->descr_ver == 0) e(0);
2833 if (strcmp(scdset[i]->descr_str, "Description A")) e(0);
2834 if (scdset[i]->descr_len != strlen(scdset[i]->descr_str) + 1) e(0);
2835 if (scdset[1 - i]->descr_num != id[1]) e(0);
2836 if (scdset[1 - i]->descr_ver == 0) e(0);
2837 if (scdset[1 - i]->descr_len != 1) e(0);
2838 if (scdset[1 - i]->descr_str[0] != '\0') e(0);
2840 if (describe_node(mib, 3, id[1], "Description B", 1) != 0) e(0);
2842 mib[3] = CTL_QUERY;
2843 oldlen = sizeof(scnset);
2844 if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2845 if (oldlen != sizeof(scnset[0]) * 2) e(0);
2846 i = (scnset[0].sysctl_num != id[0]);
2847 if (scnset[i].sysctl_num != id[0]) e(0);
2848 if (scnset[1 - i].sysctl_num != id[1]) e(0);
2849 if (!(scnset[i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2850 if (!(scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2852 mib[3] = CTL_DESCRIBE;
2853 memset(buf, 0, sizeof(buf));
2854 oldlen = sizeof(buf);
2855 if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2856 if (oldlen == 0) e(0);
2858 scdset[0] = (struct sysctldesc *)buf;
2859 scdset[1] = NEXT_DESCR(scdset[0]);
2860 if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2861 i = (scdset[0]->descr_num != id[0]);
2862 if (scdset[i]->descr_num != id[0]) e(0);
2863 if (scdset[i]->descr_ver == 0) e(0);
2864 if (strcmp(scdset[i]->descr_str, "Description A")) e(0);
2865 if (scdset[i]->descr_len != strlen(scdset[i]->descr_str) + 1) e(0);
2866 if (scdset[1 - i]->descr_num != id[1]) e(0);
2867 if (scdset[1 - i]->descr_ver == 0) e(0);
2868 if (strcmp(scdset[1 - i]->descr_str, "Description B")) e(0);
2869 if (scdset[1 - i]->descr_len != strlen(scdset[1 - i]->descr_str) + 1)
2870 e(0);
2872 if (destroy_node(mib, 3, id[0]) != 0) e(0);
2873 if (destroy_node(mib, 3, id[1]) != 0) e(0);
2875 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2878 * Test that the resulting description is copied out after setting it,
2879 * and that copy failures do not undo the description getting set.
2881 if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2882 NULL) == -1) e(0);
2884 mib[2] = CTL_DESCRIBE;
2885 memset(&scn, 0, sizeof(scn));
2886 scn.sysctl_flags = SYSCTL_VERSION;
2887 scn.sysctl_num = TEST_DYNAMIC;
2888 scn.sysctl_desc = "Testing..";
2889 memset(buf, 0, sizeof(buf));
2890 oldlen = sizeof(buf);
2891 if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != 0) e(0);
2892 if (oldlen == 0) e(0);
2893 len = oldlen;
2895 scd = (struct sysctldesc *)buf;
2896 if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2897 if (scd->descr_len != strlen(scn.sysctl_desc) + 1) e(0);
2898 if (strcmp(scd->descr_str, scn.sysctl_desc)) e(0);
2899 if (oldlen != (size_t)((char *)NEXT_DESCR(scd) - buf)) e(0);
2900 p = scd->descr_str + scd->descr_len;
2901 while (p != (char *)NEXT_DESCR(scd))
2902 if (*p++ != '\0') e(0);
2904 if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2906 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2908 if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2909 NULL) == -1) e(0);
2911 memset(buf, 0, sizeof(buf));
2912 oldlen = len - 1;
2913 if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2914 if (errno != ENOMEM) e(0);
2915 if (oldlen != len) e(0);
2917 if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2919 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2921 if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2922 NULL) == -1) e(0);
2924 memset(buf, 0, sizeof(buf));
2925 oldlen = len;
2926 if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2927 if (errno != EFAULT) e(0);
2929 if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2931 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2933 /* Finally, ensure that unprivileged users cannot set descriptions. */
2934 memcpy(&scn, &tmpscn, sizeof(scn));
2935 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2936 CTLFLAG_READWRITE | CTLFLAG_ANYWRITE | CTLTYPE_INT;
2937 if (create_node(mib, 2, &scn, TEST_DYNAMIC, "dynamic", -1,
2938 NULL) == -1) e(0);
2940 (void)test_nonroot(sub87f);
2942 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2946 * Set or test buffer contents. When setting, the buffer is filled with a
2947 * sequence of bytes that is a) free of null characters and b) likely to cause
2948 * detection of wrongly copied subsequences. When testing, for any size up to
2949 * the size used to set the buffer contents, 0 is returned if the buffer
2950 * contents match expectations, or -1 if they do not.
2952 static int
2953 test_buf(char * buf, unsigned char c, size_t size, int set)
2955 unsigned char *ptr;
2956 int step;
2958 ptr = (unsigned char *)buf;
2960 for (step = 1; size > 0; size--) {
2961 if (set)
2962 *ptr++ = c;
2963 else if (*ptr++ != c)
2964 return -1;
2966 c += step;
2967 if (c == 0) {
2968 if (++step == 256)
2969 step = 1;
2970 c += step;
2974 return 0;
2978 * Test large data sizes from an unprivileged process.
2980 static void
2981 sub87g(void)
2983 char *ptr;
2984 size_t size, oldlen;
2985 int id, mib[3];
2987 size = getpagesize() * 3;
2989 if ((ptr = mmap(NULL, size, PROT_READ, MAP_ANON | MAP_PRIVATE, -1,
2990 0)) == MAP_FAILED) e(0);
2991 memset(ptr, 0x2f, size);
2993 mib[0] = CTL_MINIX;
2994 mib[1] = MINIX_TEST;
2995 mib[2] = TEST_DYNAMIC;
2996 oldlen = size - 2;
2997 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
2998 if (oldlen != size - 2) e(0);
2999 if (test_buf(ptr, 'D', size - 2, 0) != 0) e(0);
3002 * Given the large data size, we currently expect this attempt to
3003 * write to the structure to be blocked by the MIB service.
3005 if (sysctl(mib, 3, NULL, NULL, ptr, oldlen) != -1) e(0);
3006 if (errno != EPERM) e(0);
3008 /* Get the ID of the second dynamic node. */
3009 mib[2] = TEST_ANYWRITE;
3010 oldlen = sizeof(id);
3011 if (sysctl(mib, 3, &id, &oldlen, NULL, 0) != 0) e(0);
3012 if (oldlen != sizeof(id)) e(0);
3013 if (id < 0) e(0);
3016 * Test data size limits for strings as well, although here we can also
3017 * ensure that we hit the right check by testing with a shorter string.
3019 mib[2] = id;
3020 oldlen = size;
3021 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3022 if (oldlen != size) e(0);
3023 if (test_buf(ptr, 'f', size - 1, 0) != 0) e(0);
3024 if (ptr[size - 1] != '\0') e(0);
3026 test_buf(ptr, 'h', size - 1, 1);
3027 if (sysctl(mib, 3, NULL, NULL, ptr, size) != -1) e(0);
3028 if (errno != EPERM) e(0);
3030 if (sysctl(mib, 3, NULL, NULL, ptr, getpagesize() - 1) != 0) e(0);
3032 if (munmap(ptr, size) != 0) e(0);
3036 * Test large data sizes and mid-data page faults.
3038 static void
3039 test87g(void)
3041 struct sysctlnode scn, newscn;
3042 char *ptr;
3043 size_t pgsz, size, oldlen;
3044 int id, mib[3];
3046 subtest = 6;
3049 * No need to go overboard with sizes here; it will just cause the MIB
3050 * service's memory usage to grow - permanently. Three pages followed
3051 * by an unmapped page is plenty for this test.
3053 pgsz = getpagesize();
3054 size = pgsz * 3;
3056 if ((ptr = mmap(NULL, size + pgsz, PROT_READ, MAP_ANON | MAP_PRIVATE,
3057 -1, 0)) == MAP_FAILED) e(0);
3058 if (munmap(ptr + size, pgsz) != 0) e(0);
3060 (void)destroy_node(mib, 2, TEST_DYNAMIC);
3062 /* Test string creation initializers with an accurate length. */
3063 mib[0] = CTL_MINIX;
3064 mib[1] = MINIX_TEST;
3065 mib[2] = CTL_CREATE;
3066 memset(&scn, 0, sizeof(scn));
3067 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3068 CTLFLAG_READWRITE | CTLTYPE_STRING;
3069 scn.sysctl_num = TEST_DYNAMIC;
3070 scn.sysctl_data = ptr;
3071 scn.sysctl_size = size;
3072 strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
3073 test_buf(ptr, 'a', size, 1);
3074 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3075 if (errno != EINVAL) e(0); /* no null terminator */
3077 scn.sysctl_size++;
3078 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3079 if (errno != EFAULT) e(0);
3081 scn.sysctl_size--;
3082 ptr[size - 1] = '\0';
3083 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3085 mib[2] = TEST_DYNAMIC;
3086 if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
3087 if (oldlen != size) e(0);
3089 memset(ptr, 0, size);
3090 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3091 if (oldlen != size) e(0);
3092 if (ptr[size - 1] != '\0') e(0);
3093 if (test_buf(ptr, 'a', size - 1, 0) != 0) e(0);
3095 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3097 /* Test string creation initializers with no length. */
3098 mib[2] = CTL_CREATE;
3099 scn.sysctl_size = 0;
3100 test_buf(ptr, 'b', size, 1);
3101 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3102 if (errno != EFAULT) e(0);
3104 test_buf(ptr, 'b', size - 1, 1);
3105 ptr[size - 1] = '\0';
3106 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3108 if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
3109 if (newscn.sysctl_size != size) e(0);
3111 mib[2] = TEST_DYNAMIC;
3112 if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
3113 if (oldlen != size) e(0);
3115 memset(ptr, 0x7e, size);
3116 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3117 if (oldlen != size) e(0);
3118 if (ptr[size - 1] != '\0') e(0);
3119 if (test_buf(ptr, 'b', size - 1, 0) != 0) e(0);
3121 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3124 * Test string creation initializers with a length exceeding the string
3125 * length. If the string is properly null terminated, this should not
3126 * result in a fault.
3128 mib[2] = CTL_CREATE;
3129 scn.sysctl_size = size;
3130 scn.sysctl_data = &ptr[size - pgsz - 5];
3131 test_buf(&ptr[size - pgsz - 5], 'c', pgsz + 5, 1);
3132 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3133 if (errno != EFAULT) e(0);
3135 ptr[size - 1] = '\0';
3136 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3138 if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
3139 if (newscn.sysctl_size != size) e(0);
3141 mib[2] = TEST_DYNAMIC;
3142 oldlen = size - pgsz - 6;
3143 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3144 if (oldlen != pgsz + 5) e(0);
3145 /* We rely on only the actual string getting copied out here. */
3146 if (memcmp(ptr, &ptr[size - pgsz - 5], pgsz + 5)) e(0);
3148 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3150 /* Test structure creation initializers. */
3151 mib[2] = CTL_CREATE;
3152 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3153 CTLFLAG_ANYWRITE | CTLFLAG_READWRITE | CTLTYPE_STRUCT;
3154 scn.sysctl_size = size - 2;
3155 scn.sysctl_data = &ptr[3];
3156 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3157 if (errno != EFAULT) e(0);
3159 scn.sysctl_data = &ptr[2];
3160 test_buf(&ptr[2], 'd', size - 2, 1);
3161 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3163 mib[2] = TEST_DYNAMIC;
3164 memset(ptr, 0x3b, size);
3165 oldlen = size - 2;
3166 if (sysctl(mib, 3, &ptr[3], &oldlen, NULL, 0) != -1) e(0);
3167 if (errno != EFAULT) e(0);
3168 oldlen = size - 2;
3169 if (sysctl(mib, 3, &ptr[2], &oldlen, NULL, 0) != 0) e(0);
3170 if (oldlen != size - 2) e(0);
3171 if (test_buf(&ptr[2], 'd', size - 2, 0) != 0) e(0);
3174 * Test setting new values. We already have a structure node, so let's
3175 * start there.
3177 test_buf(&ptr[2], 'D', size - 2, 1);
3178 if (sysctl(mib, 3, NULL, NULL, &ptr[3], size - 2) != -1) e(0);
3179 if (errno != EFAULT) e(0);
3181 /* Did the mid-data fault cause a partial update? It better not. */
3182 memset(ptr, 0x4c, size);
3183 oldlen = size - 2;
3184 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3185 if (oldlen != size - 2) e(0);
3186 if (test_buf(ptr, 'd', size - 2, 0) != 0) e(0);
3188 test_buf(&ptr[2], 'D', size - 2, 1);
3189 if (sysctl(mib, 3, NULL, NULL, &ptr[2], size - 2) != 0) e(0);
3191 memset(ptr, 0x5d, size);
3192 oldlen = size - 2;
3193 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3194 if (oldlen != size - 2) e(0);
3195 if (test_buf(ptr, 'D', size - 2, 0) != 0) e(0);
3198 * We are going to reuse TEST_DYNAMIC for the non-root test later, so
3199 * create a new node for string tests.
3201 mib[2] = CTL_CREATE;
3202 memset(&scn, 0, sizeof(scn));
3203 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3204 CTLFLAG_ANYWRITE | CTLFLAG_READWRITE | CTLTYPE_STRING;
3205 scn.sysctl_num = CTL_CREATE;
3206 scn.sysctl_size = size;
3207 scn.sysctl_data = ptr;
3208 test_buf(ptr, 'e', size - 1, 1);
3209 ptr[size - 1] = '\0';
3210 strlcpy(scn.sysctl_name, "dynamic2", sizeof(scn.sysctl_name));
3211 oldlen = sizeof(newscn);
3212 if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3213 if (oldlen != sizeof(newscn)) e(0);
3214 id = newscn.sysctl_num;
3215 if (id < 0) e(0);
3218 * Test setting a short but faulty string, ensuring that no partial
3219 * update on the field contents takes place.
3221 mib[2] = id;
3222 memcpy(&ptr[size - 3], "XYZ", 3);
3223 if (sysctl(mib, 3, NULL, NULL, &ptr[size - 3], 4) != -1) e(0);
3224 if (errno != EFAULT) e(0);
3226 oldlen = size;
3227 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3228 if (oldlen != size) e(0);
3229 if (test_buf(ptr, 'e', size - 1, 0) != 0) e(0);
3230 if (ptr[size - 1] != '\0') e(0);
3232 memcpy(&ptr[size - 3], "XYZ", 3);
3233 if (sysctl(mib, 3, NULL, NULL, &ptr[size - 3], 3) != 0) e(0);
3235 oldlen = size;
3236 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3237 if (oldlen != 4) e(0);
3238 if (strcmp(ptr, "XYZ")) e(0);
3240 test_buf(&ptr[1], 'f', size - 1, 1);
3241 if (sysctl(mib, 3, NULL, NULL, &ptr[1], size - 1) != 0) e(0);
3243 test_buf(&ptr[1], 'G', size - 1, 1);
3244 if (sysctl(mib, 3, NULL, NULL, &ptr[1], size) != -1) e(0);
3245 if (errno != EFAULT) e(0);
3247 oldlen = size;
3248 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3249 if (oldlen != size) e(0);
3250 if (test_buf(ptr, 'f', size - 1, 0) != 0) e(0);
3251 if (ptr[size - 1] != '\0') e(0);
3254 * Test descriptions as well. First, the MIB service does not allow
3255 * for overly long descriptions, although the limit is not exposed.
3256 * Three memory pages worth of text is way too long though.
3258 memset(ptr, 'A', size);
3259 if (describe_node(mib, 2, id, ptr, 1) != -1) e(0);
3260 if (errno != EINVAL) e(0); /* not EFAULT, should never get that far */
3262 ptr[size - 1] = '\0';
3263 if (describe_node(mib, 2, id, ptr, 1) != -1) e(0);
3264 if (errno != EINVAL) e(0);
3266 if (describe_node(mib, 2, id, "", 0) != 0) e(0);
3269 * Second, the description routine must deal with faults occurring
3270 * while it is trying to find the string end.
3272 ptr[size - 2] = 'B';
3273 ptr[size - 1] = 'C';
3274 if (describe_node(mib, 2, id, &ptr[size - 3], 1) != -1) e(0);
3275 if (errno != EFAULT) e(0);
3277 if (describe_node(mib, 2, id, "", 0) != 0) e(0);
3279 ptr[size - 1] = '\0';
3280 if (describe_node(mib, 2, id, &ptr[size - 3], 1) != 0) e(0);
3282 if (describe_node(mib, 2, id, "AB", 0) != 0) e(0);
3284 /* Pass the second dynamic node ID to the unprivileged child. */
3285 mib[2] = TEST_ANYWRITE;
3286 if (sysctl(mib, 3, NULL, NULL, &id, sizeof(id)) != 0) e(0);
3288 (void)test_nonroot(sub87g);
3290 mib[2] = id;
3291 oldlen = size;
3292 if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3293 if (oldlen != pgsz) e(0);
3294 if (test_buf(ptr, 'h', pgsz - 1, 1) != 0) e(0);
3295 if (ptr[pgsz - 1] != '\0') e(0);
3297 if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3298 if (destroy_node(mib, 2, id) != 0) e(0);
3300 munmap(ptr, size);
3304 * Verify whether the given node on the given path has the given node version.
3305 * Return 0 if the version matches, or -1 if it does not or a failure occurred.
3307 static int
3308 check_version(const int * path, unsigned int pathlen, int id, uint32_t ver)
3310 struct sysctlnode scn;
3311 struct sysctldesc scd;
3312 size_t oldlen;
3313 int r, mib[CTL_MAXNAME];
3315 assert(pathlen < CTL_MAXNAME);
3316 memcpy(mib, path, sizeof(mib[0]) * pathlen);
3317 mib[pathlen] = CTL_DESCRIBE;
3320 * For some reason, when retrieving a particular description (as
3321 * opposed to setting one), the node version number is not checked.
3322 * In order to test this, we deliberately pass in a node version number
3323 * that, if checked, would eventually cause failures.
3325 memset(&scn, 0, sizeof(scn));
3326 scn.sysctl_flags = SYSCTL_VERSION;
3327 scn.sysctl_num = id;
3328 scn.sysctl_ver = 1;
3329 oldlen = sizeof(scd);
3330 r = sysctl(mib, pathlen + 1, &scd, &oldlen, &scn, sizeof(scn));
3331 if (r == -1 && errno != ENOMEM) e(0);
3333 return (scd.descr_ver == ver) ? 0 : -1;
3337 * Test sysctl(2) node versioning.
3339 static void
3340 test87h(void)
3342 struct sysctlnode scn, oldscn;
3343 size_t oldlen;
3344 uint32_t ver[4];
3345 int mib[4], id[4];
3348 * The other tests have already tested sufficiently that a zero version
3349 * is always accepted in calls. Here, we test that node versions
3350 * actually change when creating and destroying nodes, and that the
3351 * right version test is implemented for all of the four node meta-
3352 * operations (query, create, destroy, describe). Why did we not do
3353 * this earlier, you ask? Well, versioning was implemented later on.
3355 subtest = 7;
3358 * Test versioning with node creation.
3360 mib[0] = CTL_MINIX;
3361 mib[1] = MINIX_TEST;
3362 mib[2] = CTL_CREATE;
3363 memset(&scn, 0, sizeof(scn));
3364 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
3365 scn.sysctl_num = CTL_CREATE;
3366 strlcpy(scn.sysctl_name, "NodeA", sizeof(scn.sysctl_name));
3367 oldlen = sizeof(oldscn);
3368 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3369 if (oldlen != sizeof(oldscn)) e(0);
3370 id[0] = oldscn.sysctl_num;
3371 ver[0] = oldscn.sysctl_ver;
3372 if (ver[0] == 0) e(0);
3374 if (check_version(mib, 0, CTL_MINIX, ver[0]) != 0) e(0);
3375 if (check_version(mib, 1, MINIX_TEST, ver[0]) != 0) e(0);
3376 if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3378 strlcpy(scn.sysctl_name, "NodeB", sizeof(scn.sysctl_name));
3379 oldlen = sizeof(oldscn);
3380 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3381 if (oldlen != sizeof(oldscn)) e(0);
3382 id[1] = oldscn.sysctl_num;
3383 ver[1] = oldscn.sysctl_ver;
3384 if (ver[1] == 0) e(0);
3385 if (ver[1] != NEXT_VER(ver[0])) e(0);
3387 if (check_version(mib, 0, CTL_MINIX, ver[1]) != 0) e(0);
3388 if (check_version(mib, 1, MINIX_TEST, ver[1]) != 0) e(0);
3389 if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3390 if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3392 /* A version that is too high should be rejected. */
3393 mib[2] = id[0];
3394 mib[3] = CTL_CREATE;
3395 scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
3396 CTLFLAG_READWRITE | CTLTYPE_INT;
3397 scn.sysctl_size = sizeof(int);
3398 scn.sysctl_ver = NEXT_VER(ver[1]);
3399 strlcpy(scn.sysctl_name, "ValueA", sizeof(scn.sysctl_name));
3400 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3401 if (errno != EINVAL) e(0);
3403 /* The version of the parent node should be accepted. */
3404 scn.sysctl_ver = ver[0]; /* different from the root node version */
3405 oldlen = sizeof(oldscn);
3406 if (sysctl(mib, 4, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3407 if (oldlen != sizeof(oldscn)) e(0);
3408 id[2] = oldscn.sysctl_num;
3409 ver[2] = oldscn.sysctl_ver;
3410 if (ver[2] == 0) e(0);
3411 if (ver[2] != NEXT_VER(ver[1])) e(0);
3413 if (check_version(mib, 0, CTL_MINIX, ver[2]) != 0) e(0);
3414 if (check_version(mib, 1, MINIX_TEST, ver[2]) != 0) e(0);
3415 if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3416 if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3417 if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3419 /* A version that is too low (old) should be rejected. */
3420 mib[2] = id[1];
3422 scn.sysctl_ver = ver[0];
3423 strlcpy(scn.sysctl_name, "ValueB", sizeof(scn.sysctl_name));
3424 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3425 if (errno != EINVAL) e(0);
3427 /* The version of the root node should be accepted. */
3428 scn.sysctl_ver = ver[2]; /* different from the parent node version */
3429 oldlen = sizeof(oldscn);
3430 if (sysctl(mib, 4, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3431 if (oldlen != sizeof(oldscn)) e(0);
3432 id[3] = oldscn.sysctl_num;
3433 ver[3] = oldscn.sysctl_ver;
3434 if (ver[3] == 0) e(0);
3435 if (ver[3] != NEXT_VER(ver[2])) e(0);
3437 if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3438 if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3439 if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3440 if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3441 if (check_version(mib, 3, id[3], ver[3]) != 0) e(0);
3442 mib[2] = id[0];
3443 if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3446 * Test versioning with node queries.
3448 mib[3] = CTL_QUERY;
3449 memset(&scn, 0, sizeof(scn));
3450 scn.sysctl_flags = SYSCTL_VERSION;
3451 scn.sysctl_ver = ver[0]; /* previous parent version */
3452 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3453 if (errno != EINVAL) e(0);
3455 scn.sysctl_ver = ver[2]; /* parent version */
3456 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3458 scn.sysctl_ver = ver[2]; /* root version */
3459 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3461 scn.sysctl_ver = NEXT_VER(ver[3]); /* nonexistent version */
3462 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3463 if (errno != EINVAL) e(0);
3466 * Test versioning with node description.
3468 mib[2] = CTL_DESCRIBE;
3469 scn.sysctl_num = id[0];
3470 scn.sysctl_ver = ver[3]; /* root and parent, but not target version */
3471 scn.sysctl_desc = "Parent A";
3472 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3473 if (errno != EINVAL) e(0);
3475 scn.sysctl_ver = ver[1]; /* another bad version */
3476 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3477 if (errno != EINVAL) e(0);
3479 scn.sysctl_ver = ver[2]; /* target version */
3480 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3482 /* Neither querying nor description should have changed versions. */
3483 if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3484 if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3485 if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3486 if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3487 mib[2] = id[1];
3488 if (check_version(mib, 3, id[3], ver[3]) != 0) e(0);
3489 mib[2] = id[0];
3490 if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3493 * Test versioning with node destruction.
3495 mib[3] = CTL_DESTROY;
3496 memset(&scn, 0, sizeof(scn));
3497 scn.sysctl_flags = SYSCTL_VERSION;
3498 scn.sysctl_num = id[2];
3499 scn.sysctl_ver = ver[3]; /* root but not target version */
3500 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3501 if (errno != EINVAL) e(0);
3503 scn.sysctl_ver = ver[2]; /* target (and parent) version */
3504 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3506 /* Fortunately, versions are predictable. */
3507 ver[0] = NEXT_VER(ver[3]);
3509 if (check_version(mib, 0, CTL_MINIX, ver[0]) != 0) e(0);
3510 if (check_version(mib, 1, MINIX_TEST, ver[0]) != 0) e(0);
3511 if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3512 if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3514 mib[2] = id[1];
3515 scn.sysctl_num = id[3];
3516 scn.sysctl_ver = ver[0]; /* root but not target version */
3517 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3518 if (errno != EINVAL) e(0);
3520 scn.sysctl_ver = ver[3]; /* target (and parent) version */
3521 if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3523 ver[1] = NEXT_VER(ver[0]);
3525 if (check_version(mib, 0, CTL_MINIX, ver[1]) != 0) e(0);
3526 if (check_version(mib, 1, MINIX_TEST, ver[1]) != 0) e(0);
3527 if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3528 if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3530 mib[2] = CTL_DESTROY;
3531 scn.sysctl_num = id[0];
3532 scn.sysctl_ver = ver[1]; /* root and parent, but not target version */
3533 if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3534 if (errno != EINVAL) e(0);
3536 scn.sysctl_ver = ver[0]; /* target version */
3537 oldlen = sizeof(oldscn);
3538 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3539 if (oldlen != sizeof(oldscn)) e(0);
3540 if (oldscn.sysctl_num != id[0]) e(0);
3541 if (oldscn.sysctl_ver != ver[0]) e(0);
3543 ver[2] = NEXT_VER(ver[1]);
3545 if (check_version(mib, 0, CTL_MINIX, ver[2]) != 0) e(0);
3546 if (check_version(mib, 1, MINIX_TEST, ver[2]) != 0) e(0);
3547 if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3549 /* For the last destruction, just see if we get the old version. */
3550 scn.sysctl_num = id[1];
3551 scn.sysctl_ver = 0;
3552 oldlen = sizeof(oldscn);
3553 if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3554 if (oldlen != sizeof(oldscn)) e(0);
3555 if (oldscn.sysctl_num != id[1]) e(0);
3556 if (oldscn.sysctl_ver != ver[1]) e(0);
3558 ver[3] = NEXT_VER(ver[2]);
3560 if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3561 if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3565 * Perform pre-test initialization.
3567 static void
3568 test87_init(void)
3570 size_t oldlen;
3571 int mib[3];
3573 subtest = 99;
3575 if ((bad_ptr = mmap(NULL, getpagesize(), PROT_READ,
3576 MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) e(0);
3577 if (munmap(bad_ptr, getpagesize()) != 0) e(0);
3579 mib[0] = CTL_MINIX;
3580 mib[1] = MINIX_MIB;
3581 mib[2] = MIB_NODES;
3582 oldlen = sizeof(nodes);
3583 if (sysctl(mib, 3, &nodes, &oldlen, NULL, 0) != 0) e(0);
3584 if (oldlen != sizeof(nodes)) e(0);
3586 mib[2] = MIB_OBJECTS;
3587 oldlen = sizeof(objects);
3588 if (sysctl(mib, 3, &objects, &oldlen, NULL, 0) != 0) e(0);
3589 if (oldlen != sizeof(objects)) e(0);
3593 * Perform post-test checks.
3595 static void
3596 test87_check(void)
3598 unsigned int newnodes, newobjects;
3599 size_t oldlen;
3600 int mib[3];
3602 subtest = 99;
3604 mib[0] = CTL_MINIX;
3605 mib[1] = MINIX_MIB;
3606 mib[2] = MIB_NODES;
3607 oldlen = sizeof(newnodes);
3608 if (sysctl(mib, 3, &newnodes, &oldlen, NULL, 0) != 0) e(0);
3609 if (oldlen != sizeof(newnodes)) e(0);
3612 * Upon the first run, the total number of nodes must actually go down,
3613 * as we destroy number of static nodes. Upon subsequent runs, the
3614 * number of nodes should remain stable. Thus, we can safely test that
3615 * the number of nodes has not gone up as a result of the test.
3617 if (newnodes > nodes) e(0);
3619 mib[2] = MIB_OBJECTS;
3620 oldlen = sizeof(newobjects);
3621 if (sysctl(mib, 3, &newobjects, &oldlen, NULL, 0) != 0) e(0);
3622 if (oldlen != sizeof(newobjects)) e(0);
3625 * The number of dynamically allocated objects should remain the same
3626 * across the test.
3628 if (newobjects != objects) e(0);
3632 * Test program for sysctl(2).
3635 main(int argc, char ** argv)
3637 int i, m;
3639 start(87);
3641 if (argc == 2)
3642 m = atoi(argv[1]);
3643 else
3644 m = 0xFF;
3646 test87_init();
3648 for (i = 0; i < ITERATIONS; i++) {
3649 if (m & 0x001) test87a();
3650 if (m & 0x002) test87b();
3651 if (m & 0x004) test87c();
3652 if (m & 0x008) test87d();
3653 if (m & 0x010) test87e();
3654 if (m & 0x020) test87f();
3655 if (m & 0x040) test87g();
3656 if (m & 0x080) test87h();
3659 test87_check();
3661 quit();