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.31 (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 size_t *oldlenp; 53 void *new; 54 size_t 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 size_t *oldlenp; 158 void *newp; 159 size_t 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 size_t *oldlenp; 225 void *newp; 226 size_t 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 size_t *oldlenp; 264 void *newp; 265 size_t 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 size_t *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 size_t *oldlenp; 310 void *newp; 311 size_t 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 size_t *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 size_t *oldlenp; 362 void *newp, *sp; 363 int len; 364 { 365 int error = 0; 366 367 if (oldp && *oldlenp < len) 368 return (ENOMEM); 369 if (newp) 370 return (EPERM); 371 *oldlenp = len; 372 if (oldp) 373 error = copyout(sp, oldp, len); 374 return (error); 375 } 376 377 /* 378 * Get file structures. 379 */ 380 sysctl_file(where, sizep) 381 char *where; 382 size_t *sizep; 383 { 384 int buflen, error; 385 struct file *fp; 386 char *start = where; 387 388 buflen = *sizep; 389 if (where == NULL) { 390 /* 391 * overestimate by 10 files 392 */ 393 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 394 return (0); 395 } 396 397 /* 398 * first copyout filehead 399 */ 400 if (buflen < sizeof(filehead)) { 401 *sizep = 0; 402 return (0); 403 } 404 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead))) 405 return (error); 406 buflen += sizeof(filehead); 407 where += sizeof(filehead); 408 409 /* 410 * followed by an array of file structures 411 */ 412 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 413 if (buflen < sizeof(struct file)) { 414 *sizep = where - start; 415 return (ENOMEM); 416 } 417 if (error = copyout((caddr_t)fp, where, sizeof (struct file))) 418 return (error); 419 buflen -= sizeof(struct file); 420 where += sizeof(struct file); 421 } 422 *sizep = where - start; 423 return (0); 424 } 425 426 /* 427 * try over estimating by 5 procs 428 */ 429 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 430 431 sysctl_doproc(name, namelen, where, sizep) 432 int *name; 433 u_int namelen; 434 char *where; 435 size_t *sizep; 436 { 437 register struct proc *p; 438 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 439 register int needed = 0; 440 int buflen = where != NULL ? *sizep : 0; 441 int doingzomb; 442 struct eproc eproc; 443 int error = 0; 444 445 if (namelen != 2) 446 return (EINVAL); 447 p = (struct proc *)allproc; 448 doingzomb = 0; 449 again: 450 for (; p != NULL; p = p->p_nxt) { 451 /* 452 * Skip embryonic processes. 453 */ 454 if (p->p_stat == SIDL) 455 continue; 456 /* 457 * TODO - make more efficient (see notes below). 458 * do by session. 459 */ 460 switch (name[0]) { 461 462 case KERN_PROC_PID: 463 /* could do this with just a lookup */ 464 if (p->p_pid != (pid_t)name[1]) 465 continue; 466 break; 467 468 case KERN_PROC_PGRP: 469 /* could do this by traversing pgrp */ 470 if (p->p_pgrp->pg_id != (pid_t)name[1]) 471 continue; 472 break; 473 474 case KERN_PROC_TTY: 475 if ((p->p_flag&SCTTY) == 0 || 476 p->p_session->s_ttyp == NULL || 477 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 478 continue; 479 break; 480 481 case KERN_PROC_UID: 482 if (p->p_ucred->cr_uid != (uid_t)name[1]) 483 continue; 484 break; 485 486 case KERN_PROC_RUID: 487 if (p->p_cred->p_ruid != (uid_t)name[1]) 488 continue; 489 break; 490 } 491 if (buflen >= sizeof(struct kinfo_proc)) { 492 fill_eproc(p, &eproc); 493 if (error = copyout((caddr_t)p, &dp->kp_proc, 494 sizeof(struct proc))) 495 return (error); 496 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 497 sizeof(eproc))) 498 return (error); 499 dp++; 500 buflen -= sizeof(struct kinfo_proc); 501 } 502 needed += sizeof(struct kinfo_proc); 503 } 504 if (doingzomb == 0) { 505 p = zombproc; 506 doingzomb++; 507 goto again; 508 } 509 if (where != NULL) { 510 *sizep = (caddr_t)dp - where; 511 if (needed > *sizep) 512 return (ENOMEM); 513 } else { 514 needed += KERN_PROCSLOP; 515 *sizep = needed; 516 } 517 return (0); 518 } 519 520 /* 521 * Fill in an eproc structure for the specified process. 522 */ 523 void 524 fill_eproc(p, ep) 525 register struct proc *p; 526 register struct eproc *ep; 527 { 528 register struct tty *tp; 529 530 ep->e_paddr = p; 531 ep->e_sess = p->p_pgrp->pg_session; 532 ep->e_pcred = *p->p_cred; 533 ep->e_ucred = *p->p_ucred; 534 if (p->p_stat == SIDL || p->p_stat == SZOMB) { 535 ep->e_vm.vm_rssize = 0; 536 ep->e_vm.vm_tsize = 0; 537 ep->e_vm.vm_dsize = 0; 538 ep->e_vm.vm_ssize = 0; 539 #ifndef sparc 540 /* ep->e_vm.vm_pmap = XXX; */ 541 #endif 542 } else { 543 register struct vmspace *vm = p->p_vmspace; 544 545 ep->e_vm.vm_rssize = vm->vm_rssize; 546 ep->e_vm.vm_tsize = vm->vm_tsize; 547 ep->e_vm.vm_dsize = vm->vm_dsize; 548 ep->e_vm.vm_ssize = vm->vm_ssize; 549 #ifndef sparc 550 ep->e_vm.vm_pmap = vm->vm_pmap; 551 #endif 552 } 553 if (p->p_pptr) 554 ep->e_ppid = p->p_pptr->p_pid; 555 else 556 ep->e_ppid = 0; 557 ep->e_pgid = p->p_pgrp->pg_id; 558 ep->e_jobc = p->p_pgrp->pg_jobc; 559 if ((p->p_flag&SCTTY) && 560 (tp = ep->e_sess->s_ttyp)) { 561 ep->e_tdev = tp->t_dev; 562 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 563 ep->e_tsess = tp->t_session; 564 } else 565 ep->e_tdev = NODEV; 566 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 567 if (SESS_LEADER(p)) 568 ep->e_flag |= EPROC_SLEADER; 569 if (p->p_wmesg) 570 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 571 ep->e_xsize = ep->e_xrssize = 0; 572 ep->e_xccount = ep->e_xswrss = 0; 573 } 574 575 #ifdef COMPAT_43 576 #include <sys/socket.h> 577 #define KINFO_PROC (0<<8) 578 #define KINFO_RT (1<<8) 579 #define KINFO_VNODE (2<<8) 580 #define KINFO_FILE (3<<8) 581 #define KINFO_METER (4<<8) 582 #define KINFO_LOADAVG (5<<8) 583 #define KINFO_CLOCKRATE (6<<8) 584 585 struct getkerninfo_args { 586 int op; 587 char *where; 588 int *size; 589 int arg; 590 }; 591 592 getkerninfo(p, uap, retval) 593 struct proc *p; 594 register struct getkerninfo_args *uap; 595 int *retval; 596 { 597 int error, name[5]; 598 u_int size; 599 600 if (uap->size && 601 (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 602 return (error); 603 604 switch (uap->op & 0xff00) { 605 606 case KINFO_RT: 607 name[0] = PF_ROUTE; 608 name[1] = 0; 609 name[2] = (uap->op & 0xff0000) >> 16; 610 name[3] = uap->op & 0xff; 611 name[4] = uap->arg; 612 error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 613 break; 614 615 case KINFO_VNODE: 616 name[0] = KERN_VNODE; 617 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 618 break; 619 620 case KINFO_PROC: 621 name[0] = KERN_PROC; 622 name[1] = uap->op & 0xff; 623 name[2] = uap->arg; 624 error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 625 break; 626 627 case KINFO_FILE: 628 name[0] = KERN_FILE; 629 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 630 break; 631 632 case KINFO_METER: 633 name[0] = VM_METER; 634 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 635 break; 636 637 case KINFO_LOADAVG: 638 name[0] = VM_LOADAVG; 639 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 640 break; 641 642 case KINFO_CLOCKRATE: 643 name[0] = KERN_CLOCKRATE; 644 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 645 break; 646 647 default: 648 return (EOPNOTSUPP); 649 } 650 if (error) 651 return (error); 652 *retval = size; 653 if (uap->size) 654 error = copyout((caddr_t)&size, (caddr_t)uap->size, 655 sizeof(size)); 656 return (error); 657 } 658 #endif /* COMPAT_43 */ 659