1 /* $OpenBSD: kern_sysctl.c,v 1.55 2001/07/17 20:57:49 deraadt Exp $ */ 2 /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ 3 4 /*- 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Mike Karels at Berkeley Software Design, Inc. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 40 */ 41 42 /* 43 * sysctl system call. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/malloc.h> 50 #include <sys/proc.h> 51 #include <sys/resourcevar.h> 52 #include <sys/file.h> 53 #include <sys/vnode.h> 54 #include <sys/unistd.h> 55 #include <sys/buf.h> 56 #include <sys/ioctl.h> 57 #include <sys/tty.h> 58 #include <sys/disklabel.h> 59 #include <sys/disk.h> 60 #include <vm/vm.h> 61 #include <sys/sysctl.h> 62 #include <sys/msgbuf.h> 63 #include <sys/dkstat.h> 64 #include <sys/vmmeter.h> 65 #include <sys/namei.h> 66 67 #include <uvm/uvm_extern.h> 68 69 #include <sys/mount.h> 70 #include <sys/syscallargs.h> 71 #include <dev/rndvar.h> 72 73 #ifdef DDB 74 #include <ddb/db_var.h> 75 #endif 76 77 extern struct forkstat forkstat; 78 extern struct nchstats nchstats; 79 extern int nselcoll, fscale; 80 extern struct disklist_head disklist; 81 extern fixpt_t ccpu; 82 83 int sysctl_diskinit(int, struct proc *); 84 85 /* 86 * Lock to avoid too many processes vslocking a large amount of memory 87 * at the same time. 88 */ 89 struct lock sysctl_lock, sysctl_disklock; 90 91 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES) 92 struct lock sysctl_kmemlock; 93 #endif 94 95 void 96 sysctl_init() 97 { 98 lockinit(&sysctl_lock, PLOCK|PCATCH, "sysctl", 0, 0); 99 lockinit(&sysctl_disklock, PLOCK|PCATCH, "sysctl_disklock", 0, 0); 100 101 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES) 102 lockinit(&sysctl_kmemlock, PLOCK|PCATCH, "sysctl_kmemlock", 0, 0); 103 #endif 104 } 105 106 int 107 sys___sysctl(p, v, retval) 108 struct proc *p; 109 void *v; 110 register_t *retval; 111 { 112 register struct sys___sysctl_args /* { 113 syscallarg(int *) name; 114 syscallarg(u_int) namelen; 115 syscallarg(void *) old; 116 syscallarg(size_t *) oldlenp; 117 syscallarg(void *) new; 118 syscallarg(size_t) newlen; 119 } */ *uap = v; 120 int error, dolock = 1; 121 size_t savelen = 0, oldlen = 0; 122 sysctlfn *fn; 123 int name[CTL_MAXNAME]; 124 125 if (SCARG(uap, new) != NULL && 126 (error = suser(p->p_ucred, &p->p_acflag))) 127 return (error); 128 /* 129 * all top-level sysctl names are non-terminal 130 */ 131 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2) 132 return (EINVAL); 133 error = copyin(SCARG(uap, name), &name, 134 SCARG(uap, namelen) * sizeof(int)); 135 if (error) 136 return (error); 137 138 switch (name[0]) { 139 case CTL_KERN: 140 fn = kern_sysctl; 141 if (name[2] == KERN_VNODE) /* XXX */ 142 dolock = 0; 143 break; 144 case CTL_HW: 145 fn = hw_sysctl; 146 break; 147 case CTL_VM: 148 fn = uvm_sysctl; 149 break; 150 case CTL_NET: 151 fn = net_sysctl; 152 break; 153 case CTL_FS: 154 fn = fs_sysctl; 155 break; 156 case CTL_VFS: 157 fn = vfs_sysctl; 158 break; 159 case CTL_MACHDEP: 160 fn = cpu_sysctl; 161 break; 162 #ifdef DEBUG 163 case CTL_DEBUG: 164 fn = debug_sysctl; 165 break; 166 #endif 167 #ifdef DDB 168 case CTL_DDB: 169 fn = ddb_sysctl; 170 break; 171 #endif 172 default: 173 return (EOPNOTSUPP); 174 } 175 176 if (SCARG(uap, oldlenp) && 177 (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen)))) 178 return (error); 179 if (SCARG(uap, old) != NULL) { 180 if ((error = lockmgr(&sysctl_lock, LK_EXCLUSIVE, NULL, p)) != 0) 181 return (error); 182 if (dolock) 183 if (uvm_vslock(p, SCARG(uap, old), oldlen, 184 VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { 185 lockmgr(&sysctl_lock, LK_RELEASE, NULL, p); 186 return EFAULT; 187 } 188 savelen = oldlen; 189 } 190 error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old), 191 &oldlen, SCARG(uap, new), SCARG(uap, newlen), p); 192 if (SCARG(uap, old) != NULL) { 193 if (dolock) 194 uvm_vsunlock(p, SCARG(uap, old), savelen); 195 lockmgr(&sysctl_lock, LK_RELEASE, NULL, p); 196 } 197 if (error) 198 return (error); 199 if (SCARG(uap, oldlenp)) 200 error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen)); 201 return (error); 202 } 203 204 /* 205 * Attributes stored in the kernel. 206 */ 207 char hostname[MAXHOSTNAMELEN]; 208 int hostnamelen; 209 char domainname[MAXHOSTNAMELEN]; 210 int domainnamelen; 211 long hostid; 212 char *disknames = NULL; 213 struct diskstats *diskstats = NULL; 214 #ifdef INSECURE 215 int securelevel = -1; 216 #else 217 int securelevel; 218 #endif 219 220 /* 221 * kernel related system variables. 222 */ 223 int 224 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 225 int *name; 226 u_int namelen; 227 void *oldp; 228 size_t *oldlenp; 229 void *newp; 230 size_t newlen; 231 struct proc *p; 232 { 233 int error, level, inthostid; 234 extern char ostype[], osrelease[], osversion[], version[]; 235 extern int somaxconn, sominconn; 236 extern int usermount, nosuidcoredump; 237 extern long cp_time[CPUSTATES]; 238 239 /* all sysctl names at this level are terminal */ 240 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF || 241 name[0] == KERN_MALLOCSTATS || name[0] == KERN_TTY || 242 name[0] == KERN_POOL)) 243 return (ENOTDIR); /* overloaded */ 244 245 switch (name[0]) { 246 case KERN_OSTYPE: 247 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 248 case KERN_OSRELEASE: 249 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 250 case KERN_OSREV: 251 return (sysctl_rdint(oldp, oldlenp, newp, OpenBSD)); 252 case KERN_OSVERSION: 253 return (sysctl_rdstring(oldp, oldlenp, newp, osversion)); 254 case KERN_VERSION: 255 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 256 case KERN_MAXVNODES: 257 return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 258 case KERN_MAXPROC: 259 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 260 case KERN_MAXFILES: 261 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 262 case KERN_ARGMAX: 263 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 264 case KERN_NSELCOLL: 265 return (sysctl_rdint(oldp, oldlenp, newp, nselcoll)); 266 case KERN_SECURELVL: 267 level = securelevel; 268 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 269 newp == NULL) 270 return (error); 271 if ((securelevel > 0 || level < -1) 272 && level < securelevel && p->p_pid != 1) 273 return (EPERM); 274 securelevel = level; 275 return (0); 276 case KERN_HOSTNAME: 277 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 278 hostname, sizeof(hostname)); 279 if (newp && !error) 280 hostnamelen = newlen; 281 return (error); 282 case KERN_DOMAINNAME: 283 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 284 domainname, sizeof(domainname)); 285 if (newp && !error) 286 domainnamelen = newlen; 287 return (error); 288 case KERN_HOSTID: 289 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 290 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 291 hostid = inthostid; 292 return (error); 293 case KERN_CLOCKRATE: 294 return (sysctl_clockrate(oldp, oldlenp)); 295 case KERN_BOOTTIME: 296 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 297 sizeof(struct timeval))); 298 case KERN_VNODE: 299 return (sysctl_vnode(oldp, oldlenp, p)); 300 case KERN_PROC: 301 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 302 case KERN_FILE: 303 return (sysctl_file(oldp, oldlenp)); 304 #ifdef GPROF 305 case KERN_PROF: 306 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 307 newp, newlen)); 308 #endif 309 case KERN_POSIX1: 310 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 311 case KERN_NGROUPS: 312 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 313 case KERN_JOB_CONTROL: 314 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 315 case KERN_SAVED_IDS: 316 #ifdef _POSIX_SAVED_IDS 317 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 318 #else 319 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 320 #endif 321 case KERN_MAXPARTITIONS: 322 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 323 case KERN_RAWPARTITION: 324 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 325 case KERN_NTPTIME: 326 return (sysctl_ntptime(oldp, oldlenp)); 327 case KERN_SOMAXCONN: 328 return (sysctl_int(oldp, oldlenp, newp, newlen, &somaxconn)); 329 case KERN_SOMINCONN: 330 return (sysctl_int(oldp, oldlenp, newp, newlen, &sominconn)); 331 case KERN_USERMOUNT: 332 return (sysctl_int(oldp, oldlenp, newp, newlen, &usermount)); 333 case KERN_RND: 334 return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats, 335 sizeof(rndstats))); 336 case KERN_ARND: 337 return (sysctl_rdint(oldp, oldlenp, newp, arc4random())); 338 case KERN_NOSUIDCOREDUMP: 339 return (sysctl_int(oldp, oldlenp, newp, newlen, &nosuidcoredump)); 340 case KERN_FSYNC: 341 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 342 case KERN_SYSVMSG: 343 #ifdef SYSVMSG 344 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 345 #else 346 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 347 #endif 348 case KERN_SYSVSEM: 349 #ifdef SYSVSEM 350 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 351 #else 352 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 353 #endif 354 case KERN_SYSVSHM: 355 #ifdef SYSVSHM 356 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 357 #else 358 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 359 #endif 360 case KERN_MSGBUFSIZE: 361 /* 362 * deal with cases where the message buffer has 363 * become corrupted. 364 */ 365 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 366 return (ENXIO); 367 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 368 case KERN_MSGBUF: 369 /* see note above */ 370 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 371 return (ENXIO); 372 return (sysctl_rdstruct(oldp, oldlenp, newp, msgbufp, 373 msgbufp->msg_bufs + offsetof(struct msgbuf, msg_bufc))); 374 case KERN_MALLOCSTATS: 375 return (sysctl_malloc(name + 1, namelen - 1, oldp, oldlenp, 376 newp, newlen, p)); 377 case KERN_CPTIME: 378 return (sysctl_rdstruct(oldp, oldlenp, newp, &cp_time, 379 sizeof(cp_time))); 380 case KERN_NCHSTATS: 381 return (sysctl_rdstruct(oldp, oldlenp, newp, &nchstats, 382 sizeof(struct nchstats))); 383 case KERN_FORKSTAT: 384 return (sysctl_rdstruct(oldp, oldlenp, newp, &forkstat, 385 sizeof(struct forkstat))); 386 case KERN_TTY: 387 return (sysctl_tty(name + 1, namelen - 1, oldp, oldlenp, 388 newp, newlen)); 389 case KERN_FSCALE: 390 return (sysctl_rdint(oldp, oldlenp, newp, fscale)); 391 case KERN_CCPU: 392 return (sysctl_rdint(oldp, oldlenp, newp, ccpu)); 393 case KERN_NPROCS: 394 return (sysctl_rdint(oldp, oldlenp, newp, nprocs)); 395 case KERN_POOL: 396 return (sysctl_dopool(name + 1, namelen - 1, oldp, oldlenp)); 397 default: 398 return (EOPNOTSUPP); 399 } 400 /* NOTREACHED */ 401 } 402 403 /* 404 * hardware related system variables. 405 */ 406 int 407 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 408 int *name; 409 u_int namelen; 410 void *oldp; 411 size_t *oldlenp; 412 void *newp; 413 size_t newlen; 414 struct proc *p; 415 { 416 extern char machine[], cpu_model[]; 417 int err; 418 419 /* all sysctl names at this level are terminal */ 420 if (namelen != 1) 421 return (ENOTDIR); /* overloaded */ 422 423 switch (name[0]) { 424 case HW_MACHINE: 425 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 426 case HW_MODEL: 427 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 428 case HW_NCPU: 429 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 430 case HW_BYTEORDER: 431 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 432 case HW_PHYSMEM: 433 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 434 case HW_USERMEM: 435 return (sysctl_rdint(oldp, oldlenp, newp, 436 ctob(physmem - uvmexp.wired))); 437 case HW_PAGESIZE: 438 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 439 case HW_DISKNAMES: 440 err = sysctl_diskinit(0, p); 441 if (err) 442 return err; 443 return (sysctl_rdstring(oldp, oldlenp, newp, disknames)); 444 case HW_DISKSTATS: 445 err = sysctl_diskinit(1, p); 446 if (err) 447 return err; 448 return (sysctl_rdstruct(oldp, oldlenp, newp, diskstats, 449 disk_count * sizeof(struct diskstats))); 450 case HW_DISKCOUNT: 451 return (sysctl_rdint(oldp, oldlenp, newp, disk_count)); 452 default: 453 return (EOPNOTSUPP); 454 } 455 /* NOTREACHED */ 456 } 457 458 #ifdef DEBUG 459 /* 460 * Debugging related system variables. 461 */ 462 struct ctldebug debug0, debug1, debug2, debug3, debug4; 463 struct ctldebug debug5, debug6, debug7, debug8, debug9; 464 struct ctldebug debug10, debug11, debug12, debug13, debug14; 465 struct ctldebug debug15, debug16, debug17, debug18, debug19; 466 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 467 &debug0, &debug1, &debug2, &debug3, &debug4, 468 &debug5, &debug6, &debug7, &debug8, &debug9, 469 &debug10, &debug11, &debug12, &debug13, &debug14, 470 &debug15, &debug16, &debug17, &debug18, &debug19, 471 }; 472 int 473 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 474 int *name; 475 u_int namelen; 476 void *oldp; 477 size_t *oldlenp; 478 void *newp; 479 size_t newlen; 480 struct proc *p; 481 { 482 struct ctldebug *cdp; 483 484 /* all sysctl names at this level are name and field */ 485 if (namelen != 2) 486 return (ENOTDIR); /* overloaded */ 487 cdp = debugvars[name[0]]; 488 if (cdp->debugname == 0) 489 return (EOPNOTSUPP); 490 switch (name[1]) { 491 case CTL_DEBUG_NAME: 492 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 493 case CTL_DEBUG_VALUE: 494 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 495 default: 496 return (EOPNOTSUPP); 497 } 498 /* NOTREACHED */ 499 } 500 #endif /* DEBUG */ 501 502 /* 503 * Validate parameters and get old / set new parameters 504 * for an integer-valued sysctl function. 505 */ 506 int 507 sysctl_int(oldp, oldlenp, newp, newlen, valp) 508 void *oldp; 509 size_t *oldlenp; 510 void *newp; 511 size_t newlen; 512 int *valp; 513 { 514 int error = 0; 515 516 if (oldp && *oldlenp < sizeof(int)) 517 return (ENOMEM); 518 if (newp && newlen != sizeof(int)) 519 return (EINVAL); 520 *oldlenp = sizeof(int); 521 if (oldp) 522 error = copyout(valp, oldp, sizeof(int)); 523 if (error == 0 && newp) 524 error = copyin(newp, valp, sizeof(int)); 525 return (error); 526 } 527 528 /* 529 * As above, but read-only. 530 */ 531 int 532 sysctl_rdint(oldp, oldlenp, newp, val) 533 void *oldp; 534 size_t *oldlenp; 535 void *newp; 536 int val; 537 { 538 int error = 0; 539 540 if (oldp && *oldlenp < sizeof(int)) 541 return (ENOMEM); 542 if (newp) 543 return (EPERM); 544 *oldlenp = sizeof(int); 545 if (oldp) 546 error = copyout((caddr_t)&val, oldp, sizeof(int)); 547 return (error); 548 } 549 550 /* 551 * Validate parameters and get old / set new parameters 552 * for an integer-valued sysctl function. 553 */ 554 int 555 sysctl_quad(oldp, oldlenp, newp, newlen, valp) 556 void *oldp; 557 size_t *oldlenp; 558 void *newp; 559 size_t newlen; 560 int64_t *valp; 561 { 562 int error = 0; 563 564 if (oldp && *oldlenp < sizeof(int64_t)) 565 return (ENOMEM); 566 if (newp && newlen != sizeof(int64_t)) 567 return (EINVAL); 568 *oldlenp = sizeof(int64_t); 569 if (oldp) 570 error = copyout(valp, oldp, sizeof(int64_t)); 571 if (error == 0 && newp) 572 error = copyin(newp, valp, sizeof(int64_t)); 573 return (error); 574 } 575 576 /* 577 * As above, but read-only. 578 */ 579 int 580 sysctl_rdquad(oldp, oldlenp, newp, val) 581 void *oldp; 582 size_t *oldlenp; 583 void *newp; 584 int64_t val; 585 { 586 int error = 0; 587 588 if (oldp && *oldlenp < sizeof(int64_t)) 589 return (ENOMEM); 590 if (newp) 591 return (EPERM); 592 *oldlenp = sizeof(int64_t); 593 if (oldp) 594 error = copyout((caddr_t)&val, oldp, sizeof(int64_t)); 595 return (error); 596 } 597 598 /* 599 * Validate parameters and get old / set new parameters 600 * for a string-valued sysctl function. 601 */ 602 int 603 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 604 void *oldp; 605 size_t *oldlenp; 606 void *newp; 607 size_t newlen; 608 char *str; 609 int maxlen; 610 { 611 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 0); 612 } 613 614 int 615 sysctl_tstring(oldp, oldlenp, newp, newlen, str, maxlen) 616 void *oldp; 617 size_t *oldlenp; 618 void *newp; 619 size_t newlen; 620 char *str; 621 int maxlen; 622 { 623 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1); 624 } 625 626 int 627 sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, trunc) 628 void *oldp; 629 size_t *oldlenp; 630 void *newp; 631 size_t newlen; 632 char *str; 633 int maxlen; 634 int trunc; 635 { 636 int len, error = 0; 637 char c; 638 639 len = strlen(str) + 1; 640 if (oldp && *oldlenp < len) { 641 if (trunc == 0 || *oldlenp == 0) 642 return (ENOMEM); 643 } 644 if (newp && newlen >= maxlen) 645 return (EINVAL); 646 if (oldp) { 647 if (trunc && *oldlenp < len) { 648 /* save & zap NUL terminator while copying */ 649 c = str[*oldlenp-1]; 650 str[*oldlenp-1] = '\0'; 651 error = copyout(str, oldp, *oldlenp); 652 str[*oldlenp-1] = c; 653 } else { 654 *oldlenp = len; 655 error = copyout(str, oldp, len); 656 } 657 } 658 if (error == 0 && newp) { 659 error = copyin(newp, str, newlen); 660 str[newlen] = 0; 661 } 662 return (error); 663 } 664 665 /* 666 * As above, but read-only. 667 */ 668 int 669 sysctl_rdstring(oldp, oldlenp, newp, str) 670 void *oldp; 671 size_t *oldlenp; 672 void *newp; 673 char *str; 674 { 675 int len, error = 0; 676 677 len = strlen(str) + 1; 678 if (oldp && *oldlenp < len) 679 return (ENOMEM); 680 if (newp) 681 return (EPERM); 682 *oldlenp = len; 683 if (oldp) 684 error = copyout(str, oldp, len); 685 return (error); 686 } 687 688 /* 689 * Validate parameters and get old / set new parameters 690 * for a structure oriented sysctl function. 691 */ 692 int 693 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 694 void *oldp; 695 size_t *oldlenp; 696 void *newp; 697 size_t newlen; 698 void *sp; 699 int len; 700 { 701 int error = 0; 702 703 if (oldp && *oldlenp < len) 704 return (ENOMEM); 705 if (newp && newlen > len) 706 return (EINVAL); 707 if (oldp) { 708 *oldlenp = len; 709 error = copyout(sp, oldp, len); 710 } 711 if (error == 0 && newp) 712 error = copyin(newp, sp, len); 713 return (error); 714 } 715 716 /* 717 * Validate parameters and get old parameters 718 * for a structure oriented sysctl function. 719 */ 720 int 721 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 722 void *oldp; 723 size_t *oldlenp; 724 void *newp, *sp; 725 int len; 726 { 727 int error = 0; 728 729 if (oldp && *oldlenp < len) 730 return (ENOMEM); 731 if (newp) 732 return (EPERM); 733 *oldlenp = len; 734 if (oldp) 735 error = copyout(sp, oldp, len); 736 return (error); 737 } 738 739 /* 740 * Get file structures. 741 */ 742 int 743 sysctl_file(where, sizep) 744 char *where; 745 size_t *sizep; 746 { 747 int buflen, error; 748 struct file *fp; 749 char *start = where; 750 751 buflen = *sizep; 752 if (where == NULL) { 753 /* 754 * overestimate by 10 files 755 */ 756 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 757 return (0); 758 } 759 760 /* 761 * first copyout filehead 762 */ 763 if (buflen < sizeof(filehead)) { 764 *sizep = 0; 765 return (0); 766 } 767 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 768 if (error) 769 return (error); 770 buflen -= sizeof(filehead); 771 where += sizeof(filehead); 772 773 /* 774 * followed by an array of file structures 775 */ 776 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 777 if (buflen < sizeof(struct file)) { 778 *sizep = where - start; 779 return (ENOMEM); 780 } 781 error = copyout((caddr_t)fp, where, sizeof (struct file)); 782 if (error) 783 return (error); 784 buflen -= sizeof(struct file); 785 where += sizeof(struct file); 786 } 787 *sizep = where - start; 788 return (0); 789 } 790 791 /* 792 * try over estimating by 5 procs 793 */ 794 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 795 796 int 797 sysctl_doproc(name, namelen, where, sizep) 798 int *name; 799 u_int namelen; 800 char *where; 801 size_t *sizep; 802 { 803 register struct proc *p; 804 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 805 register int needed = 0; 806 int buflen = where != NULL ? *sizep : 0; 807 int doingzomb; 808 struct eproc eproc; 809 int error = 0; 810 811 if (namelen != 2 && !(namelen == 1 && 812 (name[0] == KERN_PROC_ALL || name[0] == KERN_PROC_KTHREAD))) 813 return (EINVAL); 814 p = LIST_FIRST(&allproc); 815 doingzomb = 0; 816 again: 817 for (; p != 0; p = LIST_NEXT(p, p_list)) { 818 /* 819 * Skip embryonic processes. 820 */ 821 if (p->p_stat == SIDL) 822 continue; 823 /* 824 * TODO - make more efficient (see notes below). 825 * do by session. 826 */ 827 switch (name[0]) { 828 829 case KERN_PROC_PID: 830 /* could do this with just a lookup */ 831 if (p->p_pid != (pid_t)name[1]) 832 continue; 833 break; 834 835 case KERN_PROC_PGRP: 836 /* could do this by traversing pgrp */ 837 if (p->p_pgrp->pg_id != (pid_t)name[1]) 838 continue; 839 break; 840 841 case KERN_PROC_TTY: 842 if ((p->p_flag & P_CONTROLT) == 0 || 843 p->p_session->s_ttyp == NULL || 844 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 845 continue; 846 break; 847 848 case KERN_PROC_UID: 849 if (p->p_ucred->cr_uid != (uid_t)name[1]) 850 continue; 851 break; 852 853 case KERN_PROC_RUID: 854 if (p->p_cred->p_ruid != (uid_t)name[1]) 855 continue; 856 break; 857 858 case KERN_PROC_ALL: 859 if (p->p_flag & P_SYSTEM) 860 continue; 861 break; 862 } 863 if (buflen >= sizeof(struct kinfo_proc)) { 864 fill_eproc(p, &eproc); 865 error = copyout((caddr_t)p, &dp->kp_proc, 866 sizeof(struct proc)); 867 if (error) 868 return (error); 869 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 870 sizeof(eproc)); 871 if (error) 872 return (error); 873 dp++; 874 buflen -= sizeof(struct kinfo_proc); 875 } 876 needed += sizeof(struct kinfo_proc); 877 } 878 if (doingzomb == 0) { 879 p = LIST_FIRST(&zombproc); 880 doingzomb++; 881 goto again; 882 } 883 if (where != NULL) { 884 *sizep = (caddr_t)dp - where; 885 if (needed > *sizep) 886 return (ENOMEM); 887 } else { 888 needed += KERN_PROCSLOP; 889 *sizep = needed; 890 } 891 return (0); 892 } 893 894 /* 895 * Fill in an eproc structure for the specified process. 896 */ 897 void 898 fill_eproc(p, ep) 899 register struct proc *p; 900 register struct eproc *ep; 901 { 902 register struct tty *tp; 903 904 ep->e_paddr = p; 905 ep->e_sess = p->p_pgrp->pg_session; 906 ep->e_pcred = *p->p_cred; 907 ep->e_ucred = *p->p_ucred; 908 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 909 ep->e_vm.vm_rssize = 0; 910 ep->e_vm.vm_tsize = 0; 911 ep->e_vm.vm_dsize = 0; 912 ep->e_vm.vm_ssize = 0; 913 } else { 914 register struct vmspace *vm = p->p_vmspace; 915 916 ep->e_vm.vm_rssize = vm_resident_count(vm); 917 ep->e_vm.vm_tsize = vm->vm_tsize; 918 ep->e_vm.vm_dsize = vm->vm_dsize; 919 ep->e_vm.vm_ssize = vm->vm_ssize; 920 } 921 if (p->p_pptr) 922 ep->e_ppid = p->p_pptr->p_pid; 923 else 924 ep->e_ppid = 0; 925 ep->e_pgid = p->p_pgrp->pg_id; 926 ep->e_jobc = p->p_pgrp->pg_jobc; 927 if ((p->p_flag & P_CONTROLT) && 928 (tp = ep->e_sess->s_ttyp)) { 929 ep->e_tdev = tp->t_dev; 930 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 931 ep->e_tsess = tp->t_session; 932 } else 933 ep->e_tdev = NODEV; 934 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 935 if (SESS_LEADER(p)) 936 ep->e_flag |= EPROC_SLEADER; 937 strncpy(ep->e_wmesg, p->p_wmesg ? p->p_wmesg : "", WMESGLEN); 938 ep->e_wmesg[WMESGLEN] = '\0'; 939 ep->e_xsize = ep->e_xrssize = 0; 940 ep->e_xccount = ep->e_xswrss = 0; 941 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME-1); 942 ep->e_login[MAXLOGNAME-1] = '\0'; 943 strncpy(ep->e_emul, p->p_emul->e_name, EMULNAMELEN); 944 ep->e_emul[EMULNAMELEN] = '\0'; 945 ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0; 946 } 947 948 /* 949 * Initialize disknames/diskstats for export by sysctl. If update is set, 950 * then we simply update the disk statistics information. 951 */ 952 int 953 sysctl_diskinit(update, p) 954 int update; 955 struct proc *p; 956 { 957 struct diskstats *sdk; 958 struct disk *dk; 959 int i, tlen, l; 960 961 if ((i = lockmgr(&sysctl_disklock, LK_EXCLUSIVE, NULL, p)) != 0) 962 return i; 963 964 if (disk_change) { 965 for (dk = TAILQ_FIRST(&disklist), tlen = 0; dk; 966 dk = TAILQ_NEXT(dk, dk_link)) 967 tlen += strlen(dk->dk_name) + 1; 968 tlen++; 969 970 if (disknames) 971 free(disknames, M_SYSCTL); 972 if (diskstats) 973 free(diskstats, M_SYSCTL); 974 diskstats = NULL; 975 disknames = NULL; 976 diskstats = malloc(disk_count * sizeof(struct diskstats), 977 M_SYSCTL, M_WAITOK); 978 disknames = malloc(tlen, M_SYSCTL, M_WAITOK); 979 disknames[0] = '\0'; 980 981 for (dk = TAILQ_FIRST(&disklist), i = 0, l = 0; dk; 982 dk = TAILQ_NEXT(dk, dk_link), i++) { 983 l += sprintf(disknames + l, "%s,", 984 dk->dk_name ? dk->dk_name : ""); 985 sdk = diskstats + i; 986 sdk->ds_busy = dk->dk_busy; 987 sdk->ds_xfer = dk->dk_xfer; 988 sdk->ds_seek = dk->dk_seek; 989 sdk->ds_bytes = dk->dk_bytes; 990 sdk->ds_attachtime = dk->dk_attachtime; 991 sdk->ds_timestamp = dk->dk_timestamp; 992 sdk->ds_time = dk->dk_time; 993 } 994 995 /* Eliminate trailing comma */ 996 if (l != 0) 997 disknames[l - 1] = '\0'; 998 disk_change = 0; 999 } else if (update) { 1000 /* Just update, number of drives hasn't changed */ 1001 for (dk = TAILQ_FIRST(&disklist), i = 0; dk; 1002 dk = TAILQ_NEXT(dk, dk_link), i++) { 1003 sdk = diskstats + i; 1004 sdk->ds_busy = dk->dk_busy; 1005 sdk->ds_xfer = dk->dk_xfer; 1006 sdk->ds_seek = dk->dk_seek; 1007 sdk->ds_bytes = dk->dk_bytes; 1008 sdk->ds_attachtime = dk->dk_attachtime; 1009 sdk->ds_timestamp = dk->dk_timestamp; 1010 sdk->ds_time = dk->dk_time; 1011 } 1012 } 1013 lockmgr(&sysctl_disklock, LK_RELEASE, NULL, p); 1014 return 0; 1015 } 1016