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