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