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