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