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