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