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.33 (Berkeley) 04/19/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/sysctl.h> 23 #include <sys/unistd.h> 24 #include <sys/buf.h> 25 #include <sys/ioctl.h> 26 #include <sys/tty.h> 27 28 #include <vm/vm.h> 29 30 #include <sys/kinfo_proc.h> 31 32 sysctlfn kern_sysctl; 33 sysctlfn hw_sysctl; 34 #ifdef DEBUG 35 sysctlfn debug_sysctl; 36 #endif 37 extern sysctlfn vm_sysctl; 38 extern sysctlfn fs_sysctl; 39 extern sysctlfn net_sysctl; 40 extern sysctlfn cpu_sysctl; 41 42 /* 43 * Locking and stats 44 */ 45 static struct sysctl_lock { 46 int sl_lock; 47 int sl_want; 48 int sl_locked; 49 } memlock; 50 51 struct sysctl_args { 52 int *name; 53 u_int namelen; 54 void *old; 55 size_t *oldlenp; 56 void *new; 57 size_t newlen; 58 }; 59 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 case CTL_MACHDEP: 100 fn = cpu_sysctl; 101 break; 102 #endif 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) 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_POSIX1: 184 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 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_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 default: 217 return (EOPNOTSUPP); 218 } 219 /* NOTREACHED */ 220 } 221 222 /* 223 * hardware related system variables. 224 */ 225 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 226 int *name; 227 u_int namelen; 228 void *oldp; 229 size_t *oldlenp; 230 void *newp; 231 size_t newlen; 232 struct proc *p; 233 { 234 extern char machine[], cpu_model[]; 235 236 /* all sysctl names at this level are terminal */ 237 if (namelen != 1) 238 return (ENOTDIR); /* overloaded */ 239 240 switch (name[0]) { 241 case HW_MACHINE: 242 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 243 case HW_MODEL: 244 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 245 case HW_NCPU: 246 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 247 case HW_CPUSPEED: 248 return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed)); 249 case HW_PHYSMEM: 250 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 251 case HW_USERMEM: 252 return (sysctl_rdint(oldp, oldlenp, newp, 253 ctob(physmem - cnt.v_wire_count))); 254 case HW_PAGESIZE: 255 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 256 default: 257 return (EOPNOTSUPP); 258 } 259 /* NOTREACHED */ 260 } 261 262 #ifdef DEBUG 263 /* 264 * Debugging related system variables. 265 */ 266 struct ctldebug debug0, debug1, debug2, debug3, debug4; 267 struct ctldebug debug5, debug6, debug7, debug8, debug9; 268 struct ctldebug debug10, debug11, debug12, debug13, debug14; 269 struct ctldebug debug15, debug16, debug17, debug18, debug19; 270 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 271 &debug0, &debug1, &debug2, &debug3, &debug4, 272 &debug5, &debug6, &debug7, &debug8, &debug9, 273 &debug10, &debug11, &debug12, &debug13, &debug14, 274 &debug15, &debug16, &debug17, &debug18, &debug19, 275 }; 276 int 277 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 278 int *name; 279 u_int namelen; 280 void *oldp; 281 size_t *oldlenp; 282 void *newp; 283 size_t newlen; 284 struct proc *p; 285 { 286 struct ctldebug *cdp; 287 288 /* all sysctl names at this level are name and field */ 289 if (namelen != 2) 290 return (ENOTDIR); /* overloaded */ 291 cdp = debugvars[name[0]]; 292 if (cdp->debugname == 0) 293 return (EOPNOTSUPP); 294 switch (name[1]) { 295 case CTL_DEBUG_NAME: 296 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 297 case CTL_DEBUG_VALUE: 298 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 299 default: 300 return (EOPNOTSUPP); 301 } 302 /* NOTREACHED */ 303 } 304 #endif /* DEBUG */ 305 306 /* 307 * Validate parameters and get old / set new parameters 308 * for an integer-valued sysctl function. 309 */ 310 sysctl_int(oldp, oldlenp, newp, newlen, valp) 311 void *oldp; 312 size_t *oldlenp; 313 void *newp; 314 size_t newlen; 315 int *valp; 316 { 317 int error = 0; 318 319 if (oldp && *oldlenp < sizeof(int)) 320 return (ENOMEM); 321 if (newp && newlen != sizeof(int)) 322 return (EINVAL); 323 *oldlenp = sizeof(int); 324 if (oldp) 325 error = copyout(valp, oldp, sizeof(int)); 326 if (error == 0 && newp) 327 error = copyin(newp, valp, sizeof(int)); 328 return (error); 329 } 330 331 /* 332 * As above, but read-only. 333 */ 334 sysctl_rdint(oldp, oldlenp, newp, val) 335 void *oldp; 336 size_t *oldlenp; 337 void *newp; 338 int val; 339 { 340 int error = 0; 341 342 if (oldp && *oldlenp < sizeof(int)) 343 return (ENOMEM); 344 if (newp) 345 return (EPERM); 346 *oldlenp = sizeof(int); 347 if (oldp) 348 error = copyout((caddr_t)&val, oldp, sizeof(int)); 349 return (error); 350 } 351 352 /* 353 * Validate parameters and get old / set new parameters 354 * for a string-valued sysctl function. 355 */ 356 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 357 void *oldp; 358 size_t *oldlenp; 359 void *newp; 360 size_t newlen; 361 char *str; 362 int maxlen; 363 { 364 int len, error = 0; 365 366 len = strlen(str) + 1; 367 if (oldp && *oldlenp < len) 368 return (ENOMEM); 369 if (newp && newlen >= maxlen) 370 return (EINVAL); 371 if (oldp) { 372 *oldlenp = len; 373 error = copyout(str, oldp, len); 374 } 375 if (error == 0 && newp) { 376 error = copyin(newp, str, newlen); 377 str[newlen] = 0; 378 } 379 return (error); 380 } 381 382 /* 383 * As above, but read-only. 384 */ 385 sysctl_rdstring(oldp, oldlenp, newp, str) 386 void *oldp; 387 size_t *oldlenp; 388 void *newp; 389 char *str; 390 { 391 int len, error = 0; 392 393 len = strlen(str) + 1; 394 if (oldp && *oldlenp < len) 395 return (ENOMEM); 396 if (newp) 397 return (EPERM); 398 *oldlenp = len; 399 if (oldp) 400 error = copyout(str, oldp, len); 401 return (error); 402 } 403 404 /* 405 * Validate parameters and get old parameters 406 * for a structure oriented sysctl function. 407 */ 408 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 409 void *oldp; 410 size_t *oldlenp; 411 void *newp, *sp; 412 int len; 413 { 414 int error = 0; 415 416 if (oldp && *oldlenp < len) 417 return (ENOMEM); 418 if (newp) 419 return (EPERM); 420 *oldlenp = len; 421 if (oldp) 422 error = copyout(sp, oldp, len); 423 return (error); 424 } 425 426 /* 427 * Get file structures. 428 */ 429 sysctl_file(where, sizep) 430 char *where; 431 size_t *sizep; 432 { 433 int buflen, error; 434 struct file *fp; 435 char *start = where; 436 437 buflen = *sizep; 438 if (where == NULL) { 439 /* 440 * overestimate by 10 files 441 */ 442 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 443 return (0); 444 } 445 446 /* 447 * first copyout filehead 448 */ 449 if (buflen < sizeof(filehead)) { 450 *sizep = 0; 451 return (0); 452 } 453 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead))) 454 return (error); 455 buflen += sizeof(filehead); 456 where += sizeof(filehead); 457 458 /* 459 * followed by an array of file structures 460 */ 461 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 462 if (buflen < sizeof(struct file)) { 463 *sizep = where - start; 464 return (ENOMEM); 465 } 466 if (error = copyout((caddr_t)fp, where, sizeof (struct file))) 467 return (error); 468 buflen -= sizeof(struct file); 469 where += sizeof(struct file); 470 } 471 *sizep = where - start; 472 return (0); 473 } 474 475 /* 476 * try over estimating by 5 procs 477 */ 478 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 479 480 sysctl_doproc(name, namelen, where, sizep) 481 int *name; 482 u_int namelen; 483 char *where; 484 size_t *sizep; 485 { 486 register struct proc *p; 487 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 488 register int needed = 0; 489 int buflen = where != NULL ? *sizep : 0; 490 int doingzomb; 491 struct eproc eproc; 492 int error = 0; 493 494 if (namelen != 2) 495 return (EINVAL); 496 p = (struct proc *)allproc; 497 doingzomb = 0; 498 again: 499 for (; p != NULL; p = p->p_nxt) { 500 /* 501 * Skip embryonic processes. 502 */ 503 if (p->p_stat == SIDL) 504 continue; 505 /* 506 * TODO - make more efficient (see notes below). 507 * do by session. 508 */ 509 switch (name[0]) { 510 511 case KERN_PROC_PID: 512 /* could do this with just a lookup */ 513 if (p->p_pid != (pid_t)name[1]) 514 continue; 515 break; 516 517 case KERN_PROC_PGRP: 518 /* could do this by traversing pgrp */ 519 if (p->p_pgrp->pg_id != (pid_t)name[1]) 520 continue; 521 break; 522 523 case KERN_PROC_TTY: 524 if ((p->p_flag&SCTTY) == 0 || 525 p->p_session->s_ttyp == NULL || 526 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 527 continue; 528 break; 529 530 case KERN_PROC_UID: 531 if (p->p_ucred->cr_uid != (uid_t)name[1]) 532 continue; 533 break; 534 535 case KERN_PROC_RUID: 536 if (p->p_cred->p_ruid != (uid_t)name[1]) 537 continue; 538 break; 539 } 540 if (buflen >= sizeof(struct kinfo_proc)) { 541 fill_eproc(p, &eproc); 542 if (error = copyout((caddr_t)p, &dp->kp_proc, 543 sizeof(struct proc))) 544 return (error); 545 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 546 sizeof(eproc))) 547 return (error); 548 dp++; 549 buflen -= sizeof(struct kinfo_proc); 550 } 551 needed += sizeof(struct kinfo_proc); 552 } 553 if (doingzomb == 0) { 554 p = zombproc; 555 doingzomb++; 556 goto again; 557 } 558 if (where != NULL) { 559 *sizep = (caddr_t)dp - where; 560 if (needed > *sizep) 561 return (ENOMEM); 562 } else { 563 needed += KERN_PROCSLOP; 564 *sizep = needed; 565 } 566 return (0); 567 } 568 569 /* 570 * Fill in an eproc structure for the specified process. 571 */ 572 void 573 fill_eproc(p, ep) 574 register struct proc *p; 575 register struct eproc *ep; 576 { 577 register struct tty *tp; 578 579 ep->e_paddr = p; 580 ep->e_sess = p->p_pgrp->pg_session; 581 ep->e_pcred = *p->p_cred; 582 ep->e_ucred = *p->p_ucred; 583 if (p->p_stat == SIDL || p->p_stat == SZOMB) { 584 ep->e_vm.vm_rssize = 0; 585 ep->e_vm.vm_tsize = 0; 586 ep->e_vm.vm_dsize = 0; 587 ep->e_vm.vm_ssize = 0; 588 #ifndef sparc 589 /* ep->e_vm.vm_pmap = XXX; */ 590 #endif 591 } else { 592 register struct vmspace *vm = p->p_vmspace; 593 594 ep->e_vm.vm_rssize = vm->vm_rssize; 595 ep->e_vm.vm_tsize = vm->vm_tsize; 596 ep->e_vm.vm_dsize = vm->vm_dsize; 597 ep->e_vm.vm_ssize = vm->vm_ssize; 598 #ifndef sparc 599 ep->e_vm.vm_pmap = vm->vm_pmap; 600 #endif 601 } 602 if (p->p_pptr) 603 ep->e_ppid = p->p_pptr->p_pid; 604 else 605 ep->e_ppid = 0; 606 ep->e_pgid = p->p_pgrp->pg_id; 607 ep->e_jobc = p->p_pgrp->pg_jobc; 608 if ((p->p_flag&SCTTY) && 609 (tp = ep->e_sess->s_ttyp)) { 610 ep->e_tdev = tp->t_dev; 611 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 612 ep->e_tsess = tp->t_session; 613 } else 614 ep->e_tdev = NODEV; 615 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 616 if (SESS_LEADER(p)) 617 ep->e_flag |= EPROC_SLEADER; 618 if (p->p_wmesg) 619 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 620 ep->e_xsize = ep->e_xrssize = 0; 621 ep->e_xccount = ep->e_xswrss = 0; 622 } 623 624 #ifdef COMPAT_43 625 #include <sys/socket.h> 626 #define KINFO_PROC (0<<8) 627 #define KINFO_RT (1<<8) 628 #define KINFO_VNODE (2<<8) 629 #define KINFO_FILE (3<<8) 630 #define KINFO_METER (4<<8) 631 #define KINFO_LOADAVG (5<<8) 632 #define KINFO_CLOCKRATE (6<<8) 633 634 struct getkerninfo_args { 635 int op; 636 char *where; 637 int *size; 638 int arg; 639 }; 640 641 ogetkerninfo(p, uap, retval) 642 struct proc *p; 643 register struct getkerninfo_args *uap; 644 int *retval; 645 { 646 int error, name[5]; 647 u_int size; 648 649 if (uap->size && 650 (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 651 return (error); 652 653 switch (uap->op & 0xff00) { 654 655 case KINFO_RT: 656 name[0] = PF_ROUTE; 657 name[1] = 0; 658 name[2] = (uap->op & 0xff0000) >> 16; 659 name[3] = uap->op & 0xff; 660 name[4] = uap->arg; 661 error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 662 break; 663 664 case KINFO_VNODE: 665 name[0] = KERN_VNODE; 666 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 667 break; 668 669 case KINFO_PROC: 670 name[0] = KERN_PROC; 671 name[1] = uap->op & 0xff; 672 name[2] = uap->arg; 673 error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 674 break; 675 676 case KINFO_FILE: 677 name[0] = KERN_FILE; 678 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 679 break; 680 681 case KINFO_METER: 682 name[0] = VM_METER; 683 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 684 break; 685 686 case KINFO_LOADAVG: 687 name[0] = VM_LOADAVG; 688 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 689 break; 690 691 case KINFO_CLOCKRATE: 692 name[0] = KERN_CLOCKRATE; 693 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 694 break; 695 696 default: 697 return (EOPNOTSUPP); 698 } 699 if (error) 700 return (error); 701 *retval = size; 702 if (uap->size) 703 error = copyout((caddr_t)&size, (caddr_t)uap->size, 704 sizeof(size)); 705 return (error); 706 } 707 #endif /* COMPAT_43 */ 708