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