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