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