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