kern_sysctl.c revision 12197
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.35 1995/11/10 16:22:41 phk Exp $ 38 */ 39 40/* 41 * sysctl system call. 42 */ 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/kernel.h> 47#include <sys/malloc.h> 48#include <sys/proc.h> 49#include <sys/file.h> 50#include <sys/vnode.h> 51#include <sys/unistd.h> 52#include <sys/buf.h> 53#include <sys/ioctl.h> 54#include <sys/tty.h> 55#include <sys/conf.h> 56#include <vm/vm.h> 57#include <sys/sysctl.h> 58#include <sys/user.h> 59 60extern struct linker_set sysctl_; 61 62/* BEGIN_MIB */ 63SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, 64 "Sysctl internal magic"); 65SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, 66 "High kernel, proc, limits &c"); 67SYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, 68 "Virtual memory"); 69SYSCTL_NODE(, CTL_FS, fs, CTLFLAG_RW, 0, 70 "File system"); 71SYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, 72 "Network, (see socket.h)"); 73SYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, 74 "Debugging"); 75SYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, 76 "hardware"); 77SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, 78 "machine dependent"); 79SYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, 80 "user-level"); 81 82SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, ""); 83 84SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, ""); 85 86SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, ""); 87 88SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, ""); 89 90extern int osreldate; 91SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, ""); 92 93SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 94 95SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, ""); 96 97SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, 98 CTLFLAG_RD, &maxprocperuid, 0, ""); 99 100SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, 101 CTLFLAG_RD, &maxfilesperproc, 0, ""); 102 103SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, ""); 104 105SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, ""); 106 107SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, ""); 108 109SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, ""); 110 111SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, ""); 112 113#ifdef _POSIX_SAVED_IDS 114SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, ""); 115#else 116SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, ""); 117#endif 118 119char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ 120 121SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, 122 CTLFLAG_RW, kernelname, sizeof kernelname, ""); 123 124SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, 125 CTLFLAG_RW, &boottime, timeval, ""); 126 127SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 128 129SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 130 131SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, ""); 132 133SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, ""); 134 135SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, ""); 136 137/* END_MIB */ 138 139extern int vfs_update_wakeup; 140extern int vfs_update_interval; 141static int 142sysctl_kern_updateinterval SYSCTL_HANDLER_ARGS 143{ 144 int error = sysctl_handle_int(oidp, 145 oidp->oid_arg1, oidp->oid_arg2, 146 oldp, oldlenp, newp, newlen); 147 if (!error) 148 wakeup(&vfs_update_wakeup); 149 return error; 150} 151 152SYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW, 153 &vfs_update_interval, 0, sysctl_kern_updateinterval, ""); 154 155 156char hostname[MAXHOSTNAMELEN]; 157int hostnamelen; 158static int 159sysctl_kern_hostname SYSCTL_HANDLER_ARGS 160{ 161 int error = sysctl_handle_string(oidp, 162 oidp->oid_arg1, oidp->oid_arg2, 163 oldp, oldlenp, newp, newlen); 164 if (newp && (error == 0 || error == ENOMEM)) 165 hostnamelen = newlen; 166 return error; 167} 168 169SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW, 170 &hostname, sizeof(hostname), sysctl_kern_hostname, ""); 171 172static int 173sysctl_order_cmp(const void *a, const void *b) 174{ 175 const struct sysctl_oid **pa, **pb; 176 177 pa = (const struct sysctl_oid **)a; 178 pb = (const struct sysctl_oid **)b; 179 if (*pa == NULL) 180 return (1); 181 if (*pb == NULL) 182 return (-1); 183 return ((*pa)->oid_number - (*pb)->oid_number); 184} 185 186static void 187sysctl_order(void *arg) 188{ 189 int j; 190 struct linker_set *l = (struct linker_set *) arg; 191 struct sysctl_oid **oidpp; 192 193 j = l->ls_length; 194 oidpp = (struct sysctl_oid **) l->ls_items; 195 for (; j--; oidpp++) { 196 if (!*oidpp) 197 continue; 198 if ((*oidpp)->oid_arg1 == arg) { 199 *oidpp = 0; 200 continue; 201 } 202 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 203 if (!(*oidpp)->oid_handler) 204 sysctl_order((*oidpp)->oid_arg1); 205 } 206 qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 207 sysctl_order_cmp); 208} 209 210SYSINIT(sysctl,SI_SUB_KMEM,SI_ORDER_ANY,sysctl_order,&sysctl_); 211 212static void 213sysctl_sysctl_debug_dump_node(struct linker_set *l,int i) 214{ 215 int j,k; 216 struct sysctl_oid **oidpp; 217 218 j = l->ls_length; 219 oidpp = (struct sysctl_oid **) l->ls_items; 220 for (; j--; oidpp++) { 221 222 if (!*oidpp) 223 continue; 224 225 for (k=0; k<i; k++) 226 printf(" "); 227 228 if ((*oidpp)->oid_number > 100) { 229 printf("Junk! %p # %d %s k %x a1 %p a2 %x h %p\n", 230 *oidpp, 231 (*oidpp)->oid_number, (*oidpp)->oid_name, 232 (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 233 (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 234 continue; 235 } 236 printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 237 238 printf("%c%c", 239 (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 240 (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 241 242 switch ((*oidpp)->oid_kind & CTLTYPE) { 243 case CTLTYPE_NODE: 244 if ((*oidpp)->oid_handler) { 245 printf(" Node(proc)\n"); 246 } else { 247 printf(" Node\n"); 248 sysctl_sysctl_debug_dump_node( 249 (*oidpp)->oid_arg1,i+2); 250 } 251 break; 252 case CTLTYPE_INT: printf(" Int\n"); break; 253 case CTLTYPE_STRING: printf(" String\n"); break; 254 case CTLTYPE_QUAD: printf(" Quad\n"); break; 255 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 256 default: printf("\n"); 257 } 258 259 } 260} 261 262 263static int 264sysctl_sysctl_debug SYSCTL_HANDLER_ARGS 265{ 266 sysctl_sysctl_debug_dump_node(&sysctl_,0); 267 return ENOENT; 268} 269 270SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 271 0, 0, sysctl_sysctl_debug, ""); 272 273char domainname[MAXHOSTNAMELEN]; 274int domainnamelen; 275static int 276sysctl_kern_domainname SYSCTL_HANDLER_ARGS 277{ 278 int error = sysctl_handle_string(oidp, 279 oidp->oid_arg1, oidp->oid_arg2, 280 oldp, oldlenp, newp, newlen); 281 if (newp && (error == 0 || error == ENOMEM)) 282 domainnamelen = newlen; 283 return error; 284} 285 286SYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW, 287 &domainname, sizeof(domainname), sysctl_kern_domainname, ""); 288 289long hostid; 290/* Some trouble here, if sizeof (int) != sizeof (long) */ 291SYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, ""); 292 293int 294sysctl_handle_int SYSCTL_HANDLER_ARGS 295{ 296 /* If there isn't sufficient space to return */ 297 if (oldp && *oldlenp < sizeof(int)) 298 return (ENOMEM); 299 300 /* If it is a constant, don't write */ 301 if (newp && !arg1) 302 return (EPERM); 303 304 /* If we get more than an int */ 305 if (newp && newlen != sizeof(int)) 306 return (EINVAL); 307 308 *oldlenp = sizeof(int); 309 if (oldp && arg1 ) 310 bcopy(arg1, oldp, sizeof(int)); 311 else if (oldp) 312 bcopy(&arg2, oldp, sizeof(int)); 313 if (newp) 314 bcopy(newp, arg1, sizeof(int)); 315 return (0); 316} 317 318int 319sysctl_handle_string SYSCTL_HANDLER_ARGS 320{ 321 int len, error=0; 322 char *str = (char *)arg1; 323 324 len = strlen(str) + 1; 325 326 if (oldp && *oldlenp < len) { 327 len = *oldlenp; 328 error=ENOMEM; 329 } 330 331 if (newp && newlen >= arg2) 332 return (EINVAL); 333 334 if (oldp) { 335 *oldlenp = len; 336 bcopy(str, oldp, len); 337 } 338 339 if (newp) { 340 bcopy(newp, str, newlen); 341 str[newlen] = 0; 342 } 343 return (error); 344} 345 346int 347sysctl_handle_opaque SYSCTL_HANDLER_ARGS 348{ 349 if (oldp && *oldlenp < arg2) 350 return (ENOMEM); 351 352 if (newp && newlen != arg2) 353 return (EINVAL); 354 355 if (oldp) { 356 *oldlenp = arg2; 357 bcopy(arg1, oldp, arg2); 358 } 359 if (newp) 360 bcopy(newp, arg1, arg2); 361 return (0); 362} 363 364#ifdef DEBUG 365static sysctlfn debug_sysctl; 366#endif 367 368/* 369 * Locking and stats 370 */ 371static struct sysctl_lock { 372 int sl_lock; 373 int sl_want; 374 int sl_locked; 375} memlock; 376 377 378 379/* 380 * Traverse our tree, and find the right node, execute whatever it points 381 * at, and return the resulting error code. 382 * We work entirely in kernel-space at this time. 383 */ 384 385 386int 387sysctl_root SYSCTL_HANDLER_ARGS 388{ 389 int *name = (int *) arg1; 390 int namelen = arg2; 391 int indx, i, j; 392 struct sysctl_oid **oidpp; 393 struct linker_set *lsp = &sysctl_; 394 395 j = lsp->ls_length; 396 oidpp = (struct sysctl_oid **) lsp->ls_items; 397 398 indx = 0; 399 while (j-- && indx < CTL_MAXNAME) { 400 if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 401 indx++; 402 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 403 if ((*oidpp)->oid_handler) 404 goto found; 405 if (indx == namelen) 406 return ENOENT; 407 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 408 j = lsp->ls_length; 409 oidpp = (struct sysctl_oid **)lsp->ls_items; 410 } else { 411 if (indx != namelen) 412 return EISDIR; 413 goto found; 414 } 415 } else { 416 oidpp++; 417 } 418 } 419 return EJUSTRETURN; 420found: 421 422 /* If writing isn't allowed */ 423 if (newp && !((*oidpp)->oid_kind & CTLFLAG_WR)) 424 return (EPERM); 425 426 if (!(*oidpp)->oid_handler) 427 return EINVAL; 428 429 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 430 i = ((*oidpp)->oid_handler) (*oidpp, 431 name + indx, namelen - indx, 432 oldp, oldlenp, newp, newlen); 433 } else { 434 i = ((*oidpp)->oid_handler) (*oidpp, 435 (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 436 oldp, oldlenp, newp, newlen); 437 } 438 return (i); 439} 440 441struct sysctl_args { 442 int *name; 443 u_int namelen; 444 void *old; 445 size_t *oldlenp; 446 void *new; 447 size_t newlen; 448}; 449 450int 451__sysctl(p, uap, retval) 452 struct proc *p; 453 register struct sysctl_args *uap; 454 int *retval; 455{ 456 int error, name[CTL_MAXNAME]; 457 458 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 459 return (EINVAL); 460 461 error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 462 if (error) 463 return (error); 464 465 return (userland_sysctl(p, name, uap->namelen, 466 uap->old, uap->oldlenp, 0, 467 uap->new, uap->newlen, retval)); 468} 469 470static sysctlfn kern_sysctl; 471 472/* 473 * This is used from various compatibility syscalls too. That's why name 474 * must be in kernel space. 475 */ 476int 477userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval) 478{ 479 int error = 0, dolock = 1, i; 480 u_int savelen = 0, oldlen = 0; 481 sysctlfn *fn; 482 void *oldp = 0; 483 void *newp = 0; 484 485 if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 486 return (error); 487 488 if (oldlenp) { 489 if (inkernel) { 490 oldlen = *oldlenp; 491 } else { 492 error = copyin(oldlenp, &oldlen, sizeof(oldlen)); 493 if (error) 494 return (error); 495 } 496 } 497 498 if (old) 499 oldp = malloc(oldlen, M_TEMP, M_WAITOK); 500 501 if (newlen) { 502 newp = malloc(newlen, M_TEMP, M_WAITOK); 503 error = copyin(new, newp, newlen); 504 } 505 if (error) { 506 if (oldp) 507 free(oldp, M_TEMP); 508 if (newp) 509 free(newp, M_TEMP); 510 return error; 511 } 512 513 error = sysctl_root(0, name, namelen, oldp, &oldlen, newp, newlen); 514 515 if (!error || error == ENOMEM) { 516 if (retval) 517 *retval = oldlen; 518 if (oldlenp) { 519 if (inkernel) { 520 *oldlenp = oldlen; 521 } else { 522 i = copyout(&oldlen, oldlenp, sizeof(oldlen)); 523 if (i) 524 error = i; 525 } 526 } 527 if ((error == ENOMEM || !error ) && oldp) { 528 i = copyout(oldp, old, oldlen); 529 if (i) 530 error = i; 531 free(oldp, M_TEMP); 532 } 533 if (newp) 534 free(newp, M_TEMP); 535 return (error); 536 } 537 538 if (oldp) 539 free(oldp, M_TEMP); 540 if (newp) 541 free(newp, M_TEMP); 542 543 switch (name[0]) { 544 case CTL_KERN: 545 fn = kern_sysctl; 546 if (name[1] != KERN_VNODE) /* XXX */ 547 dolock = 0; 548 break; 549 case CTL_HW: 550 fn = hw_sysctl; 551 break; 552 case CTL_VM: 553 fn = vm_sysctl; 554 break; 555 case CTL_NET: 556 fn = net_sysctl; 557 break; 558 case CTL_FS: 559 fn = fs_sysctl; 560 break; 561#ifdef DEBUG 562 case CTL_DEBUG: 563 fn = debug_sysctl; 564 break; 565#endif 566 default: 567 return (EOPNOTSUPP); 568 } 569 if (old != NULL) { 570 if (!useracc(old, oldlen, B_WRITE)) 571 return (EFAULT); 572 while (memlock.sl_lock) { 573 memlock.sl_want = 1; 574 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 575 memlock.sl_locked++; 576 } 577 memlock.sl_lock = 1; 578 if (dolock) 579 vslock(old, oldlen); 580 savelen = oldlen; 581 } 582 583 584 error = (*fn)(name + 1, namelen - 1, old, &oldlen, 585 new, newlen, p); 586 587 588 if (old != NULL) { 589 if (dolock) 590 vsunlock(old, savelen, B_WRITE); 591 memlock.sl_lock = 0; 592 if (memlock.sl_want) { 593 memlock.sl_want = 0; 594 wakeup((caddr_t)&memlock); 595 } 596 } 597#if 0 598 if (error) { 599 printf("SYSCTL_ERROR: "); 600 for(i=0;i<namelen;i++) 601 printf("%d ", name[i]); 602 printf("= %d\n", error); 603 } 604#endif 605 if (error) 606 return (error); 607 if (retval) 608 *retval = oldlen; 609 if (oldlenp) { 610 if (inkernel) { 611 *oldlenp = oldlen; 612 } else { 613 error = copyout(&oldlen, oldlenp, sizeof(oldlen)); 614 } 615 } 616 return (error); 617} 618 619/* 620 * Attributes stored in the kernel. 621 */ 622int securelevel = -1; 623 624/* 625 * kernel related system variables. 626 */ 627static int 628kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 629 int *name; 630 u_int namelen; 631 void *oldp; 632 size_t *oldlenp; 633 void *newp; 634 size_t newlen; 635 struct proc *p; 636{ 637 int error, level; 638 dev_t ndumpdev; 639 640 /* all sysctl names at this level are terminal */ 641 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 642 || name[0] == KERN_NTP_PLL)) 643 return (ENOTDIR); /* overloaded */ 644 645 switch (name[0]) { 646 647 case KERN_SECURELVL: 648 level = securelevel; 649 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 650 newp == NULL) 651 return (error); 652 if (level < securelevel && p->p_pid != 1) 653 return (EPERM); 654 securelevel = level; 655 return (0); 656 case KERN_VNODE: 657 return (sysctl_vnode(oldp, oldlenp)); 658 case KERN_PROC: 659 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 660 case KERN_FILE: 661 return (sysctl_file(oldp, oldlenp)); 662#ifdef GPROF 663 case KERN_PROF: 664 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 665 newp, newlen)); 666#endif 667 case KERN_NTP_PLL: 668 return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp, 669 newp, newlen, p)); 670 case KERN_DUMPDEV: 671 ndumpdev = dumpdev; 672 error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev, 673 sizeof ndumpdev); 674 if (!error && ndumpdev != dumpdev) { 675 error = setdumpdev(ndumpdev); 676 } 677 return error; 678 default: 679 return (EOPNOTSUPP); 680 } 681 /* NOTREACHED */ 682} 683 684/* 685 * hardware related system variables. 686 */ 687int 688hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 689 int *name; 690 u_int namelen; 691 void *oldp; 692 size_t *oldlenp; 693 void *newp; 694 size_t newlen; 695 struct proc *p; 696{ 697 /* almost all sysctl names at this level are terminal */ 698 if (namelen != 1 && name[0] != HW_DEVCONF) 699 return (ENOTDIR); /* overloaded */ 700 701 switch (name[0]) { 702 case HW_PHYSMEM: 703 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 704 case HW_USERMEM: 705 return (sysctl_rdint(oldp, oldlenp, newp, 706 ctob(physmem - cnt.v_wire_count))); 707 case HW_DEVCONF: 708 return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 709 newp, newlen, p)); 710 default: 711 return (EOPNOTSUPP); 712 } 713 /* NOTREACHED */ 714} 715 716#ifdef DEBUG 717/* 718 * Debugging related system variables. 719 */ 720struct ctldebug debug0, debug1, debug2, debug3, debug4; 721struct ctldebug debug5, debug6, debug7, debug8, debug9; 722struct ctldebug debug10, debug11, debug12, debug13, debug14; 723struct ctldebug debug15, debug16, debug17, debug18, debug19; 724static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 725 &debug0, &debug1, &debug2, &debug3, &debug4, 726 &debug5, &debug6, &debug7, &debug8, &debug9, 727 &debug10, &debug11, &debug12, &debug13, &debug14, 728 &debug15, &debug16, &debug17, &debug18, &debug19, 729}; 730static int 731debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 732 int *name; 733 u_int namelen; 734 void *oldp; 735 size_t *oldlenp; 736 void *newp; 737 size_t newlen; 738 struct proc *p; 739{ 740 struct ctldebug *cdp; 741 742 /* all sysctl names at this level are name and field */ 743 if (namelen != 2) 744 return (ENOTDIR); /* overloaded */ 745 cdp = debugvars[name[0]]; 746 if (cdp->debugname == 0) 747 return (EOPNOTSUPP); 748 switch (name[1]) { 749 case CTL_DEBUG_NAME: 750 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 751 case CTL_DEBUG_VALUE: 752 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 753 default: 754 return (EOPNOTSUPP); 755 } 756 /* NOTREACHED */ 757} 758#endif /* DEBUG */ 759 760/* 761 * Validate parameters and get old / set new parameters 762 * for an integer-valued sysctl function. 763 */ 764int 765sysctl_int(oldp, oldlenp, newp, newlen, valp) 766 void *oldp; 767 size_t *oldlenp; 768 void *newp; 769 size_t newlen; 770 int *valp; 771{ 772 int error = 0; 773 774 if (oldp && *oldlenp < sizeof(int)) 775 return (ENOMEM); 776 if (newp && newlen != sizeof(int)) 777 return (EINVAL); 778 *oldlenp = sizeof(int); 779 if (oldp) 780 error = copyout(valp, oldp, sizeof(int)); 781 if (error == 0 && newp) 782 error = copyin(newp, valp, sizeof(int)); 783 return (error); 784} 785 786/* 787 * As above, but read-only. 788 */ 789int 790sysctl_rdint(oldp, oldlenp, newp, val) 791 void *oldp; 792 size_t *oldlenp; 793 void *newp; 794 int val; 795{ 796 int error = 0; 797 798 if (oldp && *oldlenp < sizeof(int)) 799 return (ENOMEM); 800 if (newp) 801 return (EPERM); 802 *oldlenp = sizeof(int); 803 if (oldp) 804 error = copyout((caddr_t)&val, oldp, sizeof(int)); 805 return (error); 806} 807 808/* 809 * Validate parameters and get old / set new parameters 810 * for a string-valued sysctl function. 811 */ 812int 813sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 814 void *oldp; 815 size_t *oldlenp; 816 void *newp; 817 size_t newlen; 818 char *str; 819 int maxlen; 820{ 821 int len, error = 0, rval = 0; 822 823 len = strlen(str) + 1; 824 if (oldp && *oldlenp < len) { 825 len = *oldlenp; 826 rval = ENOMEM; 827 } 828 if (newp && newlen >= maxlen) 829 return (EINVAL); 830 if (oldp) { 831 *oldlenp = len; 832 error = copyout(str, oldp, len); 833 if (error) 834 rval = error; 835 } 836 if ((error == 0 || error == ENOMEM) && newp) { 837 error = copyin(newp, str, newlen); 838 if (error) 839 rval = error; 840 str[newlen] = 0; 841 } 842 return (rval); 843} 844 845/* 846 * As above, but read-only. 847 */ 848int 849sysctl_rdstring(oldp, oldlenp, newp, str) 850 void *oldp; 851 size_t *oldlenp; 852 void *newp; 853 char *str; 854{ 855 int len, error = 0, rval = 0; 856 857 len = strlen(str) + 1; 858 if (oldp && *oldlenp < len) { 859 len = *oldlenp; 860 rval = ENOMEM; 861 } 862 if (newp) 863 return (EPERM); 864 *oldlenp = len; 865 if (oldp) 866 error = copyout(str, oldp, len); 867 if (error) 868 rval = error; 869 return (rval); 870} 871 872/* 873 * Validate parameters and get old / set new parameters 874 * for a structure oriented sysctl function. 875 */ 876int 877sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 878 void *oldp; 879 size_t *oldlenp; 880 void *newp; 881 size_t newlen; 882 void *sp; 883 int len; 884{ 885 int error = 0; 886 887 if (oldp && *oldlenp < len) 888 return (ENOMEM); 889 if (newp && newlen > len) 890 return (EINVAL); 891 if (oldp) { 892 *oldlenp = len; 893 error = copyout(sp, oldp, len); 894 } 895 if (error == 0 && newp) 896 error = copyin(newp, sp, len); 897 return (error); 898} 899 900/* 901 * Validate parameters and get old parameters 902 * for a structure oriented sysctl function. 903 */ 904int 905sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 906 void *oldp; 907 size_t *oldlenp; 908 void *newp, *sp; 909 int len; 910{ 911 int error = 0; 912 913 if (oldp && *oldlenp < len) 914 return (ENOMEM); 915 if (newp) 916 return (EPERM); 917 *oldlenp = len; 918 if (oldp) 919 error = copyout(sp, oldp, len); 920 return (error); 921} 922 923/* 924 * Get file structures. 925 */ 926int 927sysctl_file(where, sizep) 928 char *where; 929 size_t *sizep; 930{ 931 int buflen, error; 932 struct file *fp; 933 char *start = where; 934 935 buflen = *sizep; 936 if (where == NULL) { 937 /* 938 * overestimate by 10 files 939 */ 940 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 941 return (0); 942 } 943 944 /* 945 * first copyout filehead 946 */ 947 if (buflen < sizeof(filehead)) { 948 *sizep = 0; 949 return (0); 950 } 951 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 952 if (error) 953 return (error); 954 buflen -= sizeof(filehead); 955 where += sizeof(filehead); 956 957 /* 958 * followed by an array of file structures 959 */ 960 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 961 if (buflen < sizeof(struct file)) { 962 *sizep = where - start; 963 return (ENOMEM); 964 } 965 error = copyout((caddr_t)fp, where, sizeof (struct file)); 966 if (error) 967 return (error); 968 buflen -= sizeof(struct file); 969 where += sizeof(struct file); 970 } 971 *sizep = where - start; 972 return (0); 973} 974 975/* 976 * try over estimating by 5 procs 977 */ 978#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 979 980int 981sysctl_doproc(name, namelen, where, sizep) 982 int *name; 983 u_int namelen; 984 char *where; 985 size_t *sizep; 986{ 987 register struct proc *p; 988 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 989 register int needed = 0; 990 int buflen = where != NULL ? *sizep : 0; 991 int doingzomb; 992 struct eproc eproc; 993 int error = 0; 994 995 if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 996 return (EINVAL); 997 p = (struct proc *)allproc; 998 doingzomb = 0; 999again: 1000 for (; p != NULL; p = p->p_next) { 1001 /* 1002 * Skip embryonic processes. 1003 */ 1004 if (p->p_stat == SIDL) 1005 continue; 1006 /* 1007 * TODO - make more efficient (see notes below). 1008 * do by session. 1009 */ 1010 switch (name[0]) { 1011 1012 case KERN_PROC_PID: 1013 /* could do this with just a lookup */ 1014 if (p->p_pid != (pid_t)name[1]) 1015 continue; 1016 break; 1017 1018 case KERN_PROC_PGRP: 1019 /* could do this by traversing pgrp */ 1020 if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1]) 1021 continue; 1022 break; 1023 1024 case KERN_PROC_TTY: 1025 if ((p->p_flag & P_CONTROLT) == 0 || 1026 p->p_session == NULL || 1027 p->p_session->s_ttyp == NULL || 1028 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 1029 continue; 1030 break; 1031 1032 case KERN_PROC_UID: 1033 if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1]) 1034 continue; 1035 break; 1036 1037 case KERN_PROC_RUID: 1038 if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1]) 1039 continue; 1040 break; 1041 } 1042 if (buflen >= sizeof(struct kinfo_proc)) { 1043 fill_eproc(p, &eproc); 1044 error = copyout((caddr_t)p, &dp->kp_proc, 1045 sizeof(struct proc)); 1046 if (error) 1047 return (error); 1048 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 1049 sizeof(eproc)); 1050 if (error) 1051 return (error); 1052 dp++; 1053 buflen -= sizeof(struct kinfo_proc); 1054 } 1055 needed += sizeof(struct kinfo_proc); 1056 } 1057 if (doingzomb == 0) { 1058 p = zombproc; 1059 doingzomb++; 1060 goto again; 1061 } 1062 if (where != NULL) { 1063 *sizep = (caddr_t)dp - where; 1064 if (needed > *sizep) 1065 return (ENOMEM); 1066 } else { 1067 needed += KERN_PROCSLOP; 1068 *sizep = needed; 1069 } 1070 return (0); 1071} 1072 1073/* 1074 * Fill in an eproc structure for the specified process. 1075 */ 1076void 1077fill_eproc(p, ep) 1078 register struct proc *p; 1079 register struct eproc *ep; 1080{ 1081 register struct tty *tp; 1082 1083 bzero(ep, sizeof(*ep)); 1084 1085 ep->e_paddr = p; 1086 if (p->p_cred) { 1087 ep->e_pcred = *p->p_cred; 1088 if (p->p_ucred) 1089 ep->e_ucred = *p->p_ucred; 1090 } 1091 if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) { 1092 register struct vmspace *vm = p->p_vmspace; 1093 1094#ifdef pmap_resident_count 1095 ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 1096#else 1097 ep->e_vm.vm_rssize = vm->vm_rssize; 1098#endif 1099 ep->e_vm.vm_tsize = vm->vm_tsize; 1100 ep->e_vm.vm_dsize = vm->vm_dsize; 1101 ep->e_vm.vm_ssize = vm->vm_ssize; 1102#ifndef sparc 1103 ep->e_vm.vm_pmap = vm->vm_pmap; 1104#endif 1105 } 1106 if (p->p_pptr) 1107 ep->e_ppid = p->p_pptr->p_pid; 1108 if (p->p_pgrp) { 1109 ep->e_sess = p->p_pgrp->pg_session; 1110 ep->e_pgid = p->p_pgrp->pg_id; 1111 ep->e_jobc = p->p_pgrp->pg_jobc; 1112 } 1113 if ((p->p_flag & P_CONTROLT) && 1114 (ep->e_sess != NULL) && 1115 ((tp = ep->e_sess->s_ttyp) != NULL)) { 1116 ep->e_tdev = tp->t_dev; 1117 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1118 ep->e_tsess = tp->t_session; 1119 } else 1120 ep->e_tdev = NODEV; 1121 if (ep->e_sess && ep->e_sess->s_ttyvp) 1122 ep->e_flag = EPROC_CTTY; 1123 if (SESS_LEADER(p)) 1124 ep->e_flag |= EPROC_SLEADER; 1125 if (p->p_wmesg) { 1126 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 1127 ep->e_wmesg[WMESGLEN] = 0; 1128 } 1129} 1130 1131#ifdef COMPAT_43 1132#include <sys/socket.h> 1133#define KINFO_PROC (0<<8) 1134#define KINFO_RT (1<<8) 1135#define KINFO_VNODE (2<<8) 1136#define KINFO_FILE (3<<8) 1137#define KINFO_METER (4<<8) 1138#define KINFO_LOADAVG (5<<8) 1139#define KINFO_CLOCKRATE (6<<8) 1140 1141/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 1142#define KINFO_BSDI_SYSINFO (101<<8) 1143 1144/* 1145 * XXX this is bloat, but I hope it's better here than on the potentially 1146 * limited kernel stack... -Peter 1147 */ 1148 1149struct { 1150 int bsdi_machine; /* "i386" on BSD/386 */ 1151/* ^^^ this is an offset to the string, relative to the struct start */ 1152 char *pad0; 1153 long pad1; 1154 long pad2; 1155 long pad3; 1156 u_long pad4; 1157 u_long pad5; 1158 u_long pad6; 1159 1160 int bsdi_ostype; /* "BSD/386" on BSD/386 */ 1161 int bsdi_osrelease; /* "1.1" on BSD/386 */ 1162 long pad7; 1163 long pad8; 1164 char *pad9; 1165 1166 long pad10; 1167 long pad11; 1168 int pad12; 1169 long pad13; 1170 quad_t pad14; 1171 long pad15; 1172 1173 struct timeval pad16; 1174 /* we dont set this, because BSDI's uname used gethostname() instead */ 1175 int bsdi_hostname; /* hostname on BSD/386 */ 1176 1177 /* the actual string data is appended here */ 1178 1179} bsdi_si; 1180/* 1181 * this data is appended to the end of the bsdi_si structure during copyout. 1182 * The "char *" offsets are relative to the base of the bsdi_si struct. 1183 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 1184 * should not exceed the length of the buffer here... (or else!! :-) 1185 */ 1186char bsdi_strings[80]; /* It had better be less than this! */ 1187 1188struct getkerninfo_args { 1189 int op; 1190 char *where; 1191 int *size; 1192 int arg; 1193}; 1194 1195int 1196ogetkerninfo(p, uap, retval) 1197 struct proc *p; 1198 register struct getkerninfo_args *uap; 1199 int *retval; 1200{ 1201 int error, name[6]; 1202 u_int size; 1203 1204 switch (uap->op & 0xff00) { 1205 1206 case KINFO_RT: 1207 name[0] = CTL_NET; 1208 name[1] = PF_ROUTE; 1209 name[2] = 0; 1210 name[3] = (uap->op & 0xff0000) >> 16; 1211 name[4] = uap->op & 0xff; 1212 name[5] = uap->arg; 1213 error = userland_sysctl(p, name, 6, uap->where, uap->size, 1214 0, 0, 0, 0); 1215 break; 1216 1217 case KINFO_VNODE: 1218 name[0] = CTL_KERN; 1219 name[1] = KERN_VNODE; 1220 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1221 0, 0, 0, 0); 1222 break; 1223 1224 case KINFO_PROC: 1225 name[0] = CTL_KERN; 1226 name[1] = KERN_PROC; 1227 name[2] = uap->op & 0xff; 1228 name[3] = uap->arg; 1229 error = userland_sysctl(p, name, 4, uap->where, uap->size, 1230 0, 0, 0, 0); 1231 break; 1232 1233 case KINFO_FILE: 1234 name[0] = CTL_KERN; 1235 name[1] = KERN_FILE; 1236 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1237 0, 0, 0, 0); 1238 break; 1239 1240 case KINFO_METER: 1241 name[0] = CTL_VM; 1242 name[1] = VM_METER; 1243 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1244 0, 0, 0, 0); 1245 break; 1246 1247 case KINFO_LOADAVG: 1248 name[0] = CTL_VM; 1249 name[1] = VM_LOADAVG; 1250 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1251 0, 0, 0, 0); 1252 break; 1253 1254 case KINFO_CLOCKRATE: 1255 name[0] = CTL_KERN; 1256 name[1] = KERN_CLOCKRATE; 1257 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1258 0, 0, 0, 0); 1259 break; 1260 1261 case KINFO_BSDI_SYSINFO: { 1262 /* 1263 * this is pretty crude, but it's just enough for uname() 1264 * from BSDI's 1.x libc to work. 1265 * 1266 * In particular, it doesn't return the same results when 1267 * the supplied buffer is too small. BSDI's version apparently 1268 * will return the amount copied, and set the *size to how 1269 * much was needed. The emulation framework here isn't capable 1270 * of that, so we just set both to the amount copied. 1271 * BSDI's 2.x product apparently fails with ENOMEM in this 1272 * scenario. 1273 */ 1274 1275 u_int needed; 1276 u_int left; 1277 char *s; 1278 1279 bzero((char *)&bsdi_si, sizeof(bsdi_si)); 1280 bzero(bsdi_strings, sizeof(bsdi_strings)); 1281 1282 s = bsdi_strings; 1283 1284 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 1285 strcpy(s, ostype); 1286 s += strlen(s) + 1; 1287 1288 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 1289 strcpy(s, osrelease); 1290 s += strlen(s) + 1; 1291 1292 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 1293 strcpy(s, machine); 1294 s += strlen(s) + 1; 1295 1296 needed = sizeof(bsdi_si) + (s - bsdi_strings); 1297 1298 if (uap->where == NULL) { 1299 /* process is asking how much buffer to supply.. */ 1300 size = needed; 1301 error = 0; 1302 break; 1303 } 1304 1305 1306 /* if too much buffer supplied, trim it down */ 1307 if (size > needed) 1308 size = needed; 1309 1310 /* how much of the buffer is remaining */ 1311 left = size; 1312 1313 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 1314 break; 1315 1316 /* is there any point in continuing? */ 1317 if (left > sizeof(bsdi_si)) { 1318 left -= sizeof(bsdi_si); 1319 error = copyout(&bsdi_strings, 1320 uap->where + sizeof(bsdi_si), left); 1321 } 1322 break; 1323 } 1324 1325 default: 1326 return (EOPNOTSUPP); 1327 } 1328 if (error) 1329 return (error); 1330 *retval = size; 1331 if (uap->size) 1332 error = copyout((caddr_t)&size, (caddr_t)uap->size, 1333 sizeof(size)); 1334 return (error); 1335} 1336#endif /* COMPAT_43 */ 1337