1 /* $NetBSD: kern_sysctl.c,v 1.42 1998/10/19 22:19:26 tron Exp $ */ 2 3 /*- 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Mike Karels at Berkeley Software Design, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95 39 */ 40 41 /* 42 * sysctl system call. 43 */ 44 45 #include "opt_ddb.h" 46 #include "opt_insecure.h" 47 #include "opt_shortcorename.h" 48 #include "opt_uvm.h" 49 #include "opt_sysv.h" 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/kernel.h> 54 #include <sys/malloc.h> 55 #include <sys/proc.h> 56 #include <sys/file.h> 57 #include <sys/vnode.h> 58 #include <sys/unistd.h> 59 #include <sys/buf.h> 60 #include <sys/ioctl.h> 61 #include <sys/tty.h> 62 #include <sys/disklabel.h> 63 #include <sys/device.h> 64 #include <vm/vm.h> 65 #include <sys/sysctl.h> 66 #include <sys/msgbuf.h> 67 68 #if defined(UVM) 69 #include <uvm/uvm_extern.h> 70 #endif 71 72 #include <sys/mount.h> 73 #include <sys/syscallargs.h> 74 75 #if defined(UVM) 76 #include <uvm/uvm_extern.h> 77 #endif 78 79 #if defined(DDB) 80 #include <ddb/ddbvar.h> 81 #endif 82 83 /* 84 * Locking and stats 85 */ 86 static struct sysctl_lock { 87 int sl_lock; 88 int sl_want; 89 int sl_locked; 90 } memlock; 91 92 int 93 sys___sysctl(p, v, retval) 94 struct proc *p; 95 void *v; 96 register_t *retval; 97 { 98 register struct sys___sysctl_args /* { 99 syscallarg(int *) name; 100 syscallarg(u_int) namelen; 101 syscallarg(void *) old; 102 syscallarg(size_t *) oldlenp; 103 syscallarg(void *) new; 104 syscallarg(size_t) newlen; 105 } */ *uap = v; 106 int error, dolock = 1; 107 size_t savelen = 0, oldlen = 0; 108 sysctlfn *fn; 109 int name[CTL_MAXNAME]; 110 111 if (SCARG(uap, new) != NULL && 112 (error = suser(p->p_ucred, &p->p_acflag))) 113 return (error); 114 /* 115 * all top-level sysctl names are non-terminal 116 */ 117 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2) 118 return (EINVAL); 119 error = copyin(SCARG(uap, name), &name, 120 SCARG(uap, namelen) * sizeof(int)); 121 if (error) 122 return (error); 123 124 switch (name[0]) { 125 case CTL_KERN: 126 fn = kern_sysctl; 127 if (name[2] != KERN_VNODE) /* XXX */ 128 dolock = 0; 129 break; 130 case CTL_HW: 131 fn = hw_sysctl; 132 break; 133 case CTL_VM: 134 #if defined(UVM) 135 fn = uvm_sysctl; 136 #else 137 fn = vm_sysctl; 138 #endif 139 break; 140 case CTL_NET: 141 fn = net_sysctl; 142 break; 143 case CTL_VFS: 144 fn = vfs_sysctl; 145 break; 146 case CTL_MACHDEP: 147 fn = cpu_sysctl; 148 break; 149 #ifdef DEBUG 150 case CTL_DEBUG: 151 fn = debug_sysctl; 152 break; 153 #endif 154 #ifdef DDB 155 case CTL_DDB: 156 fn = ddb_sysctl; 157 break; 158 #endif 159 default: 160 return (EOPNOTSUPP); 161 } 162 163 if (SCARG(uap, oldlenp) && 164 (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen)))) 165 return (error); 166 if (SCARG(uap, old) != NULL) { 167 #if defined(UVM) 168 if (!uvm_useracc(SCARG(uap, old), oldlen, B_WRITE)) 169 #else 170 if (!useracc(SCARG(uap, old), oldlen, B_WRITE)) 171 #endif 172 return (EFAULT); 173 while (memlock.sl_lock) { 174 memlock.sl_want = 1; 175 sleep((caddr_t)&memlock, PRIBIO+1); 176 memlock.sl_locked++; 177 } 178 memlock.sl_lock = 1; 179 if (dolock) 180 #if defined(UVM) 181 uvm_vslock(p, SCARG(uap, old), oldlen); 182 #else 183 vslock(p, SCARG(uap, old), oldlen); 184 #endif 185 savelen = oldlen; 186 } 187 error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old), 188 &oldlen, SCARG(uap, new), SCARG(uap, newlen), p); 189 if (SCARG(uap, old) != NULL) { 190 if (dolock) 191 #if defined(UVM) 192 uvm_vsunlock(p, SCARG(uap, old), savelen); 193 #else 194 vsunlock(p, SCARG(uap, old), savelen); 195 #endif 196 memlock.sl_lock = 0; 197 if (memlock.sl_want) { 198 memlock.sl_want = 0; 199 wakeup((caddr_t)&memlock); 200 } 201 } 202 if (error) 203 return (error); 204 if (SCARG(uap, oldlenp)) 205 error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen)); 206 return (error); 207 } 208 209 /* 210 * Attributes stored in the kernel. 211 */ 212 char hostname[MAXHOSTNAMELEN]; 213 int hostnamelen; 214 char domainname[MAXHOSTNAMELEN]; 215 int domainnamelen; 216 long hostid; 217 #ifdef INSECURE 218 int securelevel = -1; 219 #else 220 int securelevel = 0; 221 #endif 222 #ifdef SHORTCORENAME 223 int shortcorename = 1; 224 #else 225 int shortcorename = 0; 226 #endif 227 228 /* 229 * kernel related system variables. 230 */ 231 int 232 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 233 int *name; 234 u_int namelen; 235 void *oldp; 236 size_t *oldlenp; 237 void *newp; 238 size_t newlen; 239 struct proc *p; 240 { 241 int error, level, inthostid; 242 int old_autonicetime; 243 int old_vnodes; 244 int old_shortcorename; 245 extern char ostype[], osrelease[], version[]; 246 247 /* all sysctl names at this level are terminal */ 248 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF)) 249 return (ENOTDIR); /* overloaded */ 250 251 switch (name[0]) { 252 case KERN_OSTYPE: 253 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 254 case KERN_OSRELEASE: 255 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 256 case KERN_OSREV: 257 return (sysctl_rdint(oldp, oldlenp, newp, NetBSD)); 258 case KERN_VERSION: 259 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 260 case KERN_MAXVNODES: 261 old_vnodes = desiredvnodes; 262 error = sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes); 263 if (old_vnodes > desiredvnodes) { 264 desiredvnodes = old_vnodes; 265 return (EINVAL); 266 } 267 return (error); 268 case KERN_MAXPROC: 269 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 270 case KERN_MAXFILES: 271 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 272 case KERN_ARGMAX: 273 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 274 case KERN_SECURELVL: 275 level = securelevel; 276 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 277 newp == NULL) 278 return (error); 279 if (level < securelevel && p->p_pid != 1) 280 return (EPERM); 281 securelevel = level; 282 return (0); 283 case KERN_HOSTNAME: 284 error = sysctl_string(oldp, oldlenp, newp, newlen, 285 hostname, sizeof(hostname)); 286 if (newp && !error) 287 hostnamelen = newlen; 288 return (error); 289 case KERN_DOMAINNAME: 290 error = sysctl_string(oldp, oldlenp, newp, newlen, 291 domainname, sizeof(domainname)); 292 if (newp && !error) 293 domainnamelen = newlen; 294 return (error); 295 case KERN_HOSTID: 296 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 297 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 298 hostid = inthostid; 299 return (error); 300 case KERN_CLOCKRATE: 301 return (sysctl_clockrate(oldp, oldlenp)); 302 case KERN_BOOTTIME: 303 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 304 sizeof(struct timeval))); 305 case KERN_VNODE: 306 return (sysctl_vnode(oldp, oldlenp, p)); 307 case KERN_PROC: 308 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 309 case KERN_FILE: 310 return (sysctl_file(oldp, oldlenp)); 311 #ifdef GPROF 312 case KERN_PROF: 313 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 314 newp, newlen)); 315 #endif 316 case KERN_POSIX1: 317 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 318 case KERN_NGROUPS: 319 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 320 case KERN_JOB_CONTROL: 321 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 322 case KERN_SAVED_IDS: 323 #ifdef _POSIX_SAVED_IDS 324 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 325 #else 326 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 327 #endif 328 case KERN_MAXPARTITIONS: 329 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 330 case KERN_RAWPARTITION: 331 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 332 #ifdef NTP 333 case KERN_NTPTIME: 334 return (sysctl_ntptime(oldp, oldlenp)); 335 #endif 336 case KERN_AUTONICETIME: 337 old_autonicetime = autonicetime; 338 error = sysctl_int(oldp, oldlenp, newp, newlen, &autonicetime); 339 if (autonicetime < 0) 340 autonicetime = old_autonicetime; 341 return (error); 342 case KERN_AUTONICEVAL: 343 error = sysctl_int(oldp, oldlenp, newp, newlen, &autoniceval); 344 if (autoniceval < PRIO_MIN) 345 autoniceval = PRIO_MIN; 346 if (autoniceval > PRIO_MAX) 347 autoniceval = PRIO_MAX; 348 return (error); 349 case KERN_RTC_OFFSET: 350 return (sysctl_rdint(oldp, oldlenp, newp, rtc_offset)); 351 case KERN_ROOT_DEVICE: 352 return (sysctl_rdstring(oldp, oldlenp, newp, 353 root_device->dv_xname)); 354 case KERN_MSGBUFSIZE: 355 /* 356 * deal with cases where the message buffer has 357 * become corrupted. 358 */ 359 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 360 msgbufenabled = 0; 361 return (ENXIO); 362 } 363 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 364 case KERN_FSYNC: 365 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 366 case KERN_SYSVMSG: 367 #ifdef SYSVMSG 368 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 369 #else 370 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 371 #endif 372 case KERN_SYSVSEM: 373 #ifdef SYSVSEM 374 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 375 #else 376 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 377 #endif 378 case KERN_SYSVSHM: 379 #ifdef SYSVSHM 380 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 381 #else 382 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 383 #endif 384 case KERN_SHORTCORENAME: 385 /* Only allow values of zero or one. */ 386 old_shortcorename = shortcorename; 387 error = sysctl_int(oldp, oldlenp, newp, newlen, 388 &shortcorename); 389 if (shortcorename != 0 && shortcorename != 1) { 390 shortcorename = old_shortcorename; 391 return (EINVAL); 392 } 393 return (error); 394 case KERN_SYNCHRONIZED_IO: 395 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 396 case KERN_IOV_MAX: 397 return (sysctl_rdint(oldp, oldlenp, newp, IOV_MAX)); 398 default: 399 return (EOPNOTSUPP); 400 } 401 /* NOTREACHED */ 402 } 403 404 /* 405 * hardware related system variables. 406 */ 407 int 408 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 409 int *name; 410 u_int namelen; 411 void *oldp; 412 size_t *oldlenp; 413 void *newp; 414 size_t newlen; 415 struct proc *p; 416 { 417 extern char machine[], machine_arch[], cpu_model[]; 418 419 /* all sysctl names at this level are terminal */ 420 if (namelen != 1) 421 return (ENOTDIR); /* overloaded */ 422 423 switch (name[0]) { 424 case HW_MACHINE: 425 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 426 case HW_MACHINE_ARCH: 427 return (sysctl_rdstring(oldp, oldlenp, newp, machine_arch)); 428 case HW_MODEL: 429 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 430 case HW_NCPU: 431 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 432 case HW_BYTEORDER: 433 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 434 case HW_PHYSMEM: 435 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 436 case HW_USERMEM: 437 #if defined(UVM) 438 return (sysctl_rdint(oldp, oldlenp, newp, 439 ctob(physmem - uvmexp.wired))); 440 #else 441 return (sysctl_rdint(oldp, oldlenp, newp, 442 ctob(physmem - cnt.v_wire_count))); 443 #endif 444 case HW_PAGESIZE: 445 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 446 default: 447 return (EOPNOTSUPP); 448 } 449 /* NOTREACHED */ 450 } 451 452 #ifdef DEBUG 453 /* 454 * Debugging related system variables. 455 */ 456 struct ctldebug debug0, debug1, debug2, debug3, debug4; 457 struct ctldebug debug5, debug6, debug7, debug8, debug9; 458 struct ctldebug debug10, debug11, debug12, debug13, debug14; 459 struct ctldebug debug15, debug16, debug17, debug18, debug19; 460 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 461 &debug0, &debug1, &debug2, &debug3, &debug4, 462 &debug5, &debug6, &debug7, &debug8, &debug9, 463 &debug10, &debug11, &debug12, &debug13, &debug14, 464 &debug15, &debug16, &debug17, &debug18, &debug19, 465 }; 466 int 467 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 468 int *name; 469 u_int namelen; 470 void *oldp; 471 size_t *oldlenp; 472 void *newp; 473 size_t newlen; 474 struct proc *p; 475 { 476 struct ctldebug *cdp; 477 478 /* all sysctl names at this level are name and field */ 479 if (namelen != 2) 480 return (ENOTDIR); /* overloaded */ 481 cdp = debugvars[name[0]]; 482 if (name[0] >= CTL_DEBUG_MAXID || cdp->debugname == 0) 483 return (EOPNOTSUPP); 484 switch (name[1]) { 485 case CTL_DEBUG_NAME: 486 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 487 case CTL_DEBUG_VALUE: 488 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 489 default: 490 return (EOPNOTSUPP); 491 } 492 /* NOTREACHED */ 493 } 494 #endif /* DEBUG */ 495 496 /* 497 * Validate parameters and get old / set new parameters 498 * for an integer-valued sysctl function. 499 */ 500 int 501 sysctl_int(oldp, oldlenp, newp, newlen, valp) 502 void *oldp; 503 size_t *oldlenp; 504 void *newp; 505 size_t newlen; 506 int *valp; 507 { 508 int error = 0; 509 510 if (oldp && *oldlenp < sizeof(int)) 511 return (ENOMEM); 512 if (newp && newlen != sizeof(int)) 513 return (EINVAL); 514 *oldlenp = sizeof(int); 515 if (oldp) 516 error = copyout(valp, oldp, sizeof(int)); 517 if (error == 0 && newp) 518 error = copyin(newp, valp, sizeof(int)); 519 return (error); 520 } 521 522 /* 523 * As above, but read-only. 524 */ 525 int 526 sysctl_rdint(oldp, oldlenp, newp, val) 527 void *oldp; 528 size_t *oldlenp; 529 void *newp; 530 int val; 531 { 532 int error = 0; 533 534 if (oldp && *oldlenp < sizeof(int)) 535 return (ENOMEM); 536 if (newp) 537 return (EPERM); 538 *oldlenp = sizeof(int); 539 if (oldp) 540 error = copyout((caddr_t)&val, oldp, sizeof(int)); 541 return (error); 542 } 543 544 /* 545 * Validate parameters and get old / set new parameters 546 * for a string-valued sysctl function. 547 */ 548 int 549 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 550 void *oldp; 551 size_t *oldlenp; 552 void *newp; 553 size_t newlen; 554 char *str; 555 int maxlen; 556 { 557 int len, error = 0; 558 559 len = strlen(str) + 1; 560 if (oldp && *oldlenp < len) 561 return (ENOMEM); 562 if (newp && newlen >= maxlen) 563 return (EINVAL); 564 if (oldp) { 565 *oldlenp = len; 566 error = copyout(str, oldp, len); 567 } 568 if (error == 0 && newp) { 569 error = copyin(newp, str, newlen); 570 str[newlen] = 0; 571 } 572 return (error); 573 } 574 575 /* 576 * As above, but read-only. 577 */ 578 int 579 sysctl_rdstring(oldp, oldlenp, newp, str) 580 void *oldp; 581 size_t *oldlenp; 582 void *newp; 583 char *str; 584 { 585 int len, error = 0; 586 587 len = strlen(str) + 1; 588 if (oldp && *oldlenp < len) 589 return (ENOMEM); 590 if (newp) 591 return (EPERM); 592 *oldlenp = len; 593 if (oldp) 594 error = copyout(str, oldp, len); 595 return (error); 596 } 597 598 /* 599 * Validate parameters and get old / set new parameters 600 * for a structure oriented sysctl function. 601 */ 602 int 603 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 604 void *oldp; 605 size_t *oldlenp; 606 void *newp; 607 size_t newlen; 608 void *sp; 609 int len; 610 { 611 int error = 0; 612 613 if (oldp && *oldlenp < len) 614 return (ENOMEM); 615 if (newp && newlen > len) 616 return (EINVAL); 617 if (oldp) { 618 *oldlenp = len; 619 error = copyout(sp, oldp, len); 620 } 621 if (error == 0 && newp) 622 error = copyin(newp, sp, len); 623 return (error); 624 } 625 626 /* 627 * Validate parameters and get old parameters 628 * for a structure oriented sysctl function. 629 */ 630 int 631 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 632 void *oldp; 633 size_t *oldlenp; 634 void *newp, *sp; 635 int len; 636 { 637 int error = 0; 638 639 if (oldp && *oldlenp < len) 640 return (ENOMEM); 641 if (newp) 642 return (EPERM); 643 *oldlenp = len; 644 if (oldp) 645 error = copyout(sp, oldp, len); 646 return (error); 647 } 648 649 /* 650 * Get file structures. 651 */ 652 int 653 sysctl_file(where, sizep) 654 char *where; 655 size_t *sizep; 656 { 657 int buflen, error; 658 struct file *fp; 659 char *start = where; 660 661 buflen = *sizep; 662 if (where == NULL) { 663 /* 664 * overestimate by 10 files 665 */ 666 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 667 return (0); 668 } 669 670 /* 671 * first copyout filehead 672 */ 673 if (buflen < sizeof(filehead)) { 674 *sizep = 0; 675 return (0); 676 } 677 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 678 if (error) 679 return (error); 680 buflen -= sizeof(filehead); 681 where += sizeof(filehead); 682 683 /* 684 * followed by an array of file structures 685 */ 686 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 687 if (buflen < sizeof(struct file)) { 688 *sizep = where - start; 689 return (ENOMEM); 690 } 691 error = copyout((caddr_t)fp, where, sizeof(struct file)); 692 if (error) 693 return (error); 694 buflen -= sizeof(struct file); 695 where += sizeof(struct file); 696 } 697 *sizep = where - start; 698 return (0); 699 } 700 701 /* 702 * try over estimating by 5 procs 703 */ 704 #define KERN_PROCSLOP (5 * sizeof(struct kinfo_proc)) 705 706 int 707 sysctl_doproc(name, namelen, where, sizep) 708 int *name; 709 u_int namelen; 710 char *where; 711 size_t *sizep; 712 { 713 register struct proc *p; 714 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 715 register int needed = 0; 716 int buflen = where != NULL ? *sizep : 0; 717 const struct proclist_desc *pd; 718 struct eproc eproc; 719 int error = 0; 720 721 if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 722 return (EINVAL); 723 724 pd = proclists; 725 again: 726 for (p = LIST_FIRST(pd->pd_list); p != NULL; 727 p = LIST_NEXT(p, p_list)) { 728 /* 729 * Skip embryonic processes. 730 */ 731 if (p->p_stat == SIDL) 732 continue; 733 /* 734 * TODO - make more efficient (see notes below). 735 * do by session. 736 */ 737 switch (name[0]) { 738 739 case KERN_PROC_PID: 740 /* could do this with just a lookup */ 741 if (p->p_pid != (pid_t)name[1]) 742 continue; 743 break; 744 745 case KERN_PROC_PGRP: 746 /* could do this by traversing pgrp */ 747 if (p->p_pgrp->pg_id != (pid_t)name[1]) 748 continue; 749 break; 750 751 case KERN_PROC_TTY: 752 if ((p->p_flag & P_CONTROLT) == 0 || 753 p->p_session->s_ttyp == NULL || 754 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 755 continue; 756 break; 757 758 case KERN_PROC_UID: 759 if (p->p_ucred->cr_uid != (uid_t)name[1]) 760 continue; 761 break; 762 763 case KERN_PROC_RUID: 764 if (p->p_cred->p_ruid != (uid_t)name[1]) 765 continue; 766 break; 767 } 768 if (buflen >= sizeof(struct kinfo_proc)) { 769 fill_eproc(p, &eproc); 770 error = copyout((caddr_t)p, &dp->kp_proc, 771 sizeof(struct proc)); 772 if (error) 773 return (error); 774 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 775 sizeof(eproc)); 776 if (error) 777 return (error); 778 dp++; 779 buflen -= sizeof(struct kinfo_proc); 780 } 781 needed += sizeof(struct kinfo_proc); 782 } 783 pd++; 784 if (pd->pd_list != NULL) 785 goto again; 786 787 if (where != NULL) { 788 *sizep = (caddr_t)dp - where; 789 if (needed > *sizep) 790 return (ENOMEM); 791 } else { 792 needed += KERN_PROCSLOP; 793 *sizep = needed; 794 } 795 return (0); 796 } 797 798 /* 799 * Fill in an eproc structure for the specified process. 800 */ 801 void 802 fill_eproc(p, ep) 803 register struct proc *p; 804 register struct eproc *ep; 805 { 806 register struct tty *tp; 807 808 ep->e_paddr = p; 809 ep->e_sess = p->p_pgrp->pg_session; 810 ep->e_pcred = *p->p_cred; 811 ep->e_ucred = *p->p_ucred; 812 if (p->p_stat == SIDL || p->p_stat == SZOMB) { 813 ep->e_vm.vm_rssize = 0; 814 ep->e_vm.vm_tsize = 0; 815 ep->e_vm.vm_dsize = 0; 816 ep->e_vm.vm_ssize = 0; 817 /* ep->e_vm.vm_pmap = XXX; */ 818 } else { 819 register struct vmspace *vm = p->p_vmspace; 820 821 ep->e_vm.vm_rssize = vm_resident_count(vm); 822 ep->e_vm.vm_tsize = vm->vm_tsize; 823 ep->e_vm.vm_dsize = vm->vm_dsize; 824 ep->e_vm.vm_ssize = vm->vm_ssize; 825 } 826 if (p->p_pptr) 827 ep->e_ppid = p->p_pptr->p_pid; 828 else 829 ep->e_ppid = 0; 830 ep->e_pgid = p->p_pgrp->pg_id; 831 ep->e_sid = ep->e_sess->s_sid; 832 ep->e_jobc = p->p_pgrp->pg_jobc; 833 if ((p->p_flag & P_CONTROLT) && 834 (tp = ep->e_sess->s_ttyp)) { 835 ep->e_tdev = tp->t_dev; 836 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 837 ep->e_tsess = tp->t_session; 838 } else 839 ep->e_tdev = NODEV; 840 if (p->p_wmesg) 841 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 842 ep->e_xsize = ep->e_xrssize = 0; 843 ep->e_xccount = ep->e_xswrss = 0; 844 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 845 if (SESS_LEADER(p)) 846 ep->e_flag |= EPROC_SLEADER; 847 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME); 848 } 849 850