1 /* $NetBSD: kern_sysctl.c,v 1.210 2007/08/15 12:07:34 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Brown. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1982, 1986, 1989, 1993 41 * The Regents of the University of California. All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * Mike Karels at Berkeley Software Design, Inc. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95 71 */ 72 73 /* 74 * sysctl system call. 75 */ 76 77 #include <sys/cdefs.h> 78 __KERNEL_RCSID(0, "$NetBSD: kern_sysctl.c,v 1.210 2007/08/15 12:07:34 ad Exp $"); 79 80 #include "opt_defcorename.h" 81 #include "ksyms.h" 82 83 #include <sys/param.h> 84 #define __COMPAT_SYSCTL 85 #include <sys/sysctl.h> 86 #include <sys/systm.h> 87 #include <sys/buf.h> 88 #include <sys/ksyms.h> 89 #include <sys/malloc.h> 90 #include <sys/mount.h> 91 #include <sys/syscallargs.h> 92 #include <sys/kauth.h> 93 #include <sys/ktrace.h> 94 #include <machine/stdarg.h> 95 96 #define MAXDESCLEN 1024 97 MALLOC_DEFINE(M_SYSCTLNODE, "sysctlnode", "sysctl node structures"); 98 MALLOC_DEFINE(M_SYSCTLDATA, "sysctldata", "misc sysctl data"); 99 100 static int sysctl_mmap(SYSCTLFN_PROTO); 101 static int sysctl_alloc(struct sysctlnode *, int); 102 static int sysctl_realloc(struct sysctlnode *); 103 104 static int sysctl_cvt_in(struct lwp *, int *, const void *, size_t, 105 struct sysctlnode *); 106 static int sysctl_cvt_out(struct lwp *, int, const struct sysctlnode *, 107 void *, size_t, size_t *); 108 109 static int sysctl_log_add(struct sysctllog **, const struct sysctlnode *); 110 static int sysctl_log_realloc(struct sysctllog *); 111 112 struct sysctllog { 113 const struct sysctlnode *log_root; 114 int *log_num; 115 int log_size, log_left; 116 }; 117 118 /* 119 * the "root" of the new sysctl tree 120 */ 121 struct sysctlnode sysctl_root = { 122 .sysctl_flags = SYSCTL_VERSION| 123 CTLFLAG_ROOT|CTLFLAG_READWRITE| 124 CTLTYPE_NODE, 125 .sysctl_num = 0, 126 /* 127 * XXX once all ports are on gcc3, we can get rid of this 128 * ugliness and simply make it into 129 * 130 * .sysctl_size = sizeof(struct sysctlnode), 131 */ 132 sysc_init_field(_sysctl_size, sizeof(struct sysctlnode)), 133 .sysctl_name = "(root)", 134 }; 135 136 /* 137 * link set of functions that add nodes at boot time (see also 138 * sysctl_buildtree()) 139 */ 140 __link_set_decl(sysctl_funcs, sysctl_setup_func); 141 142 /* 143 * The `sysctl_lock' is intended to serialize access to the sysctl 144 * tree. Given that it is now (a) dynamic, and (b) most consumers of 145 * sysctl are going to be copying data out, the old `sysctl_memlock' 146 * has been `upgraded' to simply guard the whole tree. 147 * 148 * The two new data here are to keep track of the locked chunk of 149 * memory, if there is one, so that it can be released more easily 150 * from anywhere. 151 */ 152 krwlock_t sysctl_treelock; 153 void *sysctl_memaddr; 154 size_t sysctl_memsize; 155 156 /* 157 * Attributes stored in the kernel. 158 */ 159 char hostname[MAXHOSTNAMELEN]; 160 int hostnamelen; 161 162 char domainname[MAXHOSTNAMELEN]; 163 int domainnamelen; 164 165 long hostid; 166 167 #ifndef DEFCORENAME 168 #define DEFCORENAME "%n.core" 169 #endif 170 char defcorename[MAXPATHLEN] = DEFCORENAME; 171 172 /* 173 * ******************************************************************** 174 * Section 0: Some simple glue 175 * ******************************************************************** 176 * By wrapping copyin(), copyout(), and copyinstr() like this, we can 177 * stop caring about who's calling us and simplify some code a bunch. 178 * ******************************************************************** 179 */ 180 static inline int 181 sysctl_copyin(struct lwp *l, const void *uaddr, void *kaddr, size_t len) 182 { 183 int error; 184 185 if (l != NULL) { 186 error = copyin(uaddr, kaddr, len); 187 ktrmibio(-1, UIO_WRITE, uaddr, len, error); 188 } else { 189 error = kcopy(uaddr, kaddr, len); 190 } 191 192 return error; 193 } 194 195 static inline int 196 sysctl_copyout(struct lwp *l, const void *kaddr, void *uaddr, size_t len) 197 { 198 int error; 199 200 if (l != NULL) { 201 error = copyout(kaddr, uaddr, len); 202 ktrmibio(-1, UIO_READ, uaddr, len, error); 203 } else { 204 error = kcopy(kaddr, uaddr, len); 205 } 206 207 return error; 208 } 209 210 static inline int 211 sysctl_copyinstr(struct lwp *l, const void *uaddr, void *kaddr, 212 size_t len, size_t *done) 213 { 214 int error; 215 216 if (l != NULL) { 217 error = copyinstr(uaddr, kaddr, len, done); 218 ktrmibio(-1, UIO_WRITE, uaddr, len, error); 219 } else { 220 error = copystr(uaddr, kaddr, len, done); 221 } 222 223 return error; 224 } 225 226 /* 227 * ******************************************************************** 228 * Initialize sysctl subsystem. 229 * ******************************************************************** 230 */ 231 void 232 sysctl_init(void) 233 { 234 sysctl_setup_func * const *sysctl_setup, f; 235 236 rw_init(&sysctl_treelock); 237 238 /* 239 * dynamic mib numbers start here 240 */ 241 sysctl_root.sysctl_num = CREATE_BASE; 242 243 __link_set_foreach(sysctl_setup, sysctl_funcs) { 244 /* 245 * XXX - why do i have to coerce the pointers like this? 246 */ 247 f = (void*)*sysctl_setup; 248 (*f)(NULL); 249 } 250 251 /* 252 * setting this means no more permanent nodes can be added, 253 * trees that claim to be readonly at the root now are, and if 254 * the main tree is readonly, *everything* is. 255 */ 256 sysctl_root.sysctl_flags |= CTLFLAG_PERMANENT; 257 258 } 259 260 /* 261 * ******************************************************************** 262 * The main native sysctl system call itself. 263 * ******************************************************************** 264 */ 265 int 266 sys___sysctl(struct lwp *l, void *v, register_t *retval) 267 { 268 struct sys___sysctl_args /* { 269 syscallarg(const int *) name; 270 syscallarg(u_int) namelen; 271 syscallarg(void *) old; 272 syscallarg(size_t *) oldlenp; 273 syscallarg(const void *) new; 274 syscallarg(size_t) newlen; 275 } */ *uap = v; 276 int error, nerror, name[CTL_MAXNAME]; 277 size_t oldlen, savelen, *oldlenp; 278 279 /* 280 * get oldlen 281 */ 282 oldlen = 0; 283 oldlenp = SCARG(uap, oldlenp); 284 if (oldlenp != NULL) { 285 error = copyin(oldlenp, &oldlen, sizeof(oldlen)); 286 if (error) 287 return (error); 288 } 289 savelen = oldlen; 290 291 /* 292 * top-level sysctl names may or may not be non-terminal, but 293 * we don't care 294 */ 295 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 1) 296 return (EINVAL); 297 error = copyin(SCARG(uap, name), &name, 298 SCARG(uap, namelen) * sizeof(int)); 299 if (error) 300 return (error); 301 302 ktrmib(name, SCARG(uap, namelen)); 303 304 /* 305 * wire old so that copyout() is less likely to fail? 306 */ 307 error = sysctl_lock(l, SCARG(uap, old), savelen); 308 if (error) 309 return (error); 310 311 /* 312 * do sysctl work (NULL means main built-in default tree) 313 */ 314 error = sysctl_dispatch(&name[0], SCARG(uap, namelen), 315 SCARG(uap, old), &oldlen, 316 SCARG(uap, new), SCARG(uap, newlen), 317 &name[0], l, NULL); 318 319 /* 320 * release the sysctl lock 321 */ 322 sysctl_unlock(l); 323 324 /* 325 * set caller's oldlen to new value even in the face of an 326 * error (if this gets an error and they didn't have one, they 327 * get this one) 328 */ 329 if (oldlenp) { 330 nerror = copyout(&oldlen, oldlenp, sizeof(oldlen)); 331 if (error == 0) 332 error = nerror; 333 } 334 335 /* 336 * if the only problem is that we weren't given enough space, 337 * that's an ENOMEM error 338 */ 339 if (error == 0 && SCARG(uap, old) != NULL && savelen < oldlen) 340 error = ENOMEM; 341 342 return (error); 343 } 344 345 /* 346 * ******************************************************************** 347 * Section 1: How the tree is used 348 * ******************************************************************** 349 * Implementations of sysctl for emulations should typically need only 350 * these three functions in this order: lock the tree, dispatch 351 * request into it, unlock the tree. 352 * ******************************************************************** 353 */ 354 int 355 sysctl_lock(struct lwp *l, void *oldp, size_t savelen) 356 { 357 int error; 358 359 rw_enter(&sysctl_treelock, RW_WRITER); /* XXX write */ 360 361 if (l != NULL && oldp != NULL && savelen) { 362 363 /* 364 * be lazy - memory is locked for short time only, so 365 * just do a basic check against system limit 366 */ 367 368 if (uvmexp.wired + atop(savelen) > uvmexp.wiredmax) { 369 rw_exit(&sysctl_treelock); 370 return (ENOMEM); 371 } 372 error = uvm_vslock(l->l_proc->p_vmspace, oldp, savelen, 373 VM_PROT_WRITE); 374 if (error) { 375 rw_exit(&sysctl_treelock); 376 return (error); 377 } 378 sysctl_memaddr = oldp; 379 sysctl_memsize = savelen; 380 } 381 382 return (0); 383 } 384 385 /* 386 * ******************************************************************** 387 * the main sysctl dispatch routine. scans the given tree and picks a 388 * function to call based on what it finds. 389 * ******************************************************************** 390 */ 391 int 392 sysctl_dispatch(SYSCTLFN_ARGS) 393 { 394 int error; 395 sysctlfn fn; 396 int ni; 397 398 if (rnode && SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 399 printf("sysctl_dispatch: rnode %p wrong version\n", rnode); 400 error = EINVAL; 401 goto out; 402 } 403 404 fn = NULL; 405 error = sysctl_locate(l, name, namelen, &rnode, &ni); 406 407 if (rnode->sysctl_func != NULL) { 408 /* 409 * the node we ended up at has a function, so call it. it can 410 * hand off to query or create if it wants to. 411 */ 412 fn = rnode->sysctl_func; 413 } else if (error == 0) { 414 /* 415 * we found the node they were looking for, so do a lookup. 416 */ 417 fn = (sysctlfn)sysctl_lookup; /* XXX may write to rnode */ 418 } else if (error == ENOENT && (ni + 1) == namelen && name[ni] < 0) { 419 /* 420 * prospective parent node found, but the terminal node was 421 * not. generic operations associate with the parent. 422 */ 423 switch (name[ni]) { 424 case CTL_QUERY: 425 fn = sysctl_query; 426 break; 427 case CTL_CREATE: 428 #if NKSYMS > 0 429 case CTL_CREATESYM: 430 #endif /* NKSYMS > 0 */ 431 fn = (sysctlfn)sysctl_create; /* we own the rnode */ 432 break; 433 case CTL_DESTROY: 434 fn = (sysctlfn)sysctl_destroy; /* we own the rnode */ 435 break; 436 case CTL_MMAP: 437 fn = (sysctlfn)sysctl_mmap; /* we own the rnode */ 438 break; 439 case CTL_DESCRIBE: 440 fn = sysctl_describe; 441 break; 442 default: 443 error = EOPNOTSUPP; 444 break; 445 } 446 } 447 448 /* 449 * after all of that, maybe we found someone who knows how to 450 * get us what we want? 451 */ 452 if (fn != NULL) 453 error = (*fn)(name + ni, namelen - ni, oldp, oldlenp, 454 newp, newlen, name, l, rnode); 455 else if (error == 0) 456 error = EOPNOTSUPP; 457 458 out: 459 return (error); 460 } 461 462 /* 463 * ******************************************************************** 464 * Releases the tree lock. Note that if uvm_vslock() was called when 465 * the lock was taken, we release that memory now. By keeping track 466 * of where and how much by ourselves, the lock can be released much 467 * more easily from anywhere. 468 * ******************************************************************** 469 */ 470 void 471 sysctl_unlock(struct lwp *l) 472 { 473 474 if (l != NULL && sysctl_memsize != 0) { 475 uvm_vsunlock(l->l_proc->p_vmspace, sysctl_memaddr, 476 sysctl_memsize); 477 sysctl_memsize = 0; 478 } 479 480 rw_exit(&sysctl_treelock); /* XXX write */ 481 } 482 483 /* 484 * ******************************************************************** 485 * Section 2: The main tree interfaces 486 * ******************************************************************** 487 * This is how sysctl_dispatch() does its work, and you can too, by 488 * calling these routines from helpers (though typically only 489 * sysctl_lookup() will be used). The tree MUST BE LOCKED when these 490 * are called. 491 * ******************************************************************** 492 */ 493 494 /* 495 * sysctl_locate -- Finds the node matching the given mib under the 496 * given tree (via rv). If no tree is given, we fall back to the 497 * native tree. The current process (via l) is used for access 498 * control on the tree (some nodes may be traversable only by root) and 499 * on return, nip will show how many numbers in the mib were consumed. 500 */ 501 int 502 sysctl_locate(struct lwp *l, const int *name, u_int namelen, 503 const struct sysctlnode **rnode, int *nip) 504 { 505 const struct sysctlnode *node, *pnode; 506 int tn, si, ni, error, alias; 507 508 /* 509 * basic checks and setup 510 */ 511 if (*rnode == NULL) 512 *rnode = &sysctl_root; 513 if (nip) 514 *nip = 0; 515 if (namelen == 0) 516 return (0); 517 518 /* 519 * search starts from "root" 520 */ 521 pnode = *rnode; 522 if (SYSCTL_VERS(pnode->sysctl_flags) != SYSCTL_VERSION) { 523 printf("sysctl_locate: pnode %p wrong version\n", pnode); 524 return (EINVAL); 525 } 526 node = pnode->sysctl_child; 527 error = 0; 528 529 /* 530 * scan for node to which new node should be attached 531 */ 532 for (ni = 0; ni < namelen; ni++) { 533 /* 534 * walked off bottom of tree 535 */ 536 if (node == NULL) { 537 if (SYSCTL_TYPE(pnode->sysctl_flags) == CTLTYPE_NODE) 538 error = ENOENT; 539 else 540 error = ENOTDIR; 541 break; 542 } 543 /* 544 * can anyone traverse this node or only root? 545 */ 546 if (l != NULL && (pnode->sysctl_flags & CTLFLAG_PRIVATE) && 547 (error = kauth_authorize_system(l->l_cred, 548 KAUTH_SYSTEM_SYSCTL, KAUTH_REQ_SYSTEM_SYSCTL_PRVT, 549 NULL, NULL, NULL)) != 0) 550 return (error); 551 /* 552 * find a child node with the right number 553 */ 554 tn = name[ni]; 555 alias = 0; 556 557 si = 0; 558 /* 559 * Note: ANYNUMBER only matches positive integers. 560 * Since ANYNUMBER is only permitted on single-node 561 * sub-trees (eg proc), check before the loop and skip 562 * it if we can. 563 */ 564 if ((node[si].sysctl_flags & CTLFLAG_ANYNUMBER) && (tn >= 0)) 565 goto foundit; 566 for (; si < pnode->sysctl_clen; si++) { 567 if (node[si].sysctl_num == tn) { 568 if (node[si].sysctl_flags & CTLFLAG_ALIAS) { 569 if (alias++ == 4) 570 break; 571 else { 572 tn = node[si].sysctl_alias; 573 si = -1; 574 } 575 } else 576 goto foundit; 577 } 578 } 579 /* 580 * if we ran off the end, it obviously doesn't exist 581 */ 582 error = ENOENT; 583 break; 584 585 /* 586 * so far so good, move on down the line 587 */ 588 foundit: 589 pnode = &node[si]; 590 if (SYSCTL_TYPE(pnode->sysctl_flags) == CTLTYPE_NODE) 591 node = node[si].sysctl_child; 592 else 593 node = NULL; 594 } 595 596 *rnode = pnode; 597 if (nip) 598 *nip = ni; 599 600 return (error); 601 } 602 603 /* 604 * sysctl_query -- The auto-discovery engine. Copies out the structs 605 * describing nodes under the given node and handles overlay trees. 606 */ 607 int 608 sysctl_query(SYSCTLFN_ARGS) 609 { 610 int error, ni, elim, v; 611 size_t out, left, t; 612 const struct sysctlnode *enode, *onode; 613 struct sysctlnode qnode; 614 615 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 616 printf("sysctl_query: rnode %p wrong version\n", rnode); 617 return (EINVAL); 618 } 619 620 if (SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE) 621 return (ENOTDIR); 622 if (namelen != 1 || name[0] != CTL_QUERY) 623 return (EINVAL); 624 625 error = 0; 626 out = 0; 627 left = *oldlenp; 628 elim = 0; 629 enode = NULL; 630 631 /* 632 * translate the given request to a current node 633 */ 634 error = sysctl_cvt_in(l, &v, newp, newlen, &qnode); 635 if (error) 636 return (error); 637 638 /* 639 * if the request specifies a version, check it 640 */ 641 if (qnode.sysctl_ver != 0) { 642 enode = rnode; 643 if (qnode.sysctl_ver != enode->sysctl_ver && 644 qnode.sysctl_ver != sysctl_rootof(enode)->sysctl_ver) 645 return (EINVAL); 646 } 647 648 /* 649 * process has overlay tree 650 */ 651 if (l && l->l_proc->p_emul->e_sysctlovly) { 652 enode = l->l_proc->p_emul->e_sysctlovly; 653 elim = (name - oname); 654 error = sysctl_locate(l, oname, elim, &enode, NULL); 655 if (error == 0) { 656 /* ah, found parent in overlay */ 657 elim = enode->sysctl_clen; 658 enode = enode->sysctl_child; 659 } else { 660 error = 0; 661 elim = 0; 662 enode = NULL; 663 } 664 } 665 666 for (ni = 0; ni < rnode->sysctl_clen; ni++) { 667 onode = &rnode->sysctl_child[ni]; 668 if (enode && enode->sysctl_num == onode->sysctl_num) { 669 if (SYSCTL_TYPE(enode->sysctl_flags) != CTLTYPE_NODE) 670 onode = enode; 671 if (--elim > 0) 672 enode++; 673 else 674 enode = NULL; 675 } 676 error = sysctl_cvt_out(l, v, onode, oldp, left, &t); 677 if (error) 678 return (error); 679 if (oldp != NULL) 680 oldp = (char*)oldp + t; 681 out += t; 682 left -= MIN(left, t); 683 } 684 685 /* 686 * overlay trees *MUST* be entirely consumed 687 */ 688 KASSERT(enode == NULL); 689 690 *oldlenp = out; 691 692 return (error); 693 } 694 695 /* 696 * sysctl_create -- Adds a node (the description of which is taken 697 * from newp) to the tree, returning a copy of it in the space pointed 698 * to by oldp. In the event that the requested slot is already taken 699 * (either by name or by number), the offending node is returned 700 * instead. Yes, this is complex, but we want to make sure everything 701 * is proper. 702 */ 703 #ifdef SYSCTL_DEBUG_CREATE 704 int _sysctl_create(SYSCTLFN_ARGS); 705 int 706 _sysctl_create(SYSCTLFN_ARGS) 707 #else 708 int 709 sysctl_create(SYSCTLFN_ARGS) 710 #endif 711 { 712 struct sysctlnode nnode, *node, *pnode; 713 int error, ni, at, nm, type, sz, flags, anum, v; 714 void *own; 715 716 error = 0; 717 own = NULL; 718 anum = -1; 719 720 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 721 printf("sysctl_create: rnode %p wrong version\n", rnode); 722 return (EINVAL); 723 } 724 725 if (namelen != 1 || (name[namelen - 1] != CTL_CREATE 726 #if NKSYMS > 0 727 && name[namelen - 1] != CTL_CREATESYM 728 #endif /* NKSYMS > 0 */ 729 )) 730 return (EINVAL); 731 732 /* 733 * processes can only add nodes at securelevel 0, must be 734 * root, and can't add nodes to a parent that's not writeable 735 */ 736 if (l != NULL) { 737 #ifndef SYSCTL_DISALLOW_CREATE 738 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL, 739 KAUTH_REQ_SYSTEM_SYSCTL_ADD, NULL, NULL, NULL); 740 if (error) 741 return (error); 742 if (!(rnode->sysctl_flags & CTLFLAG_READWRITE)) 743 #endif /* SYSCTL_DISALLOW_CREATE */ 744 return (EPERM); 745 } 746 747 /* 748 * nothing can add a node if: 749 * we've finished initial set up and 750 * the tree itself is not writeable or 751 * the entire sysctl system is not writeable 752 */ 753 if ((sysctl_root.sysctl_flags & CTLFLAG_PERMANENT) && 754 (!(sysctl_rootof(rnode)->sysctl_flags & CTLFLAG_READWRITE) || 755 !(sysctl_root.sysctl_flags & CTLFLAG_READWRITE))) 756 return (EPERM); 757 758 /* 759 * it must be a "node", not a "int" or something 760 */ 761 if (SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE) 762 return (ENOTDIR); 763 if (rnode->sysctl_flags & CTLFLAG_ALIAS) { 764 printf("sysctl_create: attempt to add node to aliased " 765 "node %p\n", rnode); 766 return (EINVAL); 767 } 768 pnode = __UNCONST(rnode); /* we are adding children to this node */ 769 770 if (newp == NULL) 771 return (EINVAL); 772 error = sysctl_cvt_in(l, &v, newp, newlen, &nnode); 773 if (error) 774 return (error); 775 776 /* 777 * nodes passed in don't *have* parents 778 */ 779 if (nnode.sysctl_parent != NULL) 780 return (EINVAL); 781 782 /* 783 * if we are indeed adding it, it should be a "good" name and 784 * number 785 */ 786 nm = nnode.sysctl_num; 787 #if NKSYMS > 0 788 if (nm == CTL_CREATESYM) 789 nm = CTL_CREATE; 790 #endif /* NKSYMS > 0 */ 791 if (nm < 0 && nm != CTL_CREATE) 792 return (EINVAL); 793 sz = 0; 794 795 /* 796 * the name can't start with a digit 797 */ 798 if (nnode.sysctl_name[sz] >= '0' && 799 nnode.sysctl_name[sz] <= '9') 800 return (EINVAL); 801 802 /* 803 * the name must be only alphanumerics or - or _, longer than 804 * 0 bytes and less that SYSCTL_NAMELEN 805 */ 806 while (sz < SYSCTL_NAMELEN && nnode.sysctl_name[sz] != '\0') { 807 if ((nnode.sysctl_name[sz] >= '0' && 808 nnode.sysctl_name[sz] <= '9') || 809 (nnode.sysctl_name[sz] >= 'A' && 810 nnode.sysctl_name[sz] <= 'Z') || 811 (nnode.sysctl_name[sz] >= 'a' && 812 nnode.sysctl_name[sz] <= 'z') || 813 nnode.sysctl_name[sz] == '-' || 814 nnode.sysctl_name[sz] == '_') 815 sz++; 816 else 817 return (EINVAL); 818 } 819 if (sz == 0 || sz == SYSCTL_NAMELEN) 820 return (EINVAL); 821 822 /* 823 * various checks revolve around size vs type, etc 824 */ 825 type = SYSCTL_TYPE(nnode.sysctl_flags); 826 flags = SYSCTL_FLAGS(nnode.sysctl_flags); 827 sz = nnode.sysctl_size; 828 829 /* 830 * find out if there's a collision, and if so, let the caller 831 * know what they collided with 832 */ 833 node = pnode->sysctl_child; 834 at = 0; 835 if (node) { 836 if ((flags | node->sysctl_flags) & CTLFLAG_ANYNUMBER) 837 /* No siblings for a CTLFLAG_ANYNUMBER node */ 838 return EINVAL; 839 for (ni = 0; ni < pnode->sysctl_clen; ni++) { 840 if (nm == node[ni].sysctl_num || 841 strcmp(nnode.sysctl_name, node[ni].sysctl_name) == 0) { 842 /* 843 * ignore error here, since we 844 * are already fixed on EEXIST 845 */ 846 (void)sysctl_cvt_out(l, v, &node[ni], oldp, 847 *oldlenp, oldlenp); 848 return (EEXIST); 849 } 850 if (nm > node[ni].sysctl_num) 851 at++; 852 } 853 } 854 855 /* 856 * use sysctl_ver to add to the tree iff it hasn't changed 857 */ 858 if (nnode.sysctl_ver != 0) { 859 /* 860 * a specified value must match either the parent 861 * node's version or the root node's version 862 */ 863 if (nnode.sysctl_ver != sysctl_rootof(rnode)->sysctl_ver && 864 nnode.sysctl_ver != rnode->sysctl_ver) { 865 return (EINVAL); 866 } 867 } 868 869 /* 870 * only the kernel can assign functions to entries 871 */ 872 if (l != NULL && nnode.sysctl_func != NULL) 873 return (EPERM); 874 875 /* 876 * only the kernel can create permanent entries, and only then 877 * before the kernel is finished setting itself up 878 */ 879 if (l != NULL && (flags & ~SYSCTL_USERFLAGS)) 880 return (EPERM); 881 if ((flags & CTLFLAG_PERMANENT) & 882 (sysctl_root.sysctl_flags & CTLFLAG_PERMANENT)) 883 return (EPERM); 884 if ((flags & (CTLFLAG_OWNDATA | CTLFLAG_IMMEDIATE)) == 885 (CTLFLAG_OWNDATA | CTLFLAG_IMMEDIATE)) 886 return (EINVAL); 887 if ((flags & CTLFLAG_IMMEDIATE) && 888 type != CTLTYPE_INT && type != CTLTYPE_QUAD) 889 return (EINVAL); 890 891 /* 892 * check size, or set it if unset and we can figure it out. 893 * kernel created nodes are allowed to have a function instead 894 * of a size (or a data pointer). 895 */ 896 switch (type) { 897 case CTLTYPE_NODE: 898 /* 899 * only *i* can assert the size of a node 900 */ 901 if (flags & CTLFLAG_ALIAS) { 902 anum = nnode.sysctl_alias; 903 if (anum < 0) 904 return (EINVAL); 905 nnode.sysctl_alias = 0; 906 } 907 if (sz != 0 || nnode.sysctl_data != NULL) 908 return (EINVAL); 909 if (nnode.sysctl_csize != 0 || 910 nnode.sysctl_clen != 0 || 911 nnode.sysctl_child != 0) 912 return (EINVAL); 913 if (flags & CTLFLAG_OWNDATA) 914 return (EINVAL); 915 sz = sizeof(struct sysctlnode); 916 break; 917 case CTLTYPE_INT: 918 /* 919 * since an int is an int, if the size is not given or 920 * is wrong, we can "int-uit" it. 921 */ 922 if (sz != 0 && sz != sizeof(int)) 923 return (EINVAL); 924 sz = sizeof(int); 925 break; 926 case CTLTYPE_STRING: 927 /* 928 * strings are a little more tricky 929 */ 930 if (sz == 0) { 931 if (l == NULL) { 932 if (nnode.sysctl_func == NULL) { 933 if (nnode.sysctl_data == NULL) 934 return (EINVAL); 935 else 936 sz = strlen(nnode.sysctl_data) + 937 1; 938 } 939 } else if (nnode.sysctl_data == NULL && 940 flags & CTLFLAG_OWNDATA) { 941 return (EINVAL); 942 } else { 943 char *vp, *e; 944 size_t s; 945 946 /* 947 * we want a rough idea of what the 948 * size is now 949 */ 950 vp = malloc(PAGE_SIZE, M_SYSCTLDATA, 951 M_WAITOK|M_CANFAIL); 952 if (vp == NULL) 953 return (ENOMEM); 954 e = nnode.sysctl_data; 955 do { 956 error = copyinstr(e, vp, PAGE_SIZE, &s); 957 if (error) { 958 if (error != ENAMETOOLONG) { 959 free(vp, M_SYSCTLDATA); 960 return (error); 961 } 962 e += PAGE_SIZE; 963 if ((e - 32 * PAGE_SIZE) > 964 (char*)nnode.sysctl_data) { 965 free(vp, M_SYSCTLDATA); 966 return (ERANGE); 967 } 968 } 969 } while (error != 0); 970 sz = s + (e - (char*)nnode.sysctl_data); 971 free(vp, M_SYSCTLDATA); 972 } 973 } 974 break; 975 case CTLTYPE_QUAD: 976 if (sz != 0 && sz != sizeof(u_quad_t)) 977 return (EINVAL); 978 sz = sizeof(u_quad_t); 979 break; 980 case CTLTYPE_STRUCT: 981 if (sz == 0) { 982 if (l != NULL || nnode.sysctl_func == NULL) 983 return (EINVAL); 984 if (flags & CTLFLAG_OWNDATA) 985 return (EINVAL); 986 } 987 break; 988 default: 989 return (EINVAL); 990 } 991 992 /* 993 * at this point, if sz is zero, we *must* have a 994 * function to go with it and we can't own it. 995 */ 996 997 /* 998 * l ptr own 999 * 0 0 0 -> EINVAL (if no func) 1000 * 0 0 1 -> own 1001 * 0 1 0 -> kptr 1002 * 0 1 1 -> kptr 1003 * 1 0 0 -> EINVAL 1004 * 1 0 1 -> own 1005 * 1 1 0 -> kptr, no own (fault on lookup) 1006 * 1 1 1 -> uptr, own 1007 */ 1008 if (type != CTLTYPE_NODE) { 1009 if (sz != 0) { 1010 if (flags & CTLFLAG_OWNDATA) { 1011 own = malloc(sz, M_SYSCTLDATA, 1012 M_WAITOK|M_CANFAIL); 1013 if (own == NULL) 1014 return ENOMEM; 1015 if (nnode.sysctl_data == NULL) 1016 memset(own, 0, sz); 1017 else { 1018 error = sysctl_copyin(l, 1019 nnode.sysctl_data, own, sz); 1020 if (error != 0) { 1021 free(own, M_SYSCTLDATA); 1022 return (error); 1023 } 1024 } 1025 } else if ((nnode.sysctl_data != NULL) && 1026 !(flags & CTLFLAG_IMMEDIATE)) { 1027 #if NKSYMS > 0 1028 if (name[namelen - 1] == CTL_CREATESYM) { 1029 char symname[128]; /* XXX enough? */ 1030 u_long symaddr; 1031 size_t symlen; 1032 1033 error = sysctl_copyinstr(l, 1034 nnode.sysctl_data, symname, 1035 sizeof(symname), &symlen); 1036 if (error) 1037 return (error); 1038 error = ksyms_getval(NULL, symname, 1039 &symaddr, KSYMS_EXTERN); 1040 if (error) 1041 return (error); /* EINVAL? */ 1042 nnode.sysctl_data = (void*)symaddr; 1043 } 1044 #endif /* NKSYMS > 0 */ 1045 /* 1046 * Ideally, we'd like to verify here 1047 * that this address is acceptable, 1048 * but... 1049 * 1050 * - it might be valid now, only to 1051 * become invalid later 1052 * 1053 * - it might be invalid only for the 1054 * moment and valid later 1055 * 1056 * - or something else. 1057 * 1058 * Since we can't get a good answer, 1059 * we'll just accept the address as 1060 * given, and fault on individual 1061 * lookups. 1062 */ 1063 } 1064 } else if (nnode.sysctl_func == NULL) 1065 return (EINVAL); 1066 } 1067 1068 /* 1069 * a process can't assign a function to a node, and the kernel 1070 * can't create a node that has no function or data. 1071 * (XXX somewhat redundant check) 1072 */ 1073 if (l != NULL || nnode.sysctl_func == NULL) { 1074 if (type != CTLTYPE_NODE && 1075 nnode.sysctl_data == NULL && 1076 !(flags & CTLFLAG_IMMEDIATE) && 1077 own == NULL) 1078 return (EINVAL); 1079 } 1080 1081 #ifdef SYSCTL_DISALLOW_KWRITE 1082 /* 1083 * a process can't create a writable node unless it refers to 1084 * new data. 1085 */ 1086 if (l != NULL && own == NULL && type != CTLTYPE_NODE && 1087 (flags & CTLFLAG_READWRITE) != CTLFLAG_READONLY && 1088 !(flags & CTLFLAG_IMMEDIATE)) 1089 return (EPERM); 1090 #endif /* SYSCTL_DISALLOW_KWRITE */ 1091 1092 /* 1093 * make sure there's somewhere to put the new stuff. 1094 */ 1095 if (pnode->sysctl_child == NULL) { 1096 if (flags & CTLFLAG_ANYNUMBER) 1097 error = sysctl_alloc(pnode, 1); 1098 else 1099 error = sysctl_alloc(pnode, 0); 1100 if (error) { 1101 if (own != NULL) 1102 free(own, M_SYSCTLDATA); 1103 return (error); 1104 } 1105 } 1106 node = pnode->sysctl_child; 1107 1108 /* 1109 * no collisions, so pick a good dynamic number if we need to. 1110 */ 1111 if (nm == CTL_CREATE) { 1112 nm = ++sysctl_root.sysctl_num; 1113 for (ni = 0; ni < pnode->sysctl_clen; ni++) { 1114 if (nm == node[ni].sysctl_num) { 1115 nm++; 1116 ni = -1; 1117 } else if (nm > node[ni].sysctl_num) 1118 at = ni + 1; 1119 } 1120 } 1121 1122 /* 1123 * oops...ran out of space 1124 */ 1125 if (pnode->sysctl_clen == pnode->sysctl_csize) { 1126 error = sysctl_realloc(pnode); 1127 if (error) { 1128 if (own != NULL) 1129 free(own, M_SYSCTLDATA); 1130 return (error); 1131 } 1132 node = pnode->sysctl_child; 1133 } 1134 1135 /* 1136 * insert new node data 1137 */ 1138 if (at < pnode->sysctl_clen) { 1139 int t; 1140 1141 /* 1142 * move the nodes that should come after the new one 1143 */ 1144 memmove(&node[at + 1], &node[at], 1145 (pnode->sysctl_clen - at) * sizeof(struct sysctlnode)); 1146 memset(&node[at], 0, sizeof(struct sysctlnode)); 1147 node[at].sysctl_parent = pnode; 1148 /* 1149 * and...reparent any children of any moved nodes 1150 */ 1151 for (ni = at; ni <= pnode->sysctl_clen; ni++) 1152 if (SYSCTL_TYPE(node[ni].sysctl_flags) == CTLTYPE_NODE) 1153 for (t = 0; t < node[ni].sysctl_clen; t++) 1154 node[ni].sysctl_child[t].sysctl_parent = 1155 &node[ni]; 1156 } 1157 node = &node[at]; 1158 pnode->sysctl_clen++; 1159 1160 strlcpy(node->sysctl_name, nnode.sysctl_name, 1161 sizeof(node->sysctl_name)); 1162 node->sysctl_num = nm; 1163 node->sysctl_size = sz; 1164 node->sysctl_flags = SYSCTL_VERSION|type|flags; /* XXX other trees */ 1165 node->sysctl_csize = 0; 1166 node->sysctl_clen = 0; 1167 if (own) { 1168 node->sysctl_data = own; 1169 node->sysctl_flags |= CTLFLAG_OWNDATA; 1170 } else if (flags & CTLFLAG_ALIAS) { 1171 node->sysctl_alias = anum; 1172 } else if (flags & CTLFLAG_IMMEDIATE) { 1173 switch (type) { 1174 case CTLTYPE_INT: 1175 node->sysctl_idata = nnode.sysctl_idata; 1176 break; 1177 case CTLTYPE_QUAD: 1178 node->sysctl_qdata = nnode.sysctl_qdata; 1179 break; 1180 } 1181 } else { 1182 node->sysctl_data = nnode.sysctl_data; 1183 node->sysctl_flags &= ~CTLFLAG_OWNDATA; 1184 } 1185 node->sysctl_func = nnode.sysctl_func; 1186 node->sysctl_child = NULL; 1187 /* node->sysctl_parent should already be done */ 1188 1189 /* 1190 * update "version" on path to "root" 1191 */ 1192 for (; rnode->sysctl_parent != NULL; rnode = rnode->sysctl_parent) 1193 ; 1194 pnode = node; 1195 for (nm = rnode->sysctl_ver + 1; pnode != NULL; 1196 pnode = pnode->sysctl_parent) 1197 pnode->sysctl_ver = nm; 1198 1199 /* If this fails, the node is already added - the user won't know! */ 1200 error = sysctl_cvt_out(l, v, node, oldp, *oldlenp, oldlenp); 1201 1202 return (error); 1203 } 1204 1205 /* 1206 * ******************************************************************** 1207 * A wrapper around sysctl_create() that prints the thing we're trying 1208 * to add. 1209 * ******************************************************************** 1210 */ 1211 #ifdef SYSCTL_DEBUG_CREATE 1212 int 1213 sysctl_create(SYSCTLFN_ARGS) 1214 { 1215 const struct sysctlnode *node; 1216 int k, rc, ni, nl = namelen + (name - oname); 1217 1218 node = newp; 1219 1220 printf("namelen %d (", nl); 1221 for (ni = 0; ni < nl - 1; ni++) 1222 printf(" %d", oname[ni]); 1223 printf(" %d )\t[%s]\tflags %08x (%08x %d %zu)\n", 1224 k = node->sysctl_num, 1225 node->sysctl_name, 1226 node->sysctl_flags, 1227 SYSCTL_FLAGS(node->sysctl_flags), 1228 SYSCTL_TYPE(node->sysctl_flags), 1229 node->sysctl_size); 1230 1231 node = rnode; 1232 rc = _sysctl_create(SYSCTLFN_CALL(rnode)); 1233 1234 printf("sysctl_create("); 1235 for (ni = 0; ni < nl - 1; ni++) 1236 printf(" %d", oname[ni]); 1237 printf(" %d ) returned %d\n", k, rc); 1238 1239 return (rc); 1240 } 1241 #endif /* SYSCTL_DEBUG_CREATE */ 1242 1243 /* 1244 * sysctl_destroy -- Removes a node (as described by newp) from the 1245 * given tree, returning (if successful) a copy of the dead node in 1246 * oldp. Since we're removing stuff, there's not much to check. 1247 */ 1248 int 1249 sysctl_destroy(SYSCTLFN_ARGS) 1250 { 1251 struct sysctlnode *node, *pnode, onode, nnode; 1252 int ni, error, v; 1253 1254 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 1255 printf("sysctl_destroy: rnode %p wrong version\n", rnode); 1256 return (EINVAL); 1257 } 1258 1259 error = 0; 1260 1261 if (namelen != 1 || name[namelen - 1] != CTL_DESTROY) 1262 return (EINVAL); 1263 1264 /* 1265 * processes can only destroy nodes at securelevel 0, must be 1266 * root, and can't remove nodes from a parent that's not 1267 * writeable 1268 */ 1269 if (l != NULL) { 1270 #ifndef SYSCTL_DISALLOW_CREATE 1271 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL, 1272 KAUTH_REQ_SYSTEM_SYSCTL_DELETE, NULL, NULL, NULL); 1273 if (error) 1274 return (error); 1275 if (!(rnode->sysctl_flags & CTLFLAG_READWRITE)) 1276 #endif /* SYSCTL_DISALLOW_CREATE */ 1277 return (EPERM); 1278 } 1279 1280 /* 1281 * nothing can remove a node if: 1282 * the node is permanent (checked later) or 1283 * the tree itself is not writeable or 1284 * the entire sysctl system is not writeable 1285 * 1286 * note that we ignore whether setup is complete or not, 1287 * because these rules always apply. 1288 */ 1289 if (!(sysctl_rootof(rnode)->sysctl_flags & CTLFLAG_READWRITE) || 1290 !(sysctl_root.sysctl_flags & CTLFLAG_READWRITE)) 1291 return (EPERM); 1292 1293 if (newp == NULL) 1294 return (EINVAL); 1295 error = sysctl_cvt_in(l, &v, newp, newlen, &nnode); 1296 if (error) 1297 return (error); 1298 memset(&onode, 0, sizeof(struct sysctlnode)); 1299 1300 node = rnode->sysctl_child; 1301 for (ni = 0; ni < rnode->sysctl_clen; ni++) { 1302 if (nnode.sysctl_num == node[ni].sysctl_num) { 1303 /* 1304 * if name specified, must match 1305 */ 1306 if (nnode.sysctl_name[0] != '\0' && 1307 strcmp(nnode.sysctl_name, node[ni].sysctl_name)) 1308 continue; 1309 /* 1310 * if version specified, must match 1311 */ 1312 if (nnode.sysctl_ver != 0 && 1313 nnode.sysctl_ver != node[ni].sysctl_ver) 1314 continue; 1315 /* 1316 * this must be the one 1317 */ 1318 break; 1319 } 1320 } 1321 if (ni == rnode->sysctl_clen) 1322 return (ENOENT); 1323 node = &node[ni]; 1324 pnode = node->sysctl_parent; 1325 1326 /* 1327 * if the kernel says permanent, it is, so there. nyah. 1328 */ 1329 if (SYSCTL_FLAGS(node->sysctl_flags) & CTLFLAG_PERMANENT) 1330 return (EPERM); 1331 1332 /* 1333 * can't delete non-empty nodes 1334 */ 1335 if (SYSCTL_TYPE(node->sysctl_flags) == CTLTYPE_NODE && 1336 node->sysctl_clen != 0) 1337 return (ENOTEMPTY); 1338 1339 /* 1340 * if the node "owns" data, release it now 1341 */ 1342 if (node->sysctl_flags & CTLFLAG_OWNDATA) { 1343 if (node->sysctl_data != NULL) 1344 free(node->sysctl_data, M_SYSCTLDATA); 1345 node->sysctl_data = NULL; 1346 } 1347 if (node->sysctl_flags & CTLFLAG_OWNDESC) { 1348 if (node->sysctl_desc != NULL) 1349 /*XXXUNCONST*/ 1350 free(__UNCONST(node->sysctl_desc), M_SYSCTLDATA); 1351 node->sysctl_desc = NULL; 1352 } 1353 1354 /* 1355 * if the node to be removed is not the last one on the list, 1356 * move the remaining nodes up, and reparent any grandchildren 1357 */ 1358 onode = *node; 1359 if (ni < pnode->sysctl_clen - 1) { 1360 int t; 1361 1362 memmove(&pnode->sysctl_child[ni], &pnode->sysctl_child[ni + 1], 1363 (pnode->sysctl_clen - ni - 1) * 1364 sizeof(struct sysctlnode)); 1365 for (; ni < pnode->sysctl_clen - 1; ni++) 1366 if (SYSCTL_TYPE(pnode->sysctl_child[ni].sysctl_flags) == 1367 CTLTYPE_NODE) 1368 for (t = 0; 1369 t < pnode->sysctl_child[ni].sysctl_clen; 1370 t++) 1371 pnode->sysctl_child[ni].sysctl_child[t]. 1372 sysctl_parent = 1373 &pnode->sysctl_child[ni]; 1374 ni = pnode->sysctl_clen - 1; 1375 node = &pnode->sysctl_child[ni]; 1376 } 1377 1378 /* 1379 * reset the space we just vacated 1380 */ 1381 memset(node, 0, sizeof(struct sysctlnode)); 1382 node->sysctl_parent = pnode; 1383 pnode->sysctl_clen--; 1384 1385 /* 1386 * if this parent just lost its last child, nuke the creche 1387 */ 1388 if (pnode->sysctl_clen == 0) { 1389 free(pnode->sysctl_child, M_SYSCTLNODE); 1390 pnode->sysctl_csize = 0; 1391 pnode->sysctl_child = NULL; 1392 } 1393 1394 /* 1395 * update "version" on path to "root" 1396 */ 1397 for (; rnode->sysctl_parent != NULL; rnode = rnode->sysctl_parent) 1398 ; 1399 for (ni = rnode->sysctl_ver + 1; pnode != NULL; 1400 pnode = pnode->sysctl_parent) 1401 pnode->sysctl_ver = ni; 1402 1403 error = sysctl_cvt_out(l, v, &onode, oldp, *oldlenp, oldlenp); 1404 1405 return (error); 1406 } 1407 1408 /* 1409 * sysctl_lookup -- Handles copyin/copyout of new and old values. 1410 * Partial reads are globally allowed. Only root can write to things 1411 * unless the node says otherwise. 1412 */ 1413 int 1414 sysctl_lookup(SYSCTLFN_ARGS) 1415 { 1416 int error, rw; 1417 size_t sz, len; 1418 void *d; 1419 1420 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 1421 printf("sysctl_lookup: rnode %p wrong version\n", rnode); 1422 return (EINVAL); 1423 } 1424 1425 error = 0; 1426 1427 /* 1428 * you can't "look up" a node. you can "query" it, but you 1429 * can't "look it up". 1430 */ 1431 if (SYSCTL_TYPE(rnode->sysctl_flags) == CTLTYPE_NODE || namelen != 0) 1432 return (EINVAL); 1433 1434 /* 1435 * some nodes are private, so only root can look into them. 1436 */ 1437 if (l != NULL && (rnode->sysctl_flags & CTLFLAG_PRIVATE) && 1438 (error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL, 1439 KAUTH_REQ_SYSTEM_SYSCTL_PRVT, NULL, NULL, NULL)) != 0) 1440 return (error); 1441 1442 /* 1443 * if a node wants to be writable according to different rules 1444 * other than "only root can write to stuff unless a flag is 1445 * set", then it needs its own function which should have been 1446 * called and not us. 1447 */ 1448 if (l != NULL && newp != NULL && 1449 !(rnode->sysctl_flags & CTLFLAG_ANYWRITE) && 1450 (error = kauth_authorize_generic(l->l_cred, 1451 KAUTH_GENERIC_ISSUSER, NULL)) != 0) 1452 return (error); 1453 1454 /* 1455 * is this node supposedly writable? 1456 */ 1457 rw = (rnode->sysctl_flags & CTLFLAG_READWRITE) ? 1 : 0; 1458 1459 /* 1460 * it appears not to be writable at this time, so if someone 1461 * tried to write to it, we must tell them to go away 1462 */ 1463 if (!rw && newp != NULL) 1464 return (EPERM); 1465 1466 /* 1467 * step one, copy out the stuff we have presently 1468 */ 1469 if (rnode->sysctl_flags & CTLFLAG_IMMEDIATE) { 1470 /* 1471 * note that we discard const here because we are 1472 * modifying the contents of the node (which is okay 1473 * because it's ours) 1474 */ 1475 switch (SYSCTL_TYPE(rnode->sysctl_flags)) { 1476 case CTLTYPE_INT: 1477 d = __UNCONST(&rnode->sysctl_idata); 1478 break; 1479 case CTLTYPE_QUAD: 1480 d = __UNCONST(&rnode->sysctl_qdata); 1481 break; 1482 default: 1483 return (EINVAL); 1484 } 1485 } else 1486 d = rnode->sysctl_data; 1487 if (SYSCTL_TYPE(rnode->sysctl_flags) == CTLTYPE_STRING) 1488 sz = strlen(d) + 1; /* XXX@@@ possible fault here */ 1489 else 1490 sz = rnode->sysctl_size; 1491 if (oldp != NULL) 1492 error = sysctl_copyout(l, d, oldp, MIN(sz, *oldlenp)); 1493 if (error) 1494 return (error); 1495 *oldlenp = sz; 1496 1497 /* 1498 * are we done? 1499 */ 1500 if (newp == NULL || newlen == 0) 1501 return (0); 1502 1503 /* 1504 * hmm...not done. must now "copy in" new value. re-adjust 1505 * sz to maximum value (strings are "weird"). 1506 */ 1507 sz = rnode->sysctl_size; 1508 switch (SYSCTL_TYPE(rnode->sysctl_flags)) { 1509 case CTLTYPE_INT: 1510 case CTLTYPE_QUAD: 1511 case CTLTYPE_STRUCT: 1512 /* 1513 * these data must be *exactly* the same size coming 1514 * in. 1515 */ 1516 if (newlen != sz) 1517 return (EINVAL); 1518 error = sysctl_copyin(l, newp, d, sz); 1519 break; 1520 case CTLTYPE_STRING: { 1521 /* 1522 * strings, on the other hand, can be shorter, and we 1523 * let userland be sloppy about the trailing nul. 1524 */ 1525 char *newbuf; 1526 1527 /* 1528 * too much new string? 1529 */ 1530 if (newlen > sz) 1531 return (EINVAL); 1532 1533 /* 1534 * temporary copy of new inbound string 1535 */ 1536 len = MIN(sz, newlen); 1537 newbuf = malloc(len, M_SYSCTLDATA, M_WAITOK|M_CANFAIL); 1538 if (newbuf == NULL) 1539 return (ENOMEM); 1540 error = sysctl_copyin(l, newp, newbuf, len); 1541 if (error) { 1542 free(newbuf, M_SYSCTLDATA); 1543 return (error); 1544 } 1545 1546 /* 1547 * did they null terminate it, or do we have space 1548 * left to do it ourselves? 1549 */ 1550 if (newbuf[len - 1] != '\0' && len == sz) { 1551 free(newbuf, M_SYSCTLDATA); 1552 return (EINVAL); 1553 } 1554 1555 /* 1556 * looks good, so pop it into place and zero the rest. 1557 */ 1558 if (len > 0) 1559 memcpy(d, newbuf, len); 1560 if (sz != len) 1561 memset((char*)d + len, 0, sz - len); 1562 free(newbuf, M_SYSCTLDATA); 1563 break; 1564 } 1565 default: 1566 return (EINVAL); 1567 } 1568 1569 return (error); 1570 } 1571 1572 /* 1573 * sysctl_mmap -- Dispatches sysctl mmap requests to those nodes that 1574 * purport to handle it. This interface isn't fully fleshed out yet, 1575 * unfortunately. 1576 */ 1577 static int 1578 sysctl_mmap(SYSCTLFN_ARGS) 1579 { 1580 const struct sysctlnode *node; 1581 struct sysctlnode nnode; 1582 int error; 1583 1584 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 1585 printf("sysctl_mmap: rnode %p wrong version\n", rnode); 1586 return (EINVAL); 1587 } 1588 1589 /* 1590 * let's just pretend that didn't happen, m'kay? 1591 */ 1592 if (l == NULL) 1593 return (EPERM); 1594 1595 /* 1596 * is this a sysctlnode description of an mmap request? 1597 */ 1598 if (newp == NULL || newlen != sizeof(struct sysctlnode)) 1599 return (EINVAL); 1600 error = sysctl_copyin(l, newp, &nnode, sizeof(nnode)); 1601 if (error) 1602 return (error); 1603 1604 /* 1605 * does the node they asked for exist? 1606 */ 1607 if (namelen != 1) 1608 return (EOPNOTSUPP); 1609 node = rnode; 1610 error = sysctl_locate(l, &nnode.sysctl_num, 1, &node, NULL); 1611 if (error) 1612 return (error); 1613 1614 /* 1615 * does this node that we have found purport to handle mmap? 1616 */ 1617 if (node->sysctl_func == NULL || 1618 !(node->sysctl_flags & CTLFLAG_MMAP)) 1619 return (EOPNOTSUPP); 1620 1621 /* 1622 * well...okay, they asked for it. 1623 */ 1624 return ((*node->sysctl_func)(SYSCTLFN_CALL(node))); 1625 } 1626 1627 int 1628 sysctl_describe(SYSCTLFN_ARGS) 1629 { 1630 struct sysctldesc *d; 1631 void *bf; 1632 size_t sz, left, tot; 1633 int i, error, v = -1; 1634 struct sysctlnode *node; 1635 struct sysctlnode dnode; 1636 1637 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 1638 printf("sysctl_query: rnode %p wrong version\n", rnode); 1639 return (EINVAL); 1640 } 1641 1642 if (SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE) 1643 return (ENOTDIR); 1644 if (namelen != 1 || name[0] != CTL_DESCRIBE) 1645 return (EINVAL); 1646 1647 /* 1648 * get ready... 1649 */ 1650 error = 0; 1651 d = bf = malloc(MAXDESCLEN, M_TEMP, M_WAITOK|M_CANFAIL); 1652 if (bf == NULL) 1653 return ENOMEM; 1654 tot = 0; 1655 node = rnode->sysctl_child; 1656 left = *oldlenp; 1657 1658 /* 1659 * no request -> all descriptions at this level 1660 * request with desc unset -> just this node 1661 * request with desc set -> set descr for this node 1662 */ 1663 if (newp != NULL) { 1664 error = sysctl_cvt_in(l, &v, newp, newlen, &dnode); 1665 if (error) 1666 goto out; 1667 if (dnode.sysctl_desc != NULL) { 1668 /* 1669 * processes cannot set descriptions above 1670 * securelevel 0. and must be root. blah 1671 * blah blah. a couple more checks are made 1672 * once we find the node we want. 1673 */ 1674 if (l != NULL) { 1675 #ifndef SYSCTL_DISALLOW_CREATE 1676 error = kauth_authorize_system(l->l_cred, 1677 KAUTH_SYSTEM_SYSCTL, 1678 KAUTH_REQ_SYSTEM_SYSCTL_DESC, NULL, 1679 NULL, NULL); 1680 if (error) 1681 goto out; 1682 #else /* SYSCTL_DISALLOW_CREATE */ 1683 error = EPERM; 1684 goto out; 1685 #endif /* SYSCTL_DISALLOW_CREATE */ 1686 } 1687 1688 /* 1689 * find node and try to set the description on it 1690 */ 1691 for (i = 0; i < rnode->sysctl_clen; i++) 1692 if (node[i].sysctl_num == dnode.sysctl_num) 1693 break; 1694 if (i == rnode->sysctl_clen) { 1695 error = ENOENT; 1696 goto out; 1697 } 1698 node = &node[i]; 1699 1700 /* 1701 * did the caller specify a node version? 1702 */ 1703 if (dnode.sysctl_ver != 0 && 1704 dnode.sysctl_ver != node->sysctl_ver) { 1705 error = EINVAL; 1706 goto out; 1707 } 1708 1709 /* 1710 * okay...some rules: 1711 * (1) if setup is done and the tree is 1712 * read-only or the whole system is 1713 * read-only 1714 * (2) no one can set a description on a 1715 * permanent node (it must be set when 1716 * using createv) 1717 * (3) processes cannot *change* a description 1718 * (4) processes *can*, however, set a 1719 * description on a read-only node so that 1720 * one can be created and then described 1721 * in two steps 1722 * anything else come to mind? 1723 */ 1724 if ((sysctl_root.sysctl_flags & CTLFLAG_PERMANENT) && 1725 (!(sysctl_rootof(node)->sysctl_flags & 1726 CTLFLAG_READWRITE) || 1727 !(sysctl_root.sysctl_flags & CTLFLAG_READWRITE))) { 1728 error = EPERM; 1729 goto out; 1730 } 1731 if (node->sysctl_flags & CTLFLAG_PERMANENT) { 1732 error = EPERM; 1733 goto out; 1734 } 1735 if (l != NULL && node->sysctl_desc != NULL) { 1736 error = EPERM; 1737 goto out; 1738 } 1739 1740 /* 1741 * right, let's go ahead. the first step is 1742 * making the description into something the 1743 * node can "own", if need be. 1744 */ 1745 if (l != NULL || 1746 dnode.sysctl_flags & CTLFLAG_OWNDESC) { 1747 char *nd, *k; 1748 1749 k = malloc(MAXDESCLEN, M_TEMP, 1750 M_WAITOK|M_CANFAIL); 1751 if (k == NULL) { 1752 error = ENOMEM; 1753 goto out; 1754 } 1755 error = sysctl_copyinstr(l, dnode.sysctl_desc, 1756 k, MAXDESCLEN, &sz); 1757 if (error) { 1758 free(k, M_TEMP); 1759 goto out; 1760 } 1761 nd = malloc(sz, M_SYSCTLDATA, 1762 M_WAITOK|M_CANFAIL); 1763 if (nd == NULL) { 1764 free(k, M_TEMP); 1765 error = ENOMEM; 1766 goto out; 1767 } 1768 memcpy(nd, k, sz); 1769 dnode.sysctl_flags |= CTLFLAG_OWNDESC; 1770 dnode.sysctl_desc = nd; 1771 free(k, M_TEMP); 1772 } 1773 1774 /* 1775 * now "release" the old description and 1776 * attach the new one. ta-da. 1777 */ 1778 if ((node->sysctl_flags & CTLFLAG_OWNDESC) && 1779 node->sysctl_desc != NULL) 1780 /*XXXUNCONST*/ 1781 free(__UNCONST(node->sysctl_desc), M_SYSCTLDATA); 1782 node->sysctl_desc = dnode.sysctl_desc; 1783 node->sysctl_flags |= 1784 (dnode.sysctl_flags & CTLFLAG_OWNDESC); 1785 1786 /* 1787 * now we "fall out" and into the loop which 1788 * will copy the new description back out for 1789 * those interested parties 1790 */ 1791 } 1792 } 1793 1794 /* 1795 * scan for one description or just retrieve all descriptions 1796 */ 1797 for (i = 0; i < rnode->sysctl_clen; i++) { 1798 /* 1799 * did they ask for the description of only one node? 1800 */ 1801 if (v != -1 && node[i].sysctl_num != dnode.sysctl_num) 1802 continue; 1803 1804 /* 1805 * don't describe "private" nodes to non-suser users 1806 */ 1807 if ((node[i].sysctl_flags & CTLFLAG_PRIVATE) && (l != NULL) && 1808 !(kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL, 1809 KAUTH_REQ_SYSTEM_SYSCTL_PRVT, NULL, NULL, NULL))) 1810 continue; 1811 1812 /* 1813 * is this description "valid"? 1814 */ 1815 memset(bf, 0, MAXDESCLEN); 1816 if (node[i].sysctl_desc == NULL) 1817 sz = 1; 1818 else if (copystr(node[i].sysctl_desc, &d->descr_str[0], 1819 MAXDESCLEN - sizeof(*d), &sz) != 0) { 1820 /* 1821 * erase possible partial description 1822 */ 1823 memset(bf, 0, MAXDESCLEN); 1824 sz = 1; 1825 } 1826 1827 /* 1828 * we've got it, stuff it into the caller's buffer 1829 */ 1830 d->descr_num = node[i].sysctl_num; 1831 d->descr_ver = node[i].sysctl_ver; 1832 d->descr_len = sz; /* includes trailing nul */ 1833 sz = (char *)NEXT_DESCR(d) - (char *)d; 1834 if (oldp != NULL && left >= sz) { 1835 error = sysctl_copyout(l, d, oldp, sz); 1836 if (error) 1837 goto out; 1838 left -= sz; 1839 oldp = (void *)__sysc_desc_adv(oldp, d->descr_len); 1840 } 1841 tot += sz; 1842 1843 /* 1844 * if we get this far with v not "unset", they asked 1845 * for a specific node and we found it 1846 */ 1847 if (v != -1) 1848 break; 1849 } 1850 1851 /* 1852 * did we find it after all? 1853 */ 1854 if (v != -1 && tot == 0) 1855 error = ENOENT; 1856 else 1857 *oldlenp = tot; 1858 1859 out: 1860 free(bf, M_TEMP); 1861 return (error); 1862 } 1863 1864 /* 1865 * ******************************************************************** 1866 * Section 3: Create and destroy from inside the kernel 1867 * ******************************************************************** 1868 * sysctl_createv() and sysctl_destroyv() are simpler-to-use 1869 * interfaces for the kernel to fling new entries into the mib and rip 1870 * them out later. In the case of sysctl_createv(), the returned copy 1871 * of the node (see sysctl_create()) will be translated back into a 1872 * pointer to the actual node. 1873 * 1874 * Note that sysctl_createv() will return 0 if the create request 1875 * matches an existing node (ala mkdir -p), and that sysctl_destroyv() 1876 * will return 0 if the node to be destroyed already does not exist 1877 * (aka rm -f) or if it is a parent of other nodes. 1878 * 1879 * This allows two (or more) different subsystems to assert sub-tree 1880 * existence before populating their own nodes, and to remove their 1881 * own nodes without orphaning the others when they are done. 1882 * ******************************************************************** 1883 */ 1884 int 1885 sysctl_createv(struct sysctllog **log, int cflags, 1886 const struct sysctlnode **rnode, const struct sysctlnode **cnode, 1887 int flags, int type, const char *namep, const char *descr, 1888 sysctlfn func, u_quad_t qv, void *newp, size_t newlen, 1889 ...) 1890 { 1891 va_list ap; 1892 int error, ni, namelen, name[CTL_MAXNAME]; 1893 const struct sysctlnode *root, *pnode; 1894 struct sysctlnode nnode, onode, *dnode; 1895 size_t sz; 1896 1897 /* 1898 * where are we putting this? 1899 */ 1900 if (rnode != NULL && *rnode == NULL) { 1901 printf("sysctl_createv: rnode NULL\n"); 1902 return (EINVAL); 1903 } 1904 root = rnode ? *rnode : NULL; 1905 if (cnode != NULL) 1906 *cnode = NULL; 1907 if (cflags != 0) 1908 return (EINVAL); 1909 1910 /* 1911 * what is it? 1912 */ 1913 flags = SYSCTL_VERSION|SYSCTL_TYPE(type)|SYSCTL_FLAGS(flags); 1914 if (log != NULL) 1915 flags &= ~CTLFLAG_PERMANENT; 1916 1917 /* 1918 * where do we put it? 1919 */ 1920 va_start(ap, newlen); 1921 namelen = 0; 1922 ni = -1; 1923 do { 1924 if (++ni == CTL_MAXNAME) 1925 return (ENAMETOOLONG); 1926 name[ni] = va_arg(ap, int); 1927 /* 1928 * sorry, this is not supported from here 1929 */ 1930 if (name[ni] == CTL_CREATESYM) 1931 return (EINVAL); 1932 } while (name[ni] != CTL_EOL && name[ni] != CTL_CREATE); 1933 namelen = ni + (name[ni] == CTL_CREATE ? 1 : 0); 1934 va_end(ap); 1935 1936 /* 1937 * what's it called 1938 */ 1939 if (strlcpy(nnode.sysctl_name, namep, sizeof(nnode.sysctl_name)) >= 1940 sizeof(nnode.sysctl_name)) 1941 return (ENAMETOOLONG); 1942 1943 /* 1944 * cons up the description of the new node 1945 */ 1946 nnode.sysctl_num = name[namelen - 1]; 1947 name[namelen - 1] = CTL_CREATE; 1948 nnode.sysctl_size = newlen; 1949 nnode.sysctl_flags = flags; 1950 if (type == CTLTYPE_NODE) { 1951 nnode.sysctl_csize = 0; 1952 nnode.sysctl_clen = 0; 1953 nnode.sysctl_child = NULL; 1954 if (flags & CTLFLAG_ALIAS) 1955 nnode.sysctl_alias = qv; 1956 } else if (flags & CTLFLAG_IMMEDIATE) { 1957 switch (type) { 1958 case CTLTYPE_INT: 1959 nnode.sysctl_idata = qv; 1960 break; 1961 case CTLTYPE_QUAD: 1962 nnode.sysctl_qdata = qv; 1963 break; 1964 default: 1965 return (EINVAL); 1966 } 1967 } else { 1968 nnode.sysctl_data = newp; 1969 } 1970 nnode.sysctl_func = func; 1971 nnode.sysctl_parent = NULL; 1972 nnode.sysctl_ver = 0; 1973 1974 /* 1975 * initialize lock state -- we need locks if the main tree has 1976 * been marked as complete, but since we could be called from 1977 * either there, or from a device driver (say, at device 1978 * insertion), or from an lkm (at lkm load time, say), we 1979 * don't really want to "wait"... 1980 */ 1981 error = sysctl_lock(NULL, NULL, 0); 1982 if (error) 1983 return (error); 1984 1985 /* 1986 * locate the prospective parent of the new node, and if we 1987 * find it, add the new node. 1988 */ 1989 sz = sizeof(onode); 1990 pnode = root; 1991 error = sysctl_locate(NULL, &name[0], namelen - 1, &pnode, &ni); 1992 if (error) { 1993 printf("sysctl_createv: sysctl_locate(%s) returned %d\n", 1994 nnode.sysctl_name, error); 1995 sysctl_unlock(NULL); 1996 return (error); 1997 } 1998 error = sysctl_create(&name[ni], namelen - ni, &onode, &sz, 1999 &nnode, sizeof(nnode), &name[0], NULL, 2000 pnode); 2001 2002 /* 2003 * unfortunately the node we wanted to create is already 2004 * there. if the node that's already there is a reasonable 2005 * facsimile of the node we wanted to create, just pretend 2006 * (for the caller's benefit) that we managed to create the 2007 * node they wanted. 2008 */ 2009 if (error == EEXIST) { 2010 /* name is the same as requested... */ 2011 if (strcmp(nnode.sysctl_name, onode.sysctl_name) == 0 && 2012 /* they want the same function... */ 2013 nnode.sysctl_func == onode.sysctl_func && 2014 /* number is the same as requested, or... */ 2015 (nnode.sysctl_num == onode.sysctl_num || 2016 /* they didn't pick a number... */ 2017 nnode.sysctl_num == CTL_CREATE)) { 2018 /* 2019 * collision here from trying to create 2020 * something that already existed; let's give 2021 * our customers a hand and tell them they got 2022 * what they wanted. 2023 */ 2024 #ifdef SYSCTL_DEBUG_CREATE 2025 printf("cleared\n"); 2026 #endif /* SYSCTL_DEBUG_CREATE */ 2027 error = 0; 2028 } 2029 } 2030 2031 if (error == 0 && 2032 (cnode != NULL || log != NULL || descr != NULL)) { 2033 /* 2034 * sysctl_create() gave us back a copy of the node, 2035 * but we need to know where it actually is... 2036 */ 2037 pnode = root; 2038 error = sysctl_locate(NULL, &name[0], namelen - 1, &pnode, &ni); 2039 2040 /* 2041 * manual scan of last layer so that aliased nodes 2042 * aren't followed. 2043 */ 2044 if (error == 0) { 2045 for (ni = 0; ni < pnode->sysctl_clen; ni++) 2046 if (pnode->sysctl_child[ni].sysctl_num == 2047 onode.sysctl_num) 2048 break; 2049 if (ni < pnode->sysctl_clen) 2050 pnode = &pnode->sysctl_child[ni]; 2051 else 2052 error = ENOENT; 2053 } 2054 2055 /* 2056 * not expecting an error here, but... 2057 */ 2058 if (error == 0) { 2059 if (log != NULL) 2060 sysctl_log_add(log, pnode); 2061 if (cnode != NULL) 2062 *cnode = pnode; 2063 if (descr != NULL) { 2064 /* 2065 * allow first caller to *set* a 2066 * description actually to set it 2067 * 2068 * discard const here so we can attach 2069 * the description 2070 */ 2071 dnode = __UNCONST(pnode); 2072 if (pnode->sysctl_desc != NULL) 2073 /* skip it...we've got one */; 2074 else if (flags & CTLFLAG_OWNDESC) { 2075 size_t l = strlen(descr) + 1; 2076 char *d = malloc(l, M_SYSCTLDATA, 2077 M_WAITOK|M_CANFAIL); 2078 if (d != NULL) { 2079 memcpy(d, descr, l); 2080 dnode->sysctl_desc = d; 2081 dnode->sysctl_flags |= 2082 CTLFLAG_OWNDESC; 2083 } 2084 } else 2085 dnode->sysctl_desc = descr; 2086 } 2087 } else { 2088 printf("sysctl_create succeeded but node not found?!\n"); 2089 /* 2090 * confusing, but the create said it 2091 * succeeded, so... 2092 */ 2093 error = 0; 2094 } 2095 } 2096 2097 /* 2098 * now it should be safe to release the lock state. note that 2099 * the pointer to the newly created node being passed back may 2100 * not be "good" for very long. 2101 */ 2102 sysctl_unlock(NULL); 2103 2104 if (error != 0) { 2105 printf("sysctl_createv: sysctl_create(%s) returned %d\n", 2106 nnode.sysctl_name, error); 2107 #if 0 2108 if (error != ENOENT) 2109 sysctl_dump(&onode); 2110 #endif 2111 } 2112 2113 return (error); 2114 } 2115 2116 int 2117 sysctl_destroyv(struct sysctlnode *rnode, ...) 2118 { 2119 va_list ap; 2120 int error, name[CTL_MAXNAME], namelen, ni; 2121 const struct sysctlnode *pnode, *node; 2122 struct sysctlnode dnode, *onode; 2123 size_t sz; 2124 2125 va_start(ap, rnode); 2126 namelen = 0; 2127 ni = 0; 2128 do { 2129 if (ni == CTL_MAXNAME) 2130 return (ENAMETOOLONG); 2131 name[ni] = va_arg(ap, int); 2132 } while (name[ni++] != CTL_EOL); 2133 namelen = ni - 1; 2134 va_end(ap); 2135 2136 /* 2137 * i can't imagine why we'd be destroying a node when the tree 2138 * wasn't complete, but who knows? 2139 */ 2140 error = sysctl_lock(NULL, NULL, 0); 2141 if (error) 2142 return (error); 2143 2144 /* 2145 * where is it? 2146 */ 2147 node = rnode; 2148 error = sysctl_locate(NULL, &name[0], namelen - 1, &node, &ni); 2149 if (error) { 2150 /* they want it gone and it's not there, so... */ 2151 sysctl_unlock(NULL); 2152 return (error == ENOENT ? 0 : error); 2153 } 2154 2155 /* 2156 * set up the deletion 2157 */ 2158 pnode = node; 2159 node = &dnode; 2160 memset(&dnode, 0, sizeof(dnode)); 2161 dnode.sysctl_flags = SYSCTL_VERSION; 2162 dnode.sysctl_num = name[namelen - 1]; 2163 2164 /* 2165 * we found it, now let's nuke it 2166 */ 2167 name[namelen - 1] = CTL_DESTROY; 2168 sz = 0; 2169 error = sysctl_destroy(&name[namelen - 1], 1, NULL, &sz, 2170 node, sizeof(*node), &name[0], NULL, 2171 pnode); 2172 if (error == ENOTEMPTY) { 2173 /* 2174 * think of trying to delete "foo" when "foo.bar" 2175 * (which someone else put there) is still in 2176 * existence 2177 */ 2178 error = 0; 2179 2180 /* 2181 * dunno who put the description there, but if this 2182 * node can ever be removed, we need to make sure the 2183 * string doesn't go out of context. that means we 2184 * need to find the node that's still there (don't use 2185 * sysctl_locate() because that follows aliasing). 2186 */ 2187 node = pnode->sysctl_child; 2188 for (ni = 0; ni < pnode->sysctl_clen; ni++) 2189 if (node[ni].sysctl_num == dnode.sysctl_num) 2190 break; 2191 node = (ni < pnode->sysctl_clen) ? &node[ni] : NULL; 2192 2193 /* 2194 * if we found it, and this node has a description, 2195 * and this node can be released, and it doesn't 2196 * already own its own description...sigh. :) 2197 */ 2198 if (node != NULL && node->sysctl_desc != NULL && 2199 !(node->sysctl_flags & CTLFLAG_PERMANENT) && 2200 !(node->sysctl_flags & CTLFLAG_OWNDESC)) { 2201 char *d; 2202 2203 sz = strlen(node->sysctl_desc) + 1; 2204 d = malloc(sz, M_SYSCTLDATA, M_WAITOK|M_CANFAIL); 2205 if (d != NULL) { 2206 /* 2207 * discard const so that we can 2208 * re-attach the description 2209 */ 2210 memcpy(d, node->sysctl_desc, sz); 2211 onode = __UNCONST(node); 2212 onode->sysctl_desc = d; 2213 onode->sysctl_flags |= CTLFLAG_OWNDESC; 2214 } else { 2215 /* 2216 * XXX drop the description? be 2217 * afraid? don't care? 2218 */ 2219 } 2220 } 2221 } 2222 2223 sysctl_unlock(NULL); 2224 2225 return (error); 2226 } 2227 2228 #if 0 2229 /* 2230 * ******************************************************************** 2231 * the dump routine. i haven't yet decided how (if at all) i'll call 2232 * this from userland when it's in the kernel. 2233 * ******************************************************************** 2234 */ 2235 static const char * 2236 sf(int f) 2237 { 2238 static char s[256]; 2239 char *c; 2240 2241 s[0] = '\0'; 2242 c = ""; 2243 2244 #define print_flag(_f, _s, _c, _q, _x) \ 2245 if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \ 2246 strlcat((_s), (_c), sizeof(_s)); \ 2247 strlcat((_s), __STRING(_q), sizeof(_s)); \ 2248 (_c) = ","; \ 2249 (_f) &= ~__CONCAT(CTLFLAG_,_x); \ 2250 } 2251 2252 print_flag(f, s, c, READONLY, READWRITE); 2253 print_flag(f, s, c, READWRITE, READWRITE); 2254 print_flag(f, s, c, ANYWRITE, ANYWRITE); 2255 print_flag(f, s, c, PRIVATE, PRIVATE); 2256 print_flag(f, s, c, PERMANENT, PERMANENT); 2257 print_flag(f, s, c, OWNDATA, OWNDATA); 2258 print_flag(f, s, c, IMMEDIATE, IMMEDIATE); 2259 print_flag(f, s, c, HEX, HEX); 2260 print_flag(f, s, c, ROOT, ROOT); 2261 print_flag(f, s, c, ANYNUMBER, ANYNUMBER); 2262 print_flag(f, s, c, HIDDEN, HIDDEN); 2263 print_flag(f, s, c, ALIAS, ALIAS); 2264 #undef print_flag 2265 2266 if (f) { 2267 char foo[9]; 2268 snprintf(foo, sizeof(foo), "%x", f); 2269 strlcat(s, c, sizeof(s)); 2270 strlcat(s, foo, sizeof(s)); 2271 } 2272 2273 return (s); 2274 } 2275 2276 static const char * 2277 st(int t) 2278 { 2279 2280 switch (t) { 2281 case CTLTYPE_NODE: 2282 return "NODE"; 2283 case CTLTYPE_INT: 2284 return "INT"; 2285 case CTLTYPE_STRING: 2286 return "STRING"; 2287 case CTLTYPE_QUAD: 2288 return "QUAD"; 2289 case CTLTYPE_STRUCT: 2290 return "STRUCT"; 2291 } 2292 2293 return "???"; 2294 } 2295 2296 void 2297 sysctl_dump(const struct sysctlnode *d) 2298 { 2299 static char nmib[64], smib[256]; 2300 static int indent; 2301 struct sysctlnode *n; 2302 char *np, *sp, tmp[20]; 2303 int i; 2304 2305 if (d == NULL) 2306 return; 2307 2308 np = &nmib[strlen(nmib)]; 2309 sp = &smib[strlen(smib)]; 2310 2311 if (!(d->sysctl_flags & CTLFLAG_ROOT)) { 2312 snprintf(tmp, sizeof(tmp), "%d", d->sysctl_num); 2313 strcat(nmib, "."); 2314 strcat(smib, "."); 2315 strcat(nmib, tmp); 2316 strcat(smib, d->sysctl_name); 2317 printf("%s -> %s (%d)\n", &nmib[1], &smib[1], 2318 SYSCTL_TYPE(d->sysctl_flags)); 2319 } 2320 2321 if (1) { 2322 printf("%*s%p:\tsysctl_name [%s]\n", indent, "", 2323 d, d->sysctl_name); 2324 printf("%*s\t\tsysctl_num %d\n", indent, "", 2325 d->sysctl_num); 2326 printf("%*s\t\tsysctl_flags %x (flags=%x<%s> type=%d<%s> " 2327 "size=%zu)\n", 2328 indent, "", d->sysctl_flags, 2329 SYSCTL_FLAGS(d->sysctl_flags), 2330 sf(SYSCTL_FLAGS(d->sysctl_flags)), 2331 SYSCTL_TYPE(d->sysctl_flags), 2332 st(SYSCTL_TYPE(d->sysctl_flags)), 2333 d->sysctl_size); 2334 if (SYSCTL_TYPE(d->sysctl_flags) == CTLTYPE_NODE) { 2335 printf("%*s\t\tsysctl_csize %d\n", indent, "", 2336 d->sysctl_csize); 2337 printf("%*s\t\tsysctl_clen %d\n", indent, "", 2338 d->sysctl_clen); 2339 printf("%*s\t\tsysctl_child %p\n", indent, "", 2340 d->sysctl_child); 2341 } else 2342 printf("%*s\t\tsysctl_data %p\n", indent, "", 2343 d->sysctl_data); 2344 printf("%*s\t\tsysctl_func %p\n", indent, "", 2345 d->sysctl_func); 2346 printf("%*s\t\tsysctl_parent %p\n", indent, "", 2347 d->sysctl_parent); 2348 printf("%*s\t\tsysctl_ver %d\n", indent, "", 2349 d->sysctl_ver); 2350 } 2351 2352 if (SYSCTL_TYPE(d->sysctl_flags) == CTLTYPE_NODE) { 2353 indent += 8; 2354 n = d->sysctl_child; 2355 for (i = 0; i < d->sysctl_clen; i++) { 2356 sysctl_dump(&n[i]); 2357 } 2358 indent -= 8; 2359 } 2360 2361 np[0] = '\0'; 2362 sp[0] = '\0'; 2363 } 2364 #endif /* 0 */ 2365 2366 /* 2367 * ******************************************************************** 2368 * Deletes an entire n-ary tree. Not recommended unless you know why 2369 * you're doing it. Personally, I don't know why you'd even think 2370 * about it. 2371 * ******************************************************************** 2372 */ 2373 void 2374 sysctl_free(struct sysctlnode *rnode) 2375 { 2376 struct sysctlnode *node, *pnode; 2377 2378 if (rnode == NULL) 2379 rnode = &sysctl_root; 2380 2381 if (SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) { 2382 printf("sysctl_free: rnode %p wrong version\n", rnode); 2383 return; 2384 } 2385 2386 pnode = rnode; 2387 2388 node = pnode->sysctl_child; 2389 do { 2390 while (node != NULL && pnode->sysctl_csize > 0) { 2391 while (node < 2392 &pnode->sysctl_child[pnode->sysctl_clen] && 2393 (SYSCTL_TYPE(node->sysctl_flags) != 2394 CTLTYPE_NODE || 2395 node->sysctl_csize == 0)) { 2396 if (SYSCTL_FLAGS(node->sysctl_flags) & 2397 CTLFLAG_OWNDATA) { 2398 if (node->sysctl_data != NULL) { 2399 free(node->sysctl_data, 2400 M_SYSCTLDATA); 2401 node->sysctl_data = NULL; 2402 } 2403 } 2404 if (SYSCTL_FLAGS(node->sysctl_flags) & 2405 CTLFLAG_OWNDESC) { 2406 if (node->sysctl_desc != NULL) { 2407 /*XXXUNCONST*/ 2408 free(__UNCONST(node->sysctl_desc), 2409 M_SYSCTLDATA); 2410 node->sysctl_desc = NULL; 2411 } 2412 } 2413 node++; 2414 } 2415 if (node < &pnode->sysctl_child[pnode->sysctl_clen]) { 2416 pnode = node; 2417 node = node->sysctl_child; 2418 } else 2419 break; 2420 } 2421 if (pnode->sysctl_child != NULL) 2422 free(pnode->sysctl_child, M_SYSCTLNODE); 2423 pnode->sysctl_clen = 0; 2424 pnode->sysctl_csize = 0; 2425 pnode->sysctl_child = NULL; 2426 node = pnode; 2427 pnode = node->sysctl_parent; 2428 } while (pnode != NULL && node != rnode); 2429 } 2430 2431 int 2432 sysctl_log_add(struct sysctllog **logp, const struct sysctlnode *node) 2433 { 2434 int name[CTL_MAXNAME], namelen, i; 2435 const struct sysctlnode *pnode; 2436 struct sysctllog *log; 2437 2438 if (node->sysctl_flags & CTLFLAG_PERMANENT) 2439 return (0); 2440 2441 if (logp == NULL) 2442 return (0); 2443 2444 if (*logp == NULL) { 2445 log = malloc(sizeof(struct sysctllog), 2446 M_SYSCTLDATA, M_WAITOK|M_CANFAIL); 2447 if (log == NULL) { 2448 /* XXX print error message? */ 2449 return (-1); 2450 } 2451 log->log_num = malloc(16 * sizeof(int), 2452 M_SYSCTLDATA, M_WAITOK|M_CANFAIL); 2453 if (log->log_num == NULL) { 2454 /* XXX print error message? */ 2455 free(log, M_SYSCTLDATA); 2456 return (-1); 2457 } 2458 memset(log->log_num, 0, 16 * sizeof(int)); 2459 log->log_root = NULL; 2460 log->log_size = 16; 2461 log->log_left = 16; 2462 *logp = log; 2463 } else 2464 log = *logp; 2465 2466 /* 2467 * check that the root is proper. it's okay to record the 2468 * address of the root of a tree. it's the only thing that's 2469 * guaranteed not to shift around as nodes come and go. 2470 */ 2471 if (log->log_root == NULL) 2472 log->log_root = sysctl_rootof(node); 2473 else if (log->log_root != sysctl_rootof(node)) { 2474 printf("sysctl: log %p root mismatch (%p)\n", 2475 log->log_root, sysctl_rootof(node)); 2476 return (-1); 2477 } 2478 2479 /* 2480 * we will copy out name in reverse order 2481 */ 2482 for (pnode = node, namelen = 0; 2483 pnode != NULL && !(pnode->sysctl_flags & CTLFLAG_ROOT); 2484 pnode = pnode->sysctl_parent) 2485 name[namelen++] = pnode->sysctl_num; 2486 2487 /* 2488 * do we have space? 2489 */ 2490 if (log->log_left < (namelen + 3)) 2491 sysctl_log_realloc(log); 2492 if (log->log_left < (namelen + 3)) 2493 return (-1); 2494 2495 /* 2496 * stuff name in, then namelen, then node type, and finally, 2497 * the version for non-node nodes. 2498 */ 2499 for (i = 0; i < namelen; i++) 2500 log->log_num[--log->log_left] = name[i]; 2501 log->log_num[--log->log_left] = namelen; 2502 log->log_num[--log->log_left] = SYSCTL_TYPE(node->sysctl_flags); 2503 if (log->log_num[log->log_left] != CTLTYPE_NODE) 2504 log->log_num[--log->log_left] = node->sysctl_ver; 2505 else 2506 log->log_num[--log->log_left] = 0; 2507 2508 return (0); 2509 } 2510 2511 void 2512 sysctl_teardown(struct sysctllog **logp) 2513 { 2514 const struct sysctlnode *rnode; 2515 struct sysctlnode node; 2516 struct sysctllog *log; 2517 uint namelen; 2518 int *name, t, v, error, ni; 2519 size_t sz; 2520 2521 if (logp == NULL || *logp == NULL) 2522 return; 2523 log = *logp; 2524 2525 error = sysctl_lock(NULL, NULL, 0); 2526 if (error) 2527 return; 2528 2529 memset(&node, 0, sizeof(node)); 2530 2531 while (log->log_left < log->log_size) { 2532 KASSERT((log->log_left + 3 < log->log_size) && 2533 (log->log_left + log->log_num[log->log_left + 2] <= 2534 log->log_size)); 2535 v = log->log_num[log->log_left++]; 2536 t = log->log_num[log->log_left++]; 2537 namelen = log->log_num[log->log_left++]; 2538 name = &log->log_num[log->log_left]; 2539 2540 node.sysctl_num = name[namelen - 1]; 2541 node.sysctl_flags = SYSCTL_VERSION|t; 2542 node.sysctl_ver = v; 2543 2544 rnode = log->log_root; 2545 error = sysctl_locate(NULL, &name[0], namelen, &rnode, &ni); 2546 if (error == 0) { 2547 name[namelen - 1] = CTL_DESTROY; 2548 rnode = rnode->sysctl_parent; 2549 sz = 0; 2550 (void)sysctl_destroy(&name[namelen - 1], 1, NULL, 2551 &sz, &node, sizeof(node), 2552 &name[0], NULL, rnode); 2553 } 2554 2555 log->log_left += namelen; 2556 } 2557 2558 KASSERT(log->log_size == log->log_left); 2559 free(log->log_num, M_SYSCTLDATA); 2560 free(log, M_SYSCTLDATA); 2561 *logp = NULL; 2562 2563 sysctl_unlock(NULL); 2564 } 2565 2566 /* 2567 * ******************************************************************** 2568 * old_sysctl -- A routine to bridge old-style internal calls to the 2569 * new infrastructure. 2570 * ******************************************************************** 2571 */ 2572 int 2573 old_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 2574 void *newp, size_t newlen, struct lwp *l) 2575 { 2576 int error; 2577 size_t oldlen = 0; 2578 size_t savelen; 2579 2580 if (oldlenp) { 2581 oldlen = *oldlenp; 2582 } 2583 savelen = oldlen; 2584 2585 error = sysctl_lock(l, oldp, savelen); 2586 if (error) 2587 return (error); 2588 error = sysctl_dispatch(name, namelen, oldp, &oldlen, 2589 newp, newlen, name, l, NULL); 2590 sysctl_unlock(l); 2591 if (error == 0 && oldp != NULL && savelen < oldlen) 2592 error = ENOMEM; 2593 2594 if (oldlenp) { 2595 *oldlenp = oldlen; 2596 } 2597 2598 return (error); 2599 } 2600 2601 /* 2602 * ******************************************************************** 2603 * Section 4: Generic helper routines 2604 * ******************************************************************** 2605 * "helper" routines that can do more finely grained access control, 2606 * construct structures from disparate information, create the 2607 * appearance of more nodes and sub-trees, etc. for example, if 2608 * CTL_PROC wanted a helper function, it could respond to a CTL_QUERY 2609 * with a dynamically created list of nodes that represented the 2610 * currently running processes at that instant. 2611 * ******************************************************************** 2612 */ 2613 2614 /* 2615 * first, a few generic helpers that provide: 2616 * 2617 * sysctl_needfunc() a readonly interface that emits a warning 2618 * sysctl_notavail() returns EOPNOTSUPP (generic error) 2619 * sysctl_null() an empty return buffer with no error 2620 */ 2621 int 2622 sysctl_needfunc(SYSCTLFN_ARGS) 2623 { 2624 int error; 2625 2626 printf("!!SYSCTL_NEEDFUNC!!\n"); 2627 2628 if (newp != NULL || namelen != 0) 2629 return (EOPNOTSUPP); 2630 2631 error = 0; 2632 if (oldp != NULL) 2633 error = sysctl_copyout(l, rnode->sysctl_data, oldp, 2634 MIN(rnode->sysctl_size, *oldlenp)); 2635 *oldlenp = rnode->sysctl_size; 2636 2637 return (error); 2638 } 2639 2640 int 2641 sysctl_notavail(SYSCTLFN_ARGS) 2642 { 2643 2644 if (namelen == 1 && name[0] == CTL_QUERY) 2645 return (sysctl_query(SYSCTLFN_CALL(rnode))); 2646 2647 return (EOPNOTSUPP); 2648 } 2649 2650 int 2651 sysctl_null(SYSCTLFN_ARGS) 2652 { 2653 2654 *oldlenp = 0; 2655 2656 return (0); 2657 } 2658 2659 /* 2660 * ******************************************************************** 2661 * Section 5: The machinery that makes it all go 2662 * ******************************************************************** 2663 * Memory "manglement" routines. Not much to this, eh? 2664 * ******************************************************************** 2665 */ 2666 static int 2667 sysctl_alloc(struct sysctlnode *p, int x) 2668 { 2669 int i; 2670 struct sysctlnode *n; 2671 2672 assert(p->sysctl_child == NULL); 2673 2674 if (x == 1) 2675 n = malloc(sizeof(struct sysctlnode), 2676 M_SYSCTLNODE, M_WAITOK|M_CANFAIL); 2677 else 2678 n = malloc(SYSCTL_DEFSIZE * sizeof(struct sysctlnode), 2679 M_SYSCTLNODE, M_WAITOK|M_CANFAIL); 2680 if (n == NULL) 2681 return (ENOMEM); 2682 2683 if (x == 1) { 2684 memset(n, 0, sizeof(struct sysctlnode)); 2685 p->sysctl_csize = 1; 2686 } else { 2687 memset(n, 0, SYSCTL_DEFSIZE * sizeof(struct sysctlnode)); 2688 p->sysctl_csize = SYSCTL_DEFSIZE; 2689 } 2690 p->sysctl_clen = 0; 2691 2692 for (i = 0; i < p->sysctl_csize; i++) 2693 n[i].sysctl_parent = p; 2694 2695 p->sysctl_child = n; 2696 return (0); 2697 } 2698 2699 static int 2700 sysctl_realloc(struct sysctlnode *p) 2701 { 2702 int i, j; 2703 struct sysctlnode *n; 2704 2705 assert(p->sysctl_csize == p->sysctl_clen); 2706 2707 /* 2708 * how many do we have...how many should we make? 2709 */ 2710 i = p->sysctl_clen; 2711 n = malloc(2 * i * sizeof(struct sysctlnode), M_SYSCTLNODE, 2712 M_WAITOK|M_CANFAIL); 2713 if (n == NULL) 2714 return (ENOMEM); 2715 2716 /* 2717 * move old children over...initialize new children 2718 */ 2719 memcpy(n, p->sysctl_child, i * sizeof(struct sysctlnode)); 2720 memset(&n[i], 0, i * sizeof(struct sysctlnode)); 2721 p->sysctl_csize = 2 * i; 2722 2723 /* 2724 * reattach moved (and new) children to parent; if a moved 2725 * child node has children, reattach the parent pointers of 2726 * grandchildren 2727 */ 2728 for (i = 0; i < p->sysctl_csize; i++) { 2729 n[i].sysctl_parent = p; 2730 if (n[i].sysctl_child != NULL) { 2731 for (j = 0; j < n[i].sysctl_csize; j++) 2732 n[i].sysctl_child[j].sysctl_parent = &n[i]; 2733 } 2734 } 2735 2736 /* 2737 * get out with the old and in with the new 2738 */ 2739 free(p->sysctl_child, M_SYSCTLNODE); 2740 p->sysctl_child = n; 2741 2742 return (0); 2743 } 2744 2745 static int 2746 sysctl_log_realloc(struct sysctllog *log) 2747 { 2748 int *n, s, d; 2749 2750 s = log->log_size * 2; 2751 d = log->log_size; 2752 2753 n = malloc(s * sizeof(int), M_SYSCTLDATA, M_WAITOK|M_CANFAIL); 2754 if (n == NULL) 2755 return (-1); 2756 2757 memset(n, 0, s * sizeof(int)); 2758 memcpy(&n[d], log->log_num, d * sizeof(int)); 2759 free(log->log_num, M_SYSCTLDATA); 2760 log->log_num = n; 2761 if (d) 2762 log->log_left += d; 2763 else 2764 log->log_left = s; 2765 log->log_size = s; 2766 2767 return (0); 2768 } 2769 2770 /* 2771 * ******************************************************************** 2772 * Section 6: Conversion between API versions wrt the sysctlnode 2773 * ******************************************************************** 2774 */ 2775 static int 2776 sysctl_cvt_in(struct lwp *l, int *vp, const void *i, size_t sz, 2777 struct sysctlnode *node) 2778 { 2779 int error, flags; 2780 2781 if (i == NULL || sz < sizeof(flags)) 2782 return (EINVAL); 2783 2784 error = sysctl_copyin(l, i, &flags, sizeof(flags)); 2785 if (error) 2786 return (error); 2787 2788 #if (SYSCTL_VERSION != SYSCTL_VERS_1) 2789 #error sysctl_cvt_in: no support for SYSCTL_VERSION 2790 #endif /* (SYSCTL_VERSION != SYSCTL_VERS_1) */ 2791 2792 if (sz == sizeof(*node) && 2793 SYSCTL_VERS(flags) == SYSCTL_VERSION) { 2794 error = sysctl_copyin(l, i, node, sizeof(*node)); 2795 if (error) 2796 return (error); 2797 *vp = SYSCTL_VERSION; 2798 return (0); 2799 } 2800 2801 return (EINVAL); 2802 } 2803 2804 static int 2805 sysctl_cvt_out(struct lwp *l, int v, const struct sysctlnode *i, 2806 void *ovp, size_t left, size_t *szp) 2807 { 2808 size_t sz = sizeof(*i); 2809 const void *src = i; 2810 int error; 2811 2812 switch (v) { 2813 case SYSCTL_VERS_0: 2814 return (EINVAL); 2815 2816 #if (SYSCTL_VERSION != SYSCTL_VERS_1) 2817 #error sysctl_cvt_out: no support for SYSCTL_VERSION 2818 #endif /* (SYSCTL_VERSION != SYSCTL_VERS_1) */ 2819 2820 case SYSCTL_VERSION: 2821 /* nothing more to do here */ 2822 break; 2823 } 2824 2825 if (ovp != NULL && left >= sz) { 2826 error = sysctl_copyout(l, src, ovp, sz); 2827 if (error) 2828 return (error); 2829 } 2830 2831 if (szp != NULL) 2832 *szp = sz; 2833 2834 return (0); 2835 } 2836