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