kern_sysctl.c revision 12288
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.47 1995/11/14 09:37:22 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 default: 606 return (EOPNOTSUPP); 607 } 608 if (old != NULL) { 609 if (!useracc(old, oldlen, B_WRITE)) 610 return (EFAULT); 611 while (memlock.sl_lock) { 612 memlock.sl_want = 1; 613 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 614 memlock.sl_locked++; 615 } 616 memlock.sl_lock = 1; 617 if (dolock) 618 vslock(old, oldlen); 619 savelen = oldlen; 620 } 621 622 623 error = (*fn)(name + 1, namelen - 1, old, &oldlen, 624 new, newlen, p); 625 626 627 if (old != NULL) { 628 if (dolock) 629 vsunlock(old, savelen, B_WRITE); 630 memlock.sl_lock = 0; 631 if (memlock.sl_want) { 632 memlock.sl_want = 0; 633 wakeup((caddr_t)&memlock); 634 } 635 } 636#if 0 637 if (error) { 638 printf("SYSCTL_ERROR: "); 639 for(i=0;i<namelen;i++) 640 printf("%d ", name[i]); 641 printf("= %d\n", error); 642 } 643#endif 644 if (error) 645 return (error); 646 if (retval) 647 *retval = oldlen; 648 return (error); 649} 650 651/* 652 * Attributes stored in the kernel. 653 */ 654int securelevel = -1; 655 656/* 657 * kernel related system variables. 658 */ 659static int 660kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 661 int *name; 662 u_int namelen; 663 void *oldp; 664 size_t *oldlenp; 665 void *newp; 666 size_t newlen; 667 struct proc *p; 668{ 669 670 /* all sysctl names at this level are terminal */ 671 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 672 || name[0] == KERN_NTP_PLL)) 673 return (ENOTDIR); /* overloaded */ 674 675 switch (name[0]) { 676 677 case KERN_VNODE: 678 return (sysctl_vnode(oldp, oldlenp)); 679#ifdef GPROF 680 case KERN_PROF: 681 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 682 newp, newlen)); 683#endif 684 default: 685 return (EOPNOTSUPP); 686 } 687 /* NOTREACHED */ 688} 689 690static int 691sysctl_kern_securelvl SYSCTL_HANDLER_ARGS 692{ 693 int error, level; 694 695 level = securelevel; 696 error = sysctl_handle_int(oidp, &level, 0, req); 697 if (error || !req->newptr) 698 return (error); 699 if (level < securelevel && req->p->p_pid != 1) 700 return (EPERM); 701 securelevel = level; 702 return (error); 703} 704 705SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW, 706 0, 0, sysctl_kern_securelvl, ""); 707 708static int 709sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS 710{ 711 int error; 712 dev_t ndumpdev; 713 714 ndumpdev = dumpdev; 715 error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req); 716 if (!error && ndumpdev != dumpdev) { 717 error = setdumpdev(ndumpdev); 718 } 719 return (error); 720} 721 722SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, 723 0, sizeof dumpdev, sysctl_kern_dumpdev, ""); 724/* 725 * hardware related system variables. 726 */ 727int 728hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 729 int *name; 730 u_int namelen; 731 void *oldp; 732 size_t *oldlenp; 733 void *newp; 734 size_t newlen; 735 struct proc *p; 736{ 737 /* almost all sysctl names at this level are terminal */ 738 if (namelen != 1 && name[0] != HW_DEVCONF) 739 return (ENOTDIR); /* overloaded */ 740 741 switch (name[0]) { 742 case HW_PHYSMEM: 743 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 744 case HW_USERMEM: 745 return (sysctl_rdint(oldp, oldlenp, newp, 746 ctob(physmem - cnt.v_wire_count))); 747 case HW_DEVCONF: 748 return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 749 newp, newlen, p)); 750 default: 751 return (EOPNOTSUPP); 752 } 753 /* NOTREACHED */ 754} 755 756/* 757 * Validate parameters and get old / set new parameters 758 * for an integer-valued sysctl function. 759 */ 760int 761sysctl_int(oldp, oldlenp, newp, newlen, valp) 762 void *oldp; 763 size_t *oldlenp; 764 void *newp; 765 size_t newlen; 766 int *valp; 767{ 768 int error = 0; 769 770 if (oldp && *oldlenp < sizeof(int)) 771 return (ENOMEM); 772 if (newp && newlen != sizeof(int)) 773 return (EINVAL); 774 *oldlenp = sizeof(int); 775 if (oldp) 776 error = copyout(valp, oldp, sizeof(int)); 777 if (error == 0 && newp) 778 error = copyin(newp, valp, sizeof(int)); 779 return (error); 780} 781 782/* 783 * As above, but read-only. 784 */ 785int 786sysctl_rdint(oldp, oldlenp, newp, val) 787 void *oldp; 788 size_t *oldlenp; 789 void *newp; 790 int val; 791{ 792 int error = 0; 793 794 if (oldp && *oldlenp < sizeof(int)) 795 return (ENOMEM); 796 if (newp) 797 return (EPERM); 798 *oldlenp = sizeof(int); 799 if (oldp) 800 error = copyout((caddr_t)&val, oldp, sizeof(int)); 801 return (error); 802} 803 804/* 805 * Validate parameters and get old / set new parameters 806 * for a string-valued sysctl function. 807 */ 808int 809sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 810 void *oldp; 811 size_t *oldlenp; 812 void *newp; 813 size_t newlen; 814 char *str; 815 int maxlen; 816{ 817 int len, error = 0, rval = 0; 818 819 len = strlen(str) + 1; 820 if (oldp && *oldlenp < len) { 821 len = *oldlenp; 822 rval = ENOMEM; 823 } 824 if (newp && newlen >= maxlen) 825 return (EINVAL); 826 if (oldp) { 827 *oldlenp = len; 828 error = copyout(str, oldp, len); 829 if (error) 830 rval = error; 831 } 832 if ((error == 0 || error == ENOMEM) && newp) { 833 error = copyin(newp, str, newlen); 834 if (error) 835 rval = error; 836 str[newlen] = 0; 837 } 838 return (rval); 839} 840 841/* 842 * As above, but read-only. 843 */ 844int 845sysctl_rdstring(oldp, oldlenp, newp, str) 846 void *oldp; 847 size_t *oldlenp; 848 void *newp; 849 char *str; 850{ 851 int len, error = 0, rval = 0; 852 853 len = strlen(str) + 1; 854 if (oldp && *oldlenp < len) { 855 len = *oldlenp; 856 rval = ENOMEM; 857 } 858 if (newp) 859 return (EPERM); 860 *oldlenp = len; 861 if (oldp) 862 error = copyout(str, oldp, len); 863 if (error) 864 rval = error; 865 return (rval); 866} 867 868/* 869 * Validate parameters and get old / set new parameters 870 * for a structure oriented sysctl function. 871 */ 872int 873sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 874 void *oldp; 875 size_t *oldlenp; 876 void *newp; 877 size_t newlen; 878 void *sp; 879 int len; 880{ 881 int error = 0; 882 883 if (oldp && *oldlenp < len) 884 return (ENOMEM); 885 if (newp && newlen > len) 886 return (EINVAL); 887 if (oldp) { 888 *oldlenp = len; 889 error = copyout(sp, oldp, len); 890 } 891 if (error == 0 && newp) 892 error = copyin(newp, sp, len); 893 return (error); 894} 895 896/* 897 * Validate parameters and get old parameters 898 * for a structure oriented sysctl function. 899 */ 900int 901sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 902 void *oldp; 903 size_t *oldlenp; 904 void *newp, *sp; 905 int len; 906{ 907 int error = 0; 908 909 if (oldp && *oldlenp < len) 910 return (ENOMEM); 911 if (newp) 912 return (EPERM); 913 *oldlenp = len; 914 if (oldp) 915 error = copyout(sp, oldp, len); 916 return (error); 917} 918 919#ifdef COMPAT_43 920#include <sys/socket.h> 921#define KINFO_PROC (0<<8) 922#define KINFO_RT (1<<8) 923#define KINFO_VNODE (2<<8) 924#define KINFO_FILE (3<<8) 925#define KINFO_METER (4<<8) 926#define KINFO_LOADAVG (5<<8) 927#define KINFO_CLOCKRATE (6<<8) 928 929/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 930#define KINFO_BSDI_SYSINFO (101<<8) 931 932/* 933 * XXX this is bloat, but I hope it's better here than on the potentially 934 * limited kernel stack... -Peter 935 */ 936 937struct { 938 int bsdi_machine; /* "i386" on BSD/386 */ 939/* ^^^ this is an offset to the string, relative to the struct start */ 940 char *pad0; 941 long pad1; 942 long pad2; 943 long pad3; 944 u_long pad4; 945 u_long pad5; 946 u_long pad6; 947 948 int bsdi_ostype; /* "BSD/386" on BSD/386 */ 949 int bsdi_osrelease; /* "1.1" on BSD/386 */ 950 long pad7; 951 long pad8; 952 char *pad9; 953 954 long pad10; 955 long pad11; 956 int pad12; 957 long pad13; 958 quad_t pad14; 959 long pad15; 960 961 struct timeval pad16; 962 /* we dont set this, because BSDI's uname used gethostname() instead */ 963 int bsdi_hostname; /* hostname on BSD/386 */ 964 965 /* the actual string data is appended here */ 966 967} bsdi_si; 968/* 969 * this data is appended to the end of the bsdi_si structure during copyout. 970 * The "char *" offsets are relative to the base of the bsdi_si struct. 971 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 972 * should not exceed the length of the buffer here... (or else!! :-) 973 */ 974char bsdi_strings[80]; /* It had better be less than this! */ 975 976#ifndef _SYS_SYSPROTO_H_ 977struct getkerninfo_args { 978 int op; 979 char *where; 980 int *size; 981 int arg; 982}; 983#endif 984 985int 986ogetkerninfo(p, uap, retval) 987 struct proc *p; 988 register struct getkerninfo_args *uap; 989 int *retval; 990{ 991 int error, name[6]; 992 u_int size; 993 994 switch (uap->op & 0xff00) { 995 996 case KINFO_RT: 997 name[0] = CTL_NET; 998 name[1] = PF_ROUTE; 999 name[2] = 0; 1000 name[3] = (uap->op & 0xff0000) >> 16; 1001 name[4] = uap->op & 0xff; 1002 name[5] = uap->arg; 1003 error = userland_sysctl(p, name, 6, uap->where, uap->size, 1004 0, 0, 0, 0); 1005 break; 1006 1007 case KINFO_VNODE: 1008 name[0] = CTL_KERN; 1009 name[1] = KERN_VNODE; 1010 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1011 0, 0, 0, 0); 1012 break; 1013 1014 case KINFO_PROC: 1015 name[0] = CTL_KERN; 1016 name[1] = KERN_PROC; 1017 name[2] = uap->op & 0xff; 1018 name[3] = uap->arg; 1019 error = userland_sysctl(p, name, 4, uap->where, uap->size, 1020 0, 0, 0, 0); 1021 break; 1022 1023 case KINFO_FILE: 1024 name[0] = CTL_KERN; 1025 name[1] = KERN_FILE; 1026 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1027 0, 0, 0, 0); 1028 break; 1029 1030 case KINFO_METER: 1031 name[0] = CTL_VM; 1032 name[1] = VM_METER; 1033 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1034 0, 0, 0, 0); 1035 break; 1036 1037 case KINFO_LOADAVG: 1038 name[0] = CTL_VM; 1039 name[1] = VM_LOADAVG; 1040 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1041 0, 0, 0, 0); 1042 break; 1043 1044 case KINFO_CLOCKRATE: 1045 name[0] = CTL_KERN; 1046 name[1] = KERN_CLOCKRATE; 1047 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1048 0, 0, 0, 0); 1049 break; 1050 1051 case KINFO_BSDI_SYSINFO: { 1052 /* 1053 * this is pretty crude, but it's just enough for uname() 1054 * from BSDI's 1.x libc to work. 1055 * 1056 * In particular, it doesn't return the same results when 1057 * the supplied buffer is too small. BSDI's version apparently 1058 * will return the amount copied, and set the *size to how 1059 * much was needed. The emulation framework here isn't capable 1060 * of that, so we just set both to the amount copied. 1061 * BSDI's 2.x product apparently fails with ENOMEM in this 1062 * scenario. 1063 */ 1064 1065 u_int needed; 1066 u_int left; 1067 char *s; 1068 1069 bzero((char *)&bsdi_si, sizeof(bsdi_si)); 1070 bzero(bsdi_strings, sizeof(bsdi_strings)); 1071 1072 s = bsdi_strings; 1073 1074 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 1075 strcpy(s, ostype); 1076 s += strlen(s) + 1; 1077 1078 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 1079 strcpy(s, osrelease); 1080 s += strlen(s) + 1; 1081 1082 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 1083 strcpy(s, machine); 1084 s += strlen(s) + 1; 1085 1086 needed = sizeof(bsdi_si) + (s - bsdi_strings); 1087 1088 if (uap->where == NULL) { 1089 /* process is asking how much buffer to supply.. */ 1090 size = needed; 1091 error = 0; 1092 break; 1093 } 1094 1095 1096 /* if too much buffer supplied, trim it down */ 1097 if (size > needed) 1098 size = needed; 1099 1100 /* how much of the buffer is remaining */ 1101 left = size; 1102 1103 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 1104 break; 1105 1106 /* is there any point in continuing? */ 1107 if (left > sizeof(bsdi_si)) { 1108 left -= sizeof(bsdi_si); 1109 error = copyout(&bsdi_strings, 1110 uap->where + sizeof(bsdi_si), left); 1111 } 1112 break; 1113 } 1114 1115 default: 1116 return (EOPNOTSUPP); 1117 } 1118 if (error) 1119 return (error); 1120 *retval = size; 1121 if (uap->size) 1122 error = copyout((caddr_t)&size, (caddr_t)uap->size, 1123 sizeof(size)); 1124 return (error); 1125} 1126#endif /* COMPAT_43 */ 1127