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