kern_sysctl.c revision 12280
1/*- 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Mike Karels at Berkeley Software Design, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 37 * $Id: kern_sysctl.c,v 1.41 1995/11/14 09:07:14 phk Exp $ 38 */ 39 40/* 41 * sysctl system call. 42 */ 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/sysproto.h> 47#include <sys/kernel.h> 48#include <sys/malloc.h> 49#include <sys/proc.h> 50#include <sys/file.h> 51#include <sys/vnode.h> 52#include <sys/unistd.h> 53#include <sys/buf.h> 54#include <sys/ioctl.h> 55#include <sys/tty.h> 56#include <sys/conf.h> 57#include <vm/vm.h> 58#include <sys/sysctl.h> 59#include <sys/user.h> 60 61extern struct linker_set sysctl_; 62 63/* BEGIN_MIB */ 64SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, 65 "Sysctl internal magic"); 66SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, 67 "High kernel, proc, limits &c"); 68SYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, 69 "Virtual memory"); 70SYSCTL_NODE(, CTL_FS, fs, CTLFLAG_RW, 0, 71 "File system"); 72SYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, 73 "Network, (see socket.h)"); 74SYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, 75 "Debugging"); 76SYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, 77 "hardware"); 78SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, 79 "machine dependent"); 80SYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, 81 "user-level"); 82 83SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, ""); 84 85SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, ""); 86 87SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, ""); 88 89SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, ""); 90 91extern int osreldate; 92SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, ""); 93 94SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 95 96SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, ""); 97 98SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, 99 CTLFLAG_RD, &maxprocperuid, 0, ""); 100 101SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, 102 CTLFLAG_RD, &maxfilesperproc, 0, ""); 103 104SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, ""); 105 106SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, ""); 107 108SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, ""); 109 110SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, ""); 111 112SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, ""); 113 114#ifdef _POSIX_SAVED_IDS 115SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, ""); 116#else 117SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, ""); 118#endif 119 120char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ 121 122SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, 123 CTLFLAG_RW, kernelname, sizeof kernelname, ""); 124 125SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, 126 CTLFLAG_RW, &boottime, timeval, ""); 127 128SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 129 130SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 131 132SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, ""); 133 134SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, ""); 135 136SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, ""); 137 138/* END_MIB */ 139 140extern int vfs_update_wakeup; 141extern int vfs_update_interval; 142static int 143sysctl_kern_updateinterval SYSCTL_HANDLER_ARGS 144{ 145 int error = sysctl_handle_int(oidp, 146 oidp->oid_arg1, oidp->oid_arg2, req); 147 if (!error) 148 wakeup(&vfs_update_wakeup); 149 return error; 150} 151 152SYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW, 153 &vfs_update_interval, 0, sysctl_kern_updateinterval, ""); 154 155 156char hostname[MAXHOSTNAMELEN]; 157int hostnamelen; 158static int 159sysctl_kern_hostname SYSCTL_HANDLER_ARGS 160{ 161 int error = sysctl_handle_string(oidp, 162 oidp->oid_arg1, oidp->oid_arg2, req); 163 if (req->newptr && (error == 0 || error == ENOMEM)) 164 hostnamelen = req->newlen; 165 return error; 166} 167 168SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW, 169 &hostname, sizeof(hostname), sysctl_kern_hostname, ""); 170 171static int 172sysctl_order_cmp(const void *a, const void *b) 173{ 174 const struct sysctl_oid **pa, **pb; 175 176 pa = (const struct sysctl_oid **)a; 177 pb = (const struct sysctl_oid **)b; 178 if (*pa == NULL) 179 return (1); 180 if (*pb == NULL) 181 return (-1); 182 return ((*pa)->oid_number - (*pb)->oid_number); 183} 184 185static void 186sysctl_order(void *arg) 187{ 188 int j; 189 struct linker_set *l = (struct linker_set *) arg; 190 struct sysctl_oid **oidpp; 191 192 j = l->ls_length; 193 oidpp = (struct sysctl_oid **) l->ls_items; 194 for (; j--; oidpp++) { 195 if (!*oidpp) 196 continue; 197 if ((*oidpp)->oid_arg1 == arg) { 198 *oidpp = 0; 199 continue; 200 } 201 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 202 if (!(*oidpp)->oid_handler) 203 sysctl_order((*oidpp)->oid_arg1); 204 } 205 qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 206 sysctl_order_cmp); 207} 208 209SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_); 210 211static void 212sysctl_sysctl_debug_dump_node(struct linker_set *l, int i) 213{ 214 int j, k; 215 struct sysctl_oid **oidpp; 216 217 j = l->ls_length; 218 oidpp = (struct sysctl_oid **) l->ls_items; 219 for (; j--; oidpp++) { 220 221 if (!*oidpp) 222 continue; 223 224 for (k=0; k<i; k++) 225 printf(" "); 226 227 if ((*oidpp)->oid_number > 100) { 228 printf("Junk! %p # %d %s k %x a1 %p a2 %x h %p\n", 229 *oidpp, 230 (*oidpp)->oid_number, (*oidpp)->oid_name, 231 (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 232 (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 233 continue; 234 } 235 printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 236 237 printf("%c%c", 238 (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 239 (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 240 241 switch ((*oidpp)->oid_kind & CTLTYPE) { 242 case CTLTYPE_NODE: 243 if ((*oidpp)->oid_handler) { 244 printf(" Node(proc)\n"); 245 } else { 246 printf(" Node\n"); 247 sysctl_sysctl_debug_dump_node( 248 (*oidpp)->oid_arg1, i+2); 249 } 250 break; 251 case CTLTYPE_INT: printf(" Int\n"); break; 252 case CTLTYPE_STRING: printf(" String\n"); break; 253 case CTLTYPE_QUAD: printf(" Quad\n"); break; 254 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 255 default: printf("\n"); 256 } 257 258 } 259} 260 261 262static int 263sysctl_sysctl_debug SYSCTL_HANDLER_ARGS 264{ 265 sysctl_sysctl_debug_dump_node(&sysctl_, 0); 266 return ENOENT; 267} 268 269SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 270 0, 0, sysctl_sysctl_debug, ""); 271 272char domainname[MAXHOSTNAMELEN]; 273SYSCTL_STRING(_kern, KERN_DOMAINNAME, domainname, CTLFLAG_RW, 274 &domainname, sizeof(domainname), ""); 275 276long hostid; 277/* Some trouble here, if sizeof (int) != sizeof (long) */ 278SYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, ""); 279 280/* 281 * Handle an integer, signed or unsigned. 282 * Two cases: 283 * a variable: point arg1 at it. 284 * a constant: pass it in arg2. 285 */ 286 287int 288sysctl_handle_int SYSCTL_HANDLER_ARGS 289{ 290 int error = 0; 291 292 if (arg1) 293 error = SYSCTL_OUT(req, arg1, sizeof(int)); 294 else if (arg2) 295 error = SYSCTL_OUT(req, &arg2, sizeof(int)); 296 297 if (error || !req->newptr) 298 return (error); 299 300 if (!arg1) 301 error = EPERM; 302 else 303 error = SYSCTL_IN(req, arg1, sizeof(int)); 304 return (error); 305} 306 307/* 308 * Handle our generic '\0' terminated 'C' string. 309 * Two cases: 310 * a variable string: point arg1 at it, arg2 is max length. 311 * a constant string: point arg1 at it, arg2 is zero. 312 */ 313 314int 315sysctl_handle_string SYSCTL_HANDLER_ARGS 316{ 317 int error=0; 318 319 if (arg2) 320 error = SYSCTL_OUT(req, arg1, arg2); 321 else 322 error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 323 324 if (error || !req->newptr || !arg2) 325 return (error); 326 327 if ((req->newlen - req->newidx) > arg2) { 328 error = E2BIG; 329 } else { 330 arg2 = (req->newlen - req->newidx); 331 error = SYSCTL_IN(req, arg1, arg2); 332 ((char *)arg1)[arg2] = '\0'; 333 } 334 335 return (error); 336} 337 338/* 339 * Handle any kind of opaque data. 340 * arg1 points to it, arg2 is the size. 341 */ 342 343int 344sysctl_handle_opaque SYSCTL_HANDLER_ARGS 345{ 346 int error; 347 348 error = SYSCTL_OUT(req, arg1, arg2); 349 350 if (error || !req->newptr) 351 return (error); 352 353 error = SYSCTL_IN(req, arg1, arg2); 354 355 return (error); 356} 357 358/* 359 * Transfer functions to/from kernel space. 360 * XXX: rather untested at this point 361 */ 362static int 363sysctl_old_kernel(struct sysctl_req *req, void *p, int l) 364{ 365 int i = 0; 366 367 if (req->oldptr) { 368 i = min(req->oldlen - req->oldidx, l); 369 if (i > 0) 370 bcopy(p, req->oldptr + req->oldidx, i); 371 } 372 req->oldidx += l; 373 if (i != l) 374 return (ENOMEM); 375 return (0); 376 377} 378 379static int 380sysctl_new_kernel(struct sysctl_req *req, void *p, int l) 381{ 382 int i; 383 if (!req->newptr) 384 return 0; 385 if (req->newlen - req->newidx < l) 386 return (EINVAL); 387 bcopy(req->newptr + req->newidx, p, l); 388 req->newidx += l; 389 return (0); 390} 391 392/* 393 * Transfer function to/from user space. 394 */ 395static int 396sysctl_old_user(struct sysctl_req *req, void *p, int l) 397{ 398 int error = 0, i = 0; 399 400 if (req->oldptr) { 401 i = min(req->oldlen - req->oldidx, l); 402 if (i > 0) 403 error = copyout(p, req->oldptr + req->oldidx, i); 404 } 405 req->oldidx += l; 406 if (error) 407 return (error); 408 if (req->oldptr && i < l) 409 return (ENOMEM); 410 return (0); 411} 412 413static int 414sysctl_new_user(struct sysctl_req *req, void *p, int l) 415{ 416 int error, i; 417 418 if (!req->newptr) 419 return 0; 420 if (req->newlen - req->newidx < l) 421 return (EINVAL); 422 error = copyin(req->newptr + req->newidx, p, l); 423 req->newidx += l; 424 return (error); 425} 426 427#ifdef DEBUG 428static sysctlfn debug_sysctl; 429#endif 430 431/* 432 * Locking and stats 433 */ 434static struct sysctl_lock { 435 int sl_lock; 436 int sl_want; 437 int sl_locked; 438} memlock; 439 440 441 442/* 443 * Traverse our tree, and find the right node, execute whatever it points 444 * at, and return the resulting error code. 445 * We work entirely in kernel-space at this time. 446 */ 447 448 449int 450sysctl_root SYSCTL_HANDLER_ARGS 451{ 452 int *name = (int *) arg1; 453 int namelen = arg2; 454 int indx, i, j; 455 struct sysctl_oid **oidpp; 456 struct linker_set *lsp = &sysctl_; 457 458 j = lsp->ls_length; 459 oidpp = (struct sysctl_oid **) lsp->ls_items; 460 461 indx = 0; 462 while (j-- && indx < CTL_MAXNAME) { 463 if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 464 indx++; 465 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 466 if ((*oidpp)->oid_handler) 467 goto found; 468 if (indx == namelen) 469 return ENOENT; 470 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 471 j = lsp->ls_length; 472 oidpp = (struct sysctl_oid **)lsp->ls_items; 473 } else { 474 if (indx != namelen) 475 return EISDIR; 476 goto found; 477 } 478 } else { 479 oidpp++; 480 } 481 } 482 return ENOENT; 483found: 484 485 /* If writing isn't allowed */ 486 if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR)) 487 return (EPERM); 488 489 if (!(*oidpp)->oid_handler) 490 return EINVAL; 491 492 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 493 i = ((*oidpp)->oid_handler) (*oidpp, 494 name + indx, namelen - indx, 495 req); 496 } else { 497 i = ((*oidpp)->oid_handler) (*oidpp, 498 (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 499 req); 500 } 501 return (i); 502} 503 504#ifndef _SYS_SYSPROTO_H_ 505struct sysctl_args { 506 int *name; 507 u_int namelen; 508 void *old; 509 size_t *oldlenp; 510 void *new; 511 size_t newlen; 512}; 513#endif 514 515int 516__sysctl(p, uap, retval) 517 struct proc *p; 518 register struct sysctl_args *uap; 519 int *retval; 520{ 521 int error, i, j, name[CTL_MAXNAME]; 522 523 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 524 return (EINVAL); 525 526 error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 527 if (error) 528 return (error); 529 530 error = userland_sysctl(p, name, uap->namelen, 531 uap->old, uap->oldlenp, 0, 532 uap->new, uap->newlen, &j); 533 if (error && error != ENOMEM) 534 return (error); 535 if (uap->oldlenp) { 536 i = copyout(&j, uap->oldlenp, sizeof(j)); 537 if (i) 538 return (i); 539 } 540 return (error); 541} 542 543static sysctlfn kern_sysctl; 544 545/* 546 * This is used from various compatibility syscalls too. That's why name 547 * must be in kernel space. 548 */ 549int 550userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 551{ 552 int error = 0, dolock = 1, i, oldlen = 0; 553 u_int savelen = 0; 554 sysctlfn *fn; 555 struct sysctl_req req; 556 557 bzero(&req, sizeof req); 558 559 if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 560 return (error); 561 562 if (oldlenp) { 563 if (inkernel) { 564 req.oldlen = *oldlenp; 565 } else { 566 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 567 if (error) 568 return (error); 569 } 570 } 571 572 if (old) { 573 if (!useracc(old, req.oldlen, B_WRITE)) 574 return (EFAULT); 575 req.oldptr= old; 576 } 577 578 if (newlen) { 579 if (!useracc(new, req.newlen, B_READ)) 580 return (EFAULT); 581 req.newlen = newlen; 582 req.newptr = new; 583 } 584 585 req.oldfunc = sysctl_old_user; 586 req.newfunc = sysctl_new_user; 587 588 error = sysctl_root(0, name, namelen, &req); 589 590/* 591 if (error && error != ENOMEM) 592 return (error); 593*/ 594 if (error == ENOENT) 595 goto oldstuff; 596 597 if (retval) { 598 if (req.oldptr && req.oldidx > req.oldlen) 599 *retval = req.oldlen; 600 else 601 *retval = req.oldidx; 602 } 603 return (error); 604 605oldstuff: 606 oldlen = req.oldlen; 607 608 switch (name[0]) { 609 case CTL_KERN: 610 fn = kern_sysctl; 611 if (name[1] != KERN_VNODE) /* XXX */ 612 dolock = 0; 613 break; 614 case CTL_HW: 615 fn = hw_sysctl; 616 break; 617 case CTL_VM: 618 fn = vm_sysctl; 619 break; 620 case CTL_NET: 621 fn = net_sysctl; 622 break; 623 case CTL_FS: 624 fn = fs_sysctl; 625 break; 626#ifdef DEBUG 627 case CTL_DEBUG: 628 fn = debug_sysctl; 629 break; 630#endif 631 default: 632 return (EOPNOTSUPP); 633 } 634 if (old != NULL) { 635 if (!useracc(old, oldlen, B_WRITE)) 636 return (EFAULT); 637 while (memlock.sl_lock) { 638 memlock.sl_want = 1; 639 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 640 memlock.sl_locked++; 641 } 642 memlock.sl_lock = 1; 643 if (dolock) 644 vslock(old, oldlen); 645 savelen = oldlen; 646 } 647 648 649 error = (*fn)(name + 1, namelen - 1, old, &oldlen, 650 new, newlen, p); 651 652 653 if (old != NULL) { 654 if (dolock) 655 vsunlock(old, savelen, B_WRITE); 656 memlock.sl_lock = 0; 657 if (memlock.sl_want) { 658 memlock.sl_want = 0; 659 wakeup((caddr_t)&memlock); 660 } 661 } 662#if 0 663 if (error) { 664 printf("SYSCTL_ERROR: "); 665 for(i=0;i<namelen;i++) 666 printf("%d ", name[i]); 667 printf("= %d\n", error); 668 } 669#endif 670 if (error) 671 return (error); 672 if (retval) 673 *retval = oldlen; 674 return (error); 675} 676 677/* 678 * Attributes stored in the kernel. 679 */ 680int securelevel = -1; 681 682/* 683 * kernel related system variables. 684 */ 685static int 686kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 687 int *name; 688 u_int namelen; 689 void *oldp; 690 size_t *oldlenp; 691 void *newp; 692 size_t newlen; 693 struct proc *p; 694{ 695 int error, level; 696 dev_t ndumpdev; 697 698 /* all sysctl names at this level are terminal */ 699 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 700 || name[0] == KERN_NTP_PLL)) 701 return (ENOTDIR); /* overloaded */ 702 703 switch (name[0]) { 704 705 case KERN_SECURELVL: 706 level = securelevel; 707 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 708 newp == NULL) 709 return (error); 710 if (level < securelevel && p->p_pid != 1) 711 return (EPERM); 712 securelevel = level; 713 return (0); 714 case KERN_VNODE: 715 return (sysctl_vnode(oldp, oldlenp)); 716#ifdef GPROF 717 case KERN_PROF: 718 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 719 newp, newlen)); 720#endif 721 case KERN_DUMPDEV: 722 ndumpdev = dumpdev; 723 error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev, 724 sizeof ndumpdev); 725 if (!error && ndumpdev != dumpdev) { 726 error = setdumpdev(ndumpdev); 727 } 728 return error; 729 default: 730 return (EOPNOTSUPP); 731 } 732 /* NOTREACHED */ 733} 734 735/* 736 * hardware related system variables. 737 */ 738int 739hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 740 int *name; 741 u_int namelen; 742 void *oldp; 743 size_t *oldlenp; 744 void *newp; 745 size_t newlen; 746 struct proc *p; 747{ 748 /* almost all sysctl names at this level are terminal */ 749 if (namelen != 1 && name[0] != HW_DEVCONF) 750 return (ENOTDIR); /* overloaded */ 751 752 switch (name[0]) { 753 case HW_PHYSMEM: 754 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 755 case HW_USERMEM: 756 return (sysctl_rdint(oldp, oldlenp, newp, 757 ctob(physmem - cnt.v_wire_count))); 758 case HW_DEVCONF: 759 return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 760 newp, newlen, p)); 761 default: 762 return (EOPNOTSUPP); 763 } 764 /* NOTREACHED */ 765} 766 767#ifdef DEBUG 768/* 769 * Debugging related system variables. 770 */ 771struct ctldebug debug0, debug1, debug2, debug3, debug4; 772struct ctldebug debug5, debug6, debug7, debug8, debug9; 773struct ctldebug debug10, debug11, debug12, debug13, debug14; 774struct ctldebug debug15, debug16, debug17, debug18, debug19; 775static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 776 &debug0, &debug1, &debug2, &debug3, &debug4, 777 &debug5, &debug6, &debug7, &debug8, &debug9, 778 &debug10, &debug11, &debug12, &debug13, &debug14, 779 &debug15, &debug16, &debug17, &debug18, &debug19, 780}; 781static int 782debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 783 int *name; 784 u_int namelen; 785 void *oldp; 786 size_t *oldlenp; 787 void *newp; 788 size_t newlen; 789 struct proc *p; 790{ 791 struct ctldebug *cdp; 792 793 /* all sysctl names at this level are name and field */ 794 if (namelen != 2) 795 return (ENOTDIR); /* overloaded */ 796 cdp = debugvars[name[0]]; 797 if (cdp->debugname == 0) 798 return (EOPNOTSUPP); 799 switch (name[1]) { 800 case CTL_DEBUG_NAME: 801 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 802 case CTL_DEBUG_VALUE: 803 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 804 default: 805 return (EOPNOTSUPP); 806 } 807 /* NOTREACHED */ 808} 809#endif /* DEBUG */ 810 811/* 812 * Validate parameters and get old / set new parameters 813 * for an integer-valued sysctl function. 814 */ 815int 816sysctl_int(oldp, oldlenp, newp, newlen, valp) 817 void *oldp; 818 size_t *oldlenp; 819 void *newp; 820 size_t newlen; 821 int *valp; 822{ 823 int error = 0; 824 825 if (oldp && *oldlenp < sizeof(int)) 826 return (ENOMEM); 827 if (newp && newlen != sizeof(int)) 828 return (EINVAL); 829 *oldlenp = sizeof(int); 830 if (oldp) 831 error = copyout(valp, oldp, sizeof(int)); 832 if (error == 0 && newp) 833 error = copyin(newp, valp, sizeof(int)); 834 return (error); 835} 836 837/* 838 * As above, but read-only. 839 */ 840int 841sysctl_rdint(oldp, oldlenp, newp, val) 842 void *oldp; 843 size_t *oldlenp; 844 void *newp; 845 int val; 846{ 847 int error = 0; 848 849 if (oldp && *oldlenp < sizeof(int)) 850 return (ENOMEM); 851 if (newp) 852 return (EPERM); 853 *oldlenp = sizeof(int); 854 if (oldp) 855 error = copyout((caddr_t)&val, oldp, sizeof(int)); 856 return (error); 857} 858 859/* 860 * Validate parameters and get old / set new parameters 861 * for a string-valued sysctl function. 862 */ 863int 864sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 865 void *oldp; 866 size_t *oldlenp; 867 void *newp; 868 size_t newlen; 869 char *str; 870 int maxlen; 871{ 872 int len, error = 0, rval = 0; 873 874 len = strlen(str) + 1; 875 if (oldp && *oldlenp < len) { 876 len = *oldlenp; 877 rval = ENOMEM; 878 } 879 if (newp && newlen >= maxlen) 880 return (EINVAL); 881 if (oldp) { 882 *oldlenp = len; 883 error = copyout(str, oldp, len); 884 if (error) 885 rval = error; 886 } 887 if ((error == 0 || error == ENOMEM) && newp) { 888 error = copyin(newp, str, newlen); 889 if (error) 890 rval = error; 891 str[newlen] = 0; 892 } 893 return (rval); 894} 895 896/* 897 * As above, but read-only. 898 */ 899int 900sysctl_rdstring(oldp, oldlenp, newp, str) 901 void *oldp; 902 size_t *oldlenp; 903 void *newp; 904 char *str; 905{ 906 int len, error = 0, rval = 0; 907 908 len = strlen(str) + 1; 909 if (oldp && *oldlenp < len) { 910 len = *oldlenp; 911 rval = ENOMEM; 912 } 913 if (newp) 914 return (EPERM); 915 *oldlenp = len; 916 if (oldp) 917 error = copyout(str, oldp, len); 918 if (error) 919 rval = error; 920 return (rval); 921} 922 923/* 924 * Validate parameters and get old / set new parameters 925 * for a structure oriented sysctl function. 926 */ 927int 928sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 929 void *oldp; 930 size_t *oldlenp; 931 void *newp; 932 size_t newlen; 933 void *sp; 934 int len; 935{ 936 int error = 0; 937 938 if (oldp && *oldlenp < len) 939 return (ENOMEM); 940 if (newp && newlen > len) 941 return (EINVAL); 942 if (oldp) { 943 *oldlenp = len; 944 error = copyout(sp, oldp, len); 945 } 946 if (error == 0 && newp) 947 error = copyin(newp, sp, len); 948 return (error); 949} 950 951/* 952 * Validate parameters and get old parameters 953 * for a structure oriented sysctl function. 954 */ 955int 956sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 957 void *oldp; 958 size_t *oldlenp; 959 void *newp, *sp; 960 int len; 961{ 962 int error = 0; 963 964 if (oldp && *oldlenp < len) 965 return (ENOMEM); 966 if (newp) 967 return (EPERM); 968 *oldlenp = len; 969 if (oldp) 970 error = copyout(sp, oldp, len); 971 return (error); 972} 973 974#ifdef COMPAT_43 975#include <sys/socket.h> 976#define KINFO_PROC (0<<8) 977#define KINFO_RT (1<<8) 978#define KINFO_VNODE (2<<8) 979#define KINFO_FILE (3<<8) 980#define KINFO_METER (4<<8) 981#define KINFO_LOADAVG (5<<8) 982#define KINFO_CLOCKRATE (6<<8) 983 984/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 985#define KINFO_BSDI_SYSINFO (101<<8) 986 987/* 988 * XXX this is bloat, but I hope it's better here than on the potentially 989 * limited kernel stack... -Peter 990 */ 991 992struct { 993 int bsdi_machine; /* "i386" on BSD/386 */ 994/* ^^^ this is an offset to the string, relative to the struct start */ 995 char *pad0; 996 long pad1; 997 long pad2; 998 long pad3; 999 u_long pad4; 1000 u_long pad5; 1001 u_long pad6; 1002 1003 int bsdi_ostype; /* "BSD/386" on BSD/386 */ 1004 int bsdi_osrelease; /* "1.1" on BSD/386 */ 1005 long pad7; 1006 long pad8; 1007 char *pad9; 1008 1009 long pad10; 1010 long pad11; 1011 int pad12; 1012 long pad13; 1013 quad_t pad14; 1014 long pad15; 1015 1016 struct timeval pad16; 1017 /* we dont set this, because BSDI's uname used gethostname() instead */ 1018 int bsdi_hostname; /* hostname on BSD/386 */ 1019 1020 /* the actual string data is appended here */ 1021 1022} bsdi_si; 1023/* 1024 * this data is appended to the end of the bsdi_si structure during copyout. 1025 * The "char *" offsets are relative to the base of the bsdi_si struct. 1026 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 1027 * should not exceed the length of the buffer here... (or else!! :-) 1028 */ 1029char bsdi_strings[80]; /* It had better be less than this! */ 1030 1031#ifndef _SYS_SYSPROTO_H_ 1032struct getkerninfo_args { 1033 int op; 1034 char *where; 1035 int *size; 1036 int arg; 1037}; 1038#endif 1039 1040int 1041ogetkerninfo(p, uap, retval) 1042 struct proc *p; 1043 register struct getkerninfo_args *uap; 1044 int *retval; 1045{ 1046 int error, name[6]; 1047 u_int size; 1048 1049 switch (uap->op & 0xff00) { 1050 1051 case KINFO_RT: 1052 name[0] = CTL_NET; 1053 name[1] = PF_ROUTE; 1054 name[2] = 0; 1055 name[3] = (uap->op & 0xff0000) >> 16; 1056 name[4] = uap->op & 0xff; 1057 name[5] = uap->arg; 1058 error = userland_sysctl(p, name, 6, uap->where, uap->size, 1059 0, 0, 0, 0); 1060 break; 1061 1062 case KINFO_VNODE: 1063 name[0] = CTL_KERN; 1064 name[1] = KERN_VNODE; 1065 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1066 0, 0, 0, 0); 1067 break; 1068 1069 case KINFO_PROC: 1070 name[0] = CTL_KERN; 1071 name[1] = KERN_PROC; 1072 name[2] = uap->op & 0xff; 1073 name[3] = uap->arg; 1074 error = userland_sysctl(p, name, 4, uap->where, uap->size, 1075 0, 0, 0, 0); 1076 break; 1077 1078 case KINFO_FILE: 1079 name[0] = CTL_KERN; 1080 name[1] = KERN_FILE; 1081 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1082 0, 0, 0, 0); 1083 break; 1084 1085 case KINFO_METER: 1086 name[0] = CTL_VM; 1087 name[1] = VM_METER; 1088 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1089 0, 0, 0, 0); 1090 break; 1091 1092 case KINFO_LOADAVG: 1093 name[0] = CTL_VM; 1094 name[1] = VM_LOADAVG; 1095 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1096 0, 0, 0, 0); 1097 break; 1098 1099 case KINFO_CLOCKRATE: 1100 name[0] = CTL_KERN; 1101 name[1] = KERN_CLOCKRATE; 1102 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1103 0, 0, 0, 0); 1104 break; 1105 1106 case KINFO_BSDI_SYSINFO: { 1107 /* 1108 * this is pretty crude, but it's just enough for uname() 1109 * from BSDI's 1.x libc to work. 1110 * 1111 * In particular, it doesn't return the same results when 1112 * the supplied buffer is too small. BSDI's version apparently 1113 * will return the amount copied, and set the *size to how 1114 * much was needed. The emulation framework here isn't capable 1115 * of that, so we just set both to the amount copied. 1116 * BSDI's 2.x product apparently fails with ENOMEM in this 1117 * scenario. 1118 */ 1119 1120 u_int needed; 1121 u_int left; 1122 char *s; 1123 1124 bzero((char *)&bsdi_si, sizeof(bsdi_si)); 1125 bzero(bsdi_strings, sizeof(bsdi_strings)); 1126 1127 s = bsdi_strings; 1128 1129 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 1130 strcpy(s, ostype); 1131 s += strlen(s) + 1; 1132 1133 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 1134 strcpy(s, osrelease); 1135 s += strlen(s) + 1; 1136 1137 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 1138 strcpy(s, machine); 1139 s += strlen(s) + 1; 1140 1141 needed = sizeof(bsdi_si) + (s - bsdi_strings); 1142 1143 if (uap->where == NULL) { 1144 /* process is asking how much buffer to supply.. */ 1145 size = needed; 1146 error = 0; 1147 break; 1148 } 1149 1150 1151 /* if too much buffer supplied, trim it down */ 1152 if (size > needed) 1153 size = needed; 1154 1155 /* how much of the buffer is remaining */ 1156 left = size; 1157 1158 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 1159 break; 1160 1161 /* is there any point in continuing? */ 1162 if (left > sizeof(bsdi_si)) { 1163 left -= sizeof(bsdi_si); 1164 error = copyout(&bsdi_strings, 1165 uap->where + sizeof(bsdi_si), left); 1166 } 1167 break; 1168 } 1169 1170 default: 1171 return (EOPNOTSUPP); 1172 } 1173 if (error) 1174 return (error); 1175 *retval = size; 1176 if (uap->size) 1177 error = copyout((caddr_t)&size, (caddr_t)uap->size, 1178 sizeof(size)); 1179 return (error); 1180} 1181#endif /* COMPAT_43 */ 1182