1 /*- 2 * Copyright (c) 1982, 1986, 1989, 1993 Regents of the University of California. 3 * 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 * %sccs.include.redist.c% 9 * 10 * @(#)kern_sysctl.c 7.35 (Berkeley) 04/27/93 11 */ 12 13 /* 14 * sysctl system call. 15 */ 16 17 #include <sys/param.h> 18 #include <sys/systm.h> 19 #include <sys/malloc.h> 20 #include <sys/proc.h> 21 #include <sys/file.h> 22 #include <sys/vnode.h> 23 #include <sys/sysctl.h> 24 #include <sys/unistd.h> 25 #include <sys/buf.h> 26 #include <sys/ioctl.h> 27 #include <sys/tty.h> 28 29 #include <vm/vm.h> 30 31 #include <sys/kinfo_proc.h> 32 33 sysctlfn kern_sysctl; 34 sysctlfn hw_sysctl; 35 #ifdef DEBUG 36 sysctlfn debug_sysctl; 37 #endif 38 extern sysctlfn vm_sysctl; 39 extern sysctlfn fs_sysctl; 40 extern sysctlfn net_sysctl; 41 extern sysctlfn cpu_sysctl; 42 43 /* 44 * Locking and stats 45 */ 46 static struct sysctl_lock { 47 int sl_lock; 48 int sl_want; 49 int sl_locked; 50 } memlock; 51 52 struct sysctl_args { 53 int *name; 54 u_int namelen; 55 void *old; 56 size_t *oldlenp; 57 void *new; 58 size_t newlen; 59 }; 60 61 sysctl(p, uap, retval) 62 struct proc *p; 63 register struct sysctl_args *uap; 64 int *retval; 65 { 66 int error, dolock = 1; 67 u_int savelen, oldlen = 0; 68 sysctlfn *fn; 69 int name[CTL_MAXNAME]; 70 71 if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 72 return (error); 73 /* 74 * all top-level sysctl names are non-terminal 75 */ 76 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 77 return (EINVAL); 78 if (error = copyin(uap->name, &name, uap->namelen * sizeof(int))) 79 return (error); 80 81 switch (name[0]) { 82 case CTL_KERN: 83 fn = kern_sysctl; 84 if (name[2] != KERN_VNODE) /* XXX */ 85 dolock = 0; 86 break; 87 case CTL_HW: 88 fn = hw_sysctl; 89 break; 90 case CTL_VM: 91 fn = vm_sysctl; 92 break; 93 case CTL_NET: 94 fn = net_sysctl; 95 break; 96 #ifdef notyet 97 case CTL_FS: 98 fn = fs_sysctl; 99 break; 100 case CTL_MACHDEP: 101 fn = cpu_sysctl; 102 break; 103 #endif 104 #ifdef DEBUG 105 case CTL_DEBUG: 106 fn = debug_sysctl; 107 break; 108 #endif 109 default: 110 return (EOPNOTSUPP); 111 } 112 113 if (uap->oldlenp && 114 (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) 115 return (error); 116 if (uap->old != NULL) { 117 if (!useracc(uap->old, oldlen, B_WRITE)) 118 return (EFAULT); 119 while (memlock.sl_lock) { 120 memlock.sl_want = 1; 121 sleep((caddr_t)&memlock, PRIBIO+1); 122 memlock.sl_locked++; 123 } 124 memlock.sl_lock = 1; 125 if (dolock) 126 vslock(uap->old, oldlen); 127 savelen = oldlen; 128 } 129 error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen, 130 uap->new, uap->newlen, p); 131 if (uap->old != NULL) { 132 if (dolock) 133 vsunlock(uap->old, savelen, B_WRITE); 134 memlock.sl_lock = 0; 135 if (memlock.sl_want) { 136 memlock.sl_want = 0; 137 wakeup((caddr_t)&memlock); 138 } 139 } 140 if (error) 141 return (error); 142 if (uap->oldlenp) 143 error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 144 *retval = oldlen; 145 return (0); 146 } 147 148 /* 149 * Attributes stored in the kernel. 150 */ 151 char hostname[MAXHOSTNAMELEN]; 152 int hostnamelen; 153 long hostid; 154 int securelevel; 155 156 /* 157 * kernel related system variables. 158 */ 159 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 160 int *name; 161 u_int namelen; 162 void *oldp; 163 size_t *oldlenp; 164 void *newp; 165 size_t newlen; 166 struct proc *p; 167 { 168 int error, level; 169 extern char ostype[], osrelease[], version[]; 170 171 /* all sysctl names at this level are terminal */ 172 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF)) 173 return (ENOTDIR); /* overloaded */ 174 175 switch (name[0]) { 176 case KERN_OSTYPE: 177 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 178 case KERN_OSRELEASE: 179 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 180 case KERN_OSREV: 181 return (sysctl_rdint(oldp, oldlenp, newp, BSD)); 182 case KERN_VERSION: 183 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 184 case KERN_POSIX1: 185 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 186 case KERN_MAXPROC: 187 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 188 case KERN_MAXFILES: 189 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 190 case KERN_MAXVNODES: 191 return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 192 case KERN_ARGMAX: 193 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 194 case KERN_HOSTNAME: 195 error = sysctl_string(oldp, oldlenp, newp, newlen, 196 hostname, sizeof(hostname)); 197 if (!error) 198 hostnamelen = newlen; 199 return (error); 200 case KERN_HOSTID: 201 return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid)); 202 case KERN_SECURELVL: 203 level = securelevel; 204 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 205 newp == NULL) 206 return (error); 207 if (level < securelevel && p->p_pid != 1) 208 return (EPERM); 209 securelevel = level; 210 return (0); 211 case KERN_CLOCKRATE: 212 return (sysctl_clockrate(oldp, oldlenp)); 213 case KERN_FILE: 214 return (sysctl_file(oldp, oldlenp)); 215 case KERN_VNODE: 216 return (sysctl_vnode(oldp, oldlenp)); 217 case KERN_PROC: 218 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 219 #ifdef GPROF 220 case KERN_PROF: 221 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 222 newp, newlen)); 223 #endif 224 default: 225 return (EOPNOTSUPP); 226 } 227 /* NOTREACHED */ 228 } 229 230 /* 231 * hardware related system variables. 232 */ 233 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 234 int *name; 235 u_int namelen; 236 void *oldp; 237 size_t *oldlenp; 238 void *newp; 239 size_t newlen; 240 struct proc *p; 241 { 242 extern char machine[], cpu_model[]; 243 244 /* all sysctl names at this level are terminal */ 245 if (namelen != 1) 246 return (ENOTDIR); /* overloaded */ 247 248 switch (name[0]) { 249 case HW_MACHINE: 250 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 251 case HW_MODEL: 252 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 253 case HW_NCPU: 254 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 255 case HW_CPUSPEED: 256 return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed)); 257 case HW_PHYSMEM: 258 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 259 case HW_USERMEM: 260 return (sysctl_rdint(oldp, oldlenp, newp, 261 ctob(physmem - cnt.v_wire_count))); 262 case HW_PAGESIZE: 263 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 264 default: 265 return (EOPNOTSUPP); 266 } 267 /* NOTREACHED */ 268 } 269 270 #ifdef DEBUG 271 /* 272 * Debugging related system variables. 273 */ 274 struct ctldebug debug0, debug1, debug2, debug3, debug4; 275 struct ctldebug debug5, debug6, debug7, debug8, debug9; 276 struct ctldebug debug10, debug11, debug12, debug13, debug14; 277 struct ctldebug debug15, debug16, debug17, debug18, debug19; 278 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 279 &debug0, &debug1, &debug2, &debug3, &debug4, 280 &debug5, &debug6, &debug7, &debug8, &debug9, 281 &debug10, &debug11, &debug12, &debug13, &debug14, 282 &debug15, &debug16, &debug17, &debug18, &debug19, 283 }; 284 int 285 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 286 int *name; 287 u_int namelen; 288 void *oldp; 289 size_t *oldlenp; 290 void *newp; 291 size_t newlen; 292 struct proc *p; 293 { 294 struct ctldebug *cdp; 295 296 /* all sysctl names at this level are name and field */ 297 if (namelen != 2) 298 return (ENOTDIR); /* overloaded */ 299 cdp = debugvars[name[0]]; 300 if (cdp->debugname == 0) 301 return (EOPNOTSUPP); 302 switch (name[1]) { 303 case CTL_DEBUG_NAME: 304 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 305 case CTL_DEBUG_VALUE: 306 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 307 default: 308 return (EOPNOTSUPP); 309 } 310 /* NOTREACHED */ 311 } 312 #endif /* DEBUG */ 313 314 /* 315 * Validate parameters and get old / set new parameters 316 * for an integer-valued sysctl function. 317 */ 318 sysctl_int(oldp, oldlenp, newp, newlen, valp) 319 void *oldp; 320 size_t *oldlenp; 321 void *newp; 322 size_t newlen; 323 int *valp; 324 { 325 int error = 0; 326 327 if (oldp && *oldlenp < sizeof(int)) 328 return (ENOMEM); 329 if (newp && newlen != sizeof(int)) 330 return (EINVAL); 331 *oldlenp = sizeof(int); 332 if (oldp) 333 error = copyout(valp, oldp, sizeof(int)); 334 if (error == 0 && newp) 335 error = copyin(newp, valp, sizeof(int)); 336 return (error); 337 } 338 339 /* 340 * As above, but read-only. 341 */ 342 sysctl_rdint(oldp, oldlenp, newp, val) 343 void *oldp; 344 size_t *oldlenp; 345 void *newp; 346 int val; 347 { 348 int error = 0; 349 350 if (oldp && *oldlenp < sizeof(int)) 351 return (ENOMEM); 352 if (newp) 353 return (EPERM); 354 *oldlenp = sizeof(int); 355 if (oldp) 356 error = copyout((caddr_t)&val, oldp, sizeof(int)); 357 return (error); 358 } 359 360 /* 361 * Validate parameters and get old / set new parameters 362 * for a string-valued sysctl function. 363 */ 364 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 365 void *oldp; 366 size_t *oldlenp; 367 void *newp; 368 size_t newlen; 369 char *str; 370 int maxlen; 371 { 372 int len, error = 0; 373 374 len = strlen(str) + 1; 375 if (oldp && *oldlenp < len) 376 return (ENOMEM); 377 if (newp && newlen >= maxlen) 378 return (EINVAL); 379 if (oldp) { 380 *oldlenp = len; 381 error = copyout(str, oldp, len); 382 } 383 if (error == 0 && newp) { 384 error = copyin(newp, str, newlen); 385 str[newlen] = 0; 386 } 387 return (error); 388 } 389 390 /* 391 * As above, but read-only. 392 */ 393 sysctl_rdstring(oldp, oldlenp, newp, str) 394 void *oldp; 395 size_t *oldlenp; 396 void *newp; 397 char *str; 398 { 399 int len, error = 0; 400 401 len = strlen(str) + 1; 402 if (oldp && *oldlenp < len) 403 return (ENOMEM); 404 if (newp) 405 return (EPERM); 406 *oldlenp = len; 407 if (oldp) 408 error = copyout(str, oldp, len); 409 return (error); 410 } 411 412 /* 413 * Validate parameters and get old / set new parameters 414 * for a structure oriented sysctl function. 415 */ 416 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 417 void *oldp; 418 size_t *oldlenp; 419 void *newp; 420 size_t newlen; 421 void *sp; 422 int len; 423 { 424 int error = 0; 425 426 if (oldp && *oldlenp < len) 427 return (ENOMEM); 428 if (newp && newlen > len) 429 return (EINVAL); 430 if (oldp) { 431 *oldlenp = len; 432 error = copyout(sp, oldp, len); 433 } 434 if (error == 0 && newp) 435 error = copyin(newp, sp, len); 436 return (error); 437 } 438 439 /* 440 * Validate parameters and get old parameters 441 * for a structure oriented sysctl function. 442 */ 443 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 444 void *oldp; 445 size_t *oldlenp; 446 void *newp, *sp; 447 int len; 448 { 449 int error = 0; 450 451 if (oldp && *oldlenp < len) 452 return (ENOMEM); 453 if (newp) 454 return (EPERM); 455 *oldlenp = len; 456 if (oldp) 457 error = copyout(sp, oldp, len); 458 return (error); 459 } 460 461 /* 462 * Get file structures. 463 */ 464 sysctl_file(where, sizep) 465 char *where; 466 size_t *sizep; 467 { 468 int buflen, error; 469 struct file *fp; 470 char *start = where; 471 472 buflen = *sizep; 473 if (where == NULL) { 474 /* 475 * overestimate by 10 files 476 */ 477 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 478 return (0); 479 } 480 481 /* 482 * first copyout filehead 483 */ 484 if (buflen < sizeof(filehead)) { 485 *sizep = 0; 486 return (0); 487 } 488 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead))) 489 return (error); 490 buflen += sizeof(filehead); 491 where += sizeof(filehead); 492 493 /* 494 * followed by an array of file structures 495 */ 496 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 497 if (buflen < sizeof(struct file)) { 498 *sizep = where - start; 499 return (ENOMEM); 500 } 501 if (error = copyout((caddr_t)fp, where, sizeof (struct file))) 502 return (error); 503 buflen -= sizeof(struct file); 504 where += sizeof(struct file); 505 } 506 *sizep = where - start; 507 return (0); 508 } 509 510 /* 511 * try over estimating by 5 procs 512 */ 513 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 514 515 sysctl_doproc(name, namelen, where, sizep) 516 int *name; 517 u_int namelen; 518 char *where; 519 size_t *sizep; 520 { 521 register struct proc *p; 522 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 523 register int needed = 0; 524 int buflen = where != NULL ? *sizep : 0; 525 int doingzomb; 526 struct eproc eproc; 527 int error = 0; 528 529 if (namelen != 2) 530 return (EINVAL); 531 p = (struct proc *)allproc; 532 doingzomb = 0; 533 again: 534 for (; p != NULL; p = p->p_nxt) { 535 /* 536 * Skip embryonic processes. 537 */ 538 if (p->p_stat == SIDL) 539 continue; 540 /* 541 * TODO - make more efficient (see notes below). 542 * do by session. 543 */ 544 switch (name[0]) { 545 546 case KERN_PROC_PID: 547 /* could do this with just a lookup */ 548 if (p->p_pid != (pid_t)name[1]) 549 continue; 550 break; 551 552 case KERN_PROC_PGRP: 553 /* could do this by traversing pgrp */ 554 if (p->p_pgrp->pg_id != (pid_t)name[1]) 555 continue; 556 break; 557 558 case KERN_PROC_TTY: 559 if ((p->p_flag&SCTTY) == 0 || 560 p->p_session->s_ttyp == NULL || 561 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 562 continue; 563 break; 564 565 case KERN_PROC_UID: 566 if (p->p_ucred->cr_uid != (uid_t)name[1]) 567 continue; 568 break; 569 570 case KERN_PROC_RUID: 571 if (p->p_cred->p_ruid != (uid_t)name[1]) 572 continue; 573 break; 574 } 575 if (buflen >= sizeof(struct kinfo_proc)) { 576 fill_eproc(p, &eproc); 577 if (error = copyout((caddr_t)p, &dp->kp_proc, 578 sizeof(struct proc))) 579 return (error); 580 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 581 sizeof(eproc))) 582 return (error); 583 dp++; 584 buflen -= sizeof(struct kinfo_proc); 585 } 586 needed += sizeof(struct kinfo_proc); 587 } 588 if (doingzomb == 0) { 589 p = zombproc; 590 doingzomb++; 591 goto again; 592 } 593 if (where != NULL) { 594 *sizep = (caddr_t)dp - where; 595 if (needed > *sizep) 596 return (ENOMEM); 597 } else { 598 needed += KERN_PROCSLOP; 599 *sizep = needed; 600 } 601 return (0); 602 } 603 604 /* 605 * Fill in an eproc structure for the specified process. 606 */ 607 void 608 fill_eproc(p, ep) 609 register struct proc *p; 610 register struct eproc *ep; 611 { 612 register struct tty *tp; 613 614 ep->e_paddr = p; 615 ep->e_sess = p->p_pgrp->pg_session; 616 ep->e_pcred = *p->p_cred; 617 ep->e_ucred = *p->p_ucred; 618 if (p->p_stat == SIDL || p->p_stat == SZOMB) { 619 ep->e_vm.vm_rssize = 0; 620 ep->e_vm.vm_tsize = 0; 621 ep->e_vm.vm_dsize = 0; 622 ep->e_vm.vm_ssize = 0; 623 #ifndef sparc 624 /* ep->e_vm.vm_pmap = XXX; */ 625 #endif 626 } else { 627 register struct vmspace *vm = p->p_vmspace; 628 629 ep->e_vm.vm_rssize = vm->vm_rssize; 630 ep->e_vm.vm_tsize = vm->vm_tsize; 631 ep->e_vm.vm_dsize = vm->vm_dsize; 632 ep->e_vm.vm_ssize = vm->vm_ssize; 633 #ifndef sparc 634 ep->e_vm.vm_pmap = vm->vm_pmap; 635 #endif 636 } 637 if (p->p_pptr) 638 ep->e_ppid = p->p_pptr->p_pid; 639 else 640 ep->e_ppid = 0; 641 ep->e_pgid = p->p_pgrp->pg_id; 642 ep->e_jobc = p->p_pgrp->pg_jobc; 643 if ((p->p_flag&SCTTY) && 644 (tp = ep->e_sess->s_ttyp)) { 645 ep->e_tdev = tp->t_dev; 646 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 647 ep->e_tsess = tp->t_session; 648 } else 649 ep->e_tdev = NODEV; 650 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 651 if (SESS_LEADER(p)) 652 ep->e_flag |= EPROC_SLEADER; 653 if (p->p_wmesg) 654 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 655 ep->e_xsize = ep->e_xrssize = 0; 656 ep->e_xccount = ep->e_xswrss = 0; 657 } 658 659 #ifdef COMPAT_43 660 #include <sys/socket.h> 661 #define KINFO_PROC (0<<8) 662 #define KINFO_RT (1<<8) 663 #define KINFO_VNODE (2<<8) 664 #define KINFO_FILE (3<<8) 665 #define KINFO_METER (4<<8) 666 #define KINFO_LOADAVG (5<<8) 667 #define KINFO_CLOCKRATE (6<<8) 668 669 struct getkerninfo_args { 670 int op; 671 char *where; 672 int *size; 673 int arg; 674 }; 675 676 ogetkerninfo(p, uap, retval) 677 struct proc *p; 678 register struct getkerninfo_args *uap; 679 int *retval; 680 { 681 int error, name[5]; 682 u_int size; 683 684 if (uap->size && 685 (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 686 return (error); 687 688 switch (uap->op & 0xff00) { 689 690 case KINFO_RT: 691 name[0] = PF_ROUTE; 692 name[1] = 0; 693 name[2] = (uap->op & 0xff0000) >> 16; 694 name[3] = uap->op & 0xff; 695 name[4] = uap->arg; 696 error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 697 break; 698 699 case KINFO_VNODE: 700 name[0] = KERN_VNODE; 701 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 702 break; 703 704 case KINFO_PROC: 705 name[0] = KERN_PROC; 706 name[1] = uap->op & 0xff; 707 name[2] = uap->arg; 708 error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 709 break; 710 711 case KINFO_FILE: 712 name[0] = KERN_FILE; 713 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 714 break; 715 716 case KINFO_METER: 717 name[0] = VM_METER; 718 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 719 break; 720 721 case KINFO_LOADAVG: 722 name[0] = VM_LOADAVG; 723 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 724 break; 725 726 case KINFO_CLOCKRATE: 727 name[0] = KERN_CLOCKRATE; 728 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 729 break; 730 731 default: 732 return (EOPNOTSUPP); 733 } 734 if (error) 735 return (error); 736 *retval = size; 737 if (uap->size) 738 error = copyout((caddr_t)&size, (caddr_t)uap->size, 739 sizeof(size)); 740 return (error); 741 } 742 #endif /* COMPAT_43 */ 743