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