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