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. */
9 #include <minix/sysctl.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.
29 test_nonroot(void (* proc
)(void))
44 if ((pw
= getpwnam(NONROOT_USER
)) == NULL
) e(0);
46 if (setuid(pw
->pw_uid
) != 0) e(0);
52 if (wait(&status
) != pid
) e(0);
53 if (!WIFEXITED(status
)) e(0);
54 if (WEXITSTATUS(status
) != 0) e(0);
61 * Test basic operations from an unprivileged process.
76 /* Regular reads should succeed. */
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);
85 if (sysctl(mib
, 3, &b
, &oldlen
, NULL
, 0) != 0) e(0);
86 if (oldlen
!= sizeof(b
)) e(0);
89 /* Regular writes should fail. */
91 if (sysctl(mib
, 3, NULL
, NULL
, &b
, sizeof(b
)) != -1) e(0);
92 if (errno
!= EPERM
) e(0);
95 if (sysctl(mib
, 3, &b
, &oldlen
, NULL
, 0) != 0) e(0);
96 if (oldlen
!= sizeof(b
)) 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);
106 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != -1) e(0);
107 if (errno
!= EPERM
) 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
;
117 if (sysctl(mib
, 4, &i
, &oldlen
, NULL
, 0) != -1) e(0);
118 if (errno
!= EPERM
) e(0);
119 if (i
== 12345) e(0);
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);
133 if (sysctl(mib
, 3, NULL
, NULL
, &i
, sizeof(i
)) != 0) e(0);
137 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != 0) e(0);
138 if (oldlen
!= sizeof(i
)) e(0);
143 * Test the basic sysctl(2) interface.
153 int i
, va
[2], lastva
= -1 /*gcc*/, mib
[CTL_MAXNAME
+ 1];
157 mib
[0] = INT_MAX
; /* some root-level identifier that does not exist */
158 for (i
= 1; i
<= CTL_MAXNAME
; 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
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. */
182 if (sysctl(mib
, 1, NULL
, NULL
, NULL
, 0) != -1) e(0);
183 if (errno
!= EISDIR
) e(0);
185 if (sysctl(mib
, 2, NULL
, NULL
, NULL
, 0) != -1) e(0);
186 if (errno
!= EISDIR
) e(0);
188 if (sysctl(mib
, 3, NULL
, NULL
, NULL
, 0) != 0) e(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). */
195 if (sysctl(mib
, 4, NULL
, NULL
, NULL
, 0) != -1) e(0);
196 if (errno
!= ENOTDIR
) e(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. */
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. */
215 if (sysctl(mib
, 3, NULL
, &oldlen
, NULL
, 0) != 0) e(0);
216 if (oldlen
!= sizeof(int)) e(0);
218 if (sysctl(mib
, 3, NULL
, &oldlen
, NULL
, 0) != 0) e(0);
219 if (oldlen
!= sizeof(int)) e(0);
221 if (sysctl(mib
, 3, NULL
, &oldlen
, NULL
, 0) != 0) e(0);
222 if (oldlen
!= sizeof(int)) e(0);
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]);
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
++) {
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);
248 /* Test retrieval with a length that is too long. */
249 oldlen
= sizeof(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);
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);
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.
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]);
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.
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);
307 if (sysctl(mib
, 3, NULL
, &oldlen
, &b
, sizeof(b
)) != 0) e(0);
308 if (oldlen
!= sizeof(b
)) e(0);
311 if (sysctl(mib
, 3, &b
, &oldlen
, NULL
, 0) != 0) e(0);
312 if (oldlen
!= sizeof(b
)) e(0);
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.
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);
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. */
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);
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);
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);
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);
370 if (sysctl(mib
, 3, NULL
, NULL
, &q
, sizeof(q
)) != 0) e(0);
374 if (sysctl(mib
, 3, &q
, &oldlen
, NULL
, 0) != 0) e(0);
375 if (oldlen
!= sizeof(q
)) e(0);
378 /* Test reading and writing a string. */
379 mib
[2] = TEST_STRING
;
380 strlcpy(buf
, "test", sizeof(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
));
397 if (sysctl(mib
, 3, NULL
, &oldlen
, buf
, strlen(buf
) + 1) != 0) e(0);
398 if (oldlen
!= len
+ 1) e(0);
401 memset(buf
, 0x07, sizeof(buf
));
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
));
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
));
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
));
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
));
448 if (sysctl(mib
, 3, NULL
, NULL
, buf
, len
+ 1)) e(0);
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
));
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);
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);
508 for (i
= 0; i
< len
+ 1; i
++)
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
));
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
));
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
));
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
++)
543 if (sysctl(mib
, 3, NULL
, NULL
, buf
, len
) != 0) e(0);
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);
553 if (sysctl(mib
, 3, NULL
, NULL
, buf
, len
) != 0) e(0);
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);
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
;
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.
606 struct sysctlnode scn
[32];
611 /* Query minix.test and make sure we do not get privileged values. */
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]);
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
)
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
)
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
;
665 if (sysctl(mib
, 4, NULL
, &oldlen
, NULL
, 0) != -1) e(0);
666 if (errno
!= EPERM
) e(0);
670 * Test sysctl(2) queries.
675 struct sysctlnode scn
[32];
684 /* We should be able to query the root key. */
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. */
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.
724 if (sysctl(mib
, 3, NULL
, NULL
, &b
, sizeof(b
)) != 0) e(0);
728 if (sysctl(mib
, 3, NULL
, NULL
, &q
, sizeof(q
)) != 0) e(0);
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);
737 count
= len
/ sizeof(scn
[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.
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)
850 if (errno
!= EINVAL
) e(0);
851 if (sysctl(mib
, 2, NULL
, &oldlen
, &scn
[1], sizeof(scn
[1]) + 1) != -1)
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.
885 mib
[2] = TEST_SECRET
;
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. */
917 oldlen
= sizeof(scn
[0]);
918 if (sysctl(mib
, 3, &scn
, &oldlen
, NULL
, 0) != -1) e(0);
919 if (errno
!= ENOENT
) e(0);
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) */
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) */
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.
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
;
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
));
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);
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);
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.
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
;
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.
1006 query_node(const int * path
, unsigned int pathlen
, int id
,
1007 struct sysctlnode
* scn
)
1009 struct sysctlnode scnset
[32];
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
)
1025 if (i
== oldlen
/ sizeof(scnset
[0])) {
1026 if (r
!= 0) e(0); /* if this triggers, make scnset[] bigger! */
1029 memcpy(scn
, &scnset
[i
], sizeof(*scn
));
1034 * Test unprivileged node creation.
1039 struct sysctlnode scn
;
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.
1069 static const uint32_t badflags
[] = {
1070 SYSCTL_VERS_MASK
, SYSCTL_TYPEMASK
, CTLFLAG_PERMANENT
,
1071 CTLFLAG_ROOT
, CTLFLAG_ANYNUMBER
, CTLFLAG_ALIAS
, CTLFLAG_MMAP
,
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];
1090 char buf
[32], seen
[5];
1093 int i
, mib
[CTL_MAXNAME
], id
[3];
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.
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
;
1140 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != 0) e(0);
1141 if (oldlen
!= sizeof(i
)) 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. */
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
;
1229 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != 0) e(0);
1230 if (oldlen
!= sizeof(i
)) 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
;
1243 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != 0) e(0);
1244 if (oldlen
!= sizeof(i
)) 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);
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
;
1265 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != 0) e(0);
1266 if (oldlen
!= sizeof(i
)) 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
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
,
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,
1348 if ((id
[1] = create_node(mib
, 2, &tmpscn
, CTL_CREATE
, "id1", -1,
1350 if ((id
[2] = create_node(mib
, 2, &tmpscn
, CTL_CREATE
, "id2", -1,
1352 if (id
[0] < CREATE_BASE
|| id
[1] < CREATE_BASE
|| id
[2] < CREATE_BASE
)
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],
1361 if (create_node(mib
, 2, &tmpscn
, id
[2], "id1", id
[2],
1363 if (create_node(mib
, 2, &tmpscn
, id
[1], "id0", id
[0],
1365 if (create_node(mib
, 2, &tmpscn
, id
[1], "id2", id
[2],
1368 /* Test name conflicts before and after LL insertion point. */
1369 if (create_node(mib
, 2, &tmpscn
, CTL_CREATE
, "id0", id
[0],
1371 if (create_node(mib
, 2, &tmpscn
, CTL_CREATE
, "id2", id
[2],
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,
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,
1388 /* Ensure that all dynamic nodes show up in a 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);
1399 } else if (scnset
[i
].sysctl_num
== TEST_DYNAMIC
) {
1400 if (strcmp(scnset
[i
].sysctl_name
, "dynamic")) e(0);
1402 } else if (scnset
[i
].sysctl_num
== id
[0]) {
1403 if (strcmp(scnset
[i
].sysctl_name
, "id0")) e(0);
1405 } else if (scnset
[i
].sysctl_num
== id
[1]) {
1406 if (strcmp(scnset
[i
].sysctl_name
, "id1")) e(0);
1408 } else if (scnset
[i
].sysctl_num
== id
[2]) {
1409 if (strcmp(scnset
[i
].sysctl_name
, "id2")) e(0);
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);
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
;
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);
1471 if (sysctl(mib
, 3, NULL
, NULL
, &b
, sizeof(b
)) != 0) e(0);
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
;
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
;
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
;
1515 if (sysctl(mib
, 3, NULL
, NULL
, &scn
, sizeof(scn
)) != -1) e(0);
1516 if (errno
!= EINVAL
) e(0);
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);
1524 scn
.sysctl_data
= &b
;
1525 if (sysctl(mib
, 3, NULL
, NULL
, &scn
, sizeof(scn
)) != 0) e(0);
1527 mib
[2] = TEST_DYNAMIC
;
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);
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);
1540 if (sysctl(mib
, 3, NULL
, NULL
, &b
, sizeof(b
)) != 0) e(0);
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
;
1561 if (sysctl(mib
, 3, &q
, &oldlen
, NULL
, 0) != 0) e(0);
1562 if (oldlen
!= sizeof(q
)) e(0);
1566 if (sysctl(mib
, 3, NULL
, NULL
, &q
, sizeof(q
)) != 0) e(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
;
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);
1607 scn
.sysctl_data
= &q
;
1608 if (sysctl(mib
, 3, NULL
, NULL
, &scn
, sizeof(scn
)) != 0) e(0);
1610 mib
[2] = TEST_DYNAMIC
;
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);
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);
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
++)
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
));
1906 scn
.sysctl_num
= i
- 3;
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",
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
;
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);
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
));
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
;
1989 if (create_node(mib
, 3, &scn
, TEST_DYNAMIC
, "d", -1, NULL
) != -1) e(0);
1990 if (errno
!= ENOTDIR
) e(0);
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.
2012 struct sysctlnode scn
;
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.
2038 struct sysctlnode scn
, oldscn
, newscn
, tmpscn
;
2041 int i
, r
, mib
[4], id
[15];
2046 mib
[1] = MINIX_TEST
;
2047 (void)destroy_node(mib
, 2, TEST_DYNAMIC
);
2049 /* Start with the path-related error code tests this time. */
2051 if (destroy_node(mib
, 2, TEST_DYNAMIC
) != -1) e(0);
2052 if (errno
!= ENOENT
) e(0);
2054 mib
[1] = MINIX_TEST
;
2056 if (destroy_node(mib
, 3, TEST_DYNAMIC
) != -1) e(0);
2057 if (errno
!= ENOTDIR
) e(0);
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
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
;
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
;
2189 if (sysctl(mib
, 3, &i
, &oldlen
, NULL
, 0) != -1) e(0);
2190 if (errno
!= ENOENT
) e(0);
2191 if (oldlen
!= 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
;
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)
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,
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,
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
2278 describe_node(const int * path
, unsigned int pathlen
, int id
,
2279 const char * desc
, int set
)
2282 struct sysctlnode scn
;
2283 struct sysctldesc
*scd
;
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
;
2297 scn
.sysctl_desc
= desc
;
2298 if (sysctl(mib
, pathlen
+ 1, buf
, &oldlen
, &scn
, sizeof(scn
)) != 0)
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);
2314 * Test getting descriptions from an unprivileged process.
2319 static char buf
[2048];
2321 struct sysctldesc
*scd
, *endscd
;
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.
2386 static char buf
[2048];
2388 struct sysctldesc
*scd
, *endscd
;
2389 struct sysctlnode scn
;
2390 size_t oldlen
, len
, sublen
;
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);
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
) {
2431 if (strcmp(scd
->descr_str
, "Value test field")) e(0);
2434 if (strcmp(scd
->descr_str
, "Boolean test field")) e(0);
2437 if (strcmp(scd
->descr_str
, "Quad test field")) e(0);
2440 if (strcmp(scd
->descr_str
, "String test field")) e(0);
2443 if (strcmp(scd
->descr_str
, "Private test field")) e(0);
2446 if (strcmp(scd
->descr_str
, "Private subtree")) e(0);
2449 if (strcmp(scd
->descr_str
, "")) e(0);
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
));
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",
2528 if (describe_node(mib
, 2, TEST_SECRET
, "Private subtree",
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. */
2541 if (describe_node(mib
, 2, TEST_DYNAMIC
, "", 0) != -1) e(0);
2542 if (errno
!= ENOENT
) e(0);
2544 mib
[1] = MINIX_TEST
;
2546 if (describe_node(mib
, 3, TEST_DYNAMIC
, "", 0) != -1) e(0);
2547 if (errno
!= ENOTDIR
) e(0);
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.
2564 struct sysctlnode scn
;
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.
2586 static char buf
[2048];
2588 struct sysctlnode scn
, tmpscn
, scnset
[3];
2589 struct sysctldesc
*scd
, *endscd
, *scdset
[2];
2591 int i
, r
, mib
[4], id
[2];
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.
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
];
2630 while (scd
< endscd
) {
2631 if (scd
->descr_num
== TEST_DYNAMIC
) {
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);
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
];
2678 while (scd
< endscd
) {
2679 if (scd
->descr_num
== TEST_DYNAMIC
) {
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);
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);
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)
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);
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);
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);
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)
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,
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);
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,
2911 memset(buf
, 0, sizeof(buf
));
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,
2924 memset(buf
, 0, sizeof(buf
));
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,
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.
2953 test_buf(char * buf
, unsigned char c
, size_t size
, int set
)
2958 ptr
= (unsigned char *)buf
;
2960 for (step
= 1; size
> 0; size
--) {
2963 else if (*ptr
++ != c
)
2978 * Test large data sizes from an unprivileged process.
2984 size_t size
, oldlen
;
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
);
2994 mib
[1] = MINIX_TEST
;
2995 mib
[2] = TEST_DYNAMIC
;
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);
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.
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.
3041 struct sysctlnode scn
, newscn
;
3043 size_t pgsz
, size
, oldlen
;
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();
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. */
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 */
3078 if (sysctl(mib
, 3, NULL
, NULL
, &scn
, sizeof(scn
)) != -1) e(0);
3079 if (errno
!= EFAULT
) e(0);
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
);
3166 if (sysctl(mib
, 3, &ptr
[3], &oldlen
, NULL
, 0) != -1) e(0);
3167 if (errno
!= EFAULT
) e(0);
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
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
);
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
);
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
;
3218 * Test setting a short but faulty string, ensuring that no partial
3219 * update on the field contents takes place.
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);
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);
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);
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
);
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);
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.
3308 check_version(const int * path
, unsigned int pathlen
, int id
, uint32_t ver
)
3310 struct sysctlnode scn
;
3311 struct sysctldesc scd
;
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
;
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.
3342 struct sysctlnode scn
, oldscn
;
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.
3358 * Test versioning with node creation.
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. */
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. */
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);
3443 if (check_version(mib
, 3, id
[2], ver
[2]) != 0) e(0);
3446 * Test versioning with node queries.
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);
3488 if (check_version(mib
, 3, id
[3], ver
[3]) != 0) e(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);
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];
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.
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);
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.
3598 unsigned int newnodes
, newobjects
;
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
3628 if (newobjects
!= objects
) e(0);
3632 * Test program for sysctl(2).
3635 main(int argc
, char ** argv
)
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();