1 /* $OpenBSD: kern_sysctl.c,v 1.57 2001/09/07 22:03:21 angelos 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, oldsgap; 234 extern char ostype[], osrelease[], osversion[], version[]; 235 extern int somaxconn, sominconn; 236 extern int usermount, nosuidcoredump; 237 extern long cp_time[CPUSTATES]; 238 extern int stackgap_random; 239 240 /* all sysctl names at this level are terminal */ 241 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF || 242 name[0] == KERN_MALLOCSTATS || name[0] == KERN_TTY || 243 name[0] == KERN_POOL)) 244 return (ENOTDIR); /* overloaded */ 245 246 switch (name[0]) { 247 case KERN_OSTYPE: 248 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 249 case KERN_OSRELEASE: 250 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 251 case KERN_OSREV: 252 return (sysctl_rdint(oldp, oldlenp, newp, OpenBSD)); 253 case KERN_OSVERSION: 254 return (sysctl_rdstring(oldp, oldlenp, newp, osversion)); 255 case KERN_VERSION: 256 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 257 case KERN_MAXVNODES: 258 return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 259 case KERN_MAXPROC: 260 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 261 case KERN_MAXFILES: 262 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 263 case KERN_ARGMAX: 264 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 265 case KERN_NSELCOLL: 266 return (sysctl_rdint(oldp, oldlenp, newp, nselcoll)); 267 case KERN_SECURELVL: 268 level = securelevel; 269 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 270 newp == NULL) 271 return (error); 272 if ((securelevel > 0 || level < -1) 273 && level < securelevel && p->p_pid != 1) 274 return (EPERM); 275 securelevel = level; 276 return (0); 277 case KERN_HOSTNAME: 278 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 279 hostname, sizeof(hostname)); 280 if (newp && !error) 281 hostnamelen = newlen; 282 return (error); 283 case KERN_DOMAINNAME: 284 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 285 domainname, sizeof(domainname)); 286 if (newp && !error) 287 domainnamelen = newlen; 288 return (error); 289 case KERN_HOSTID: 290 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 291 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 292 hostid = inthostid; 293 return (error); 294 case KERN_CLOCKRATE: 295 return (sysctl_clockrate(oldp, oldlenp)); 296 case KERN_BOOTTIME: 297 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 298 sizeof(struct timeval))); 299 case KERN_VNODE: 300 return (sysctl_vnode(oldp, oldlenp, p)); 301 case KERN_PROC: 302 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 303 case KERN_FILE: 304 return (sysctl_file(oldp, oldlenp)); 305 #ifdef GPROF 306 case KERN_PROF: 307 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 308 newp, newlen)); 309 #endif 310 case KERN_POSIX1: 311 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 312 case KERN_NGROUPS: 313 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 314 case KERN_JOB_CONTROL: 315 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 316 case KERN_SAVED_IDS: 317 #ifdef _POSIX_SAVED_IDS 318 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 319 #else 320 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 321 #endif 322 case KERN_MAXPARTITIONS: 323 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 324 case KERN_RAWPARTITION: 325 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 326 case KERN_NTPTIME: 327 return (sysctl_ntptime(oldp, oldlenp)); 328 case KERN_SOMAXCONN: 329 return (sysctl_int(oldp, oldlenp, newp, newlen, &somaxconn)); 330 case KERN_SOMINCONN: 331 return (sysctl_int(oldp, oldlenp, newp, newlen, &sominconn)); 332 case KERN_USERMOUNT: 333 return (sysctl_int(oldp, oldlenp, newp, newlen, &usermount)); 334 case KERN_RND: 335 return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats, 336 sizeof(rndstats))); 337 case KERN_ARND: 338 return (sysctl_rdint(oldp, oldlenp, newp, arc4random())); 339 case KERN_NOSUIDCOREDUMP: 340 return (sysctl_int(oldp, oldlenp, newp, newlen, &nosuidcoredump)); 341 case KERN_FSYNC: 342 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 343 case KERN_SYSVMSG: 344 #ifdef SYSVMSG 345 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 346 #else 347 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 348 #endif 349 case KERN_SYSVSEM: 350 #ifdef SYSVSEM 351 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 352 #else 353 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 354 #endif 355 case KERN_SYSVSHM: 356 #ifdef SYSVSHM 357 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 358 #else 359 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 360 #endif 361 case KERN_MSGBUFSIZE: 362 /* 363 * deal with cases where the message buffer has 364 * become corrupted. 365 */ 366 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 367 return (ENXIO); 368 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 369 case KERN_MSGBUF: 370 /* see note above */ 371 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 372 return (ENXIO); 373 return (sysctl_rdstruct(oldp, oldlenp, newp, msgbufp, 374 msgbufp->msg_bufs + offsetof(struct msgbuf, msg_bufc))); 375 case KERN_MALLOCSTATS: 376 return (sysctl_malloc(name + 1, namelen - 1, oldp, oldlenp, 377 newp, newlen, p)); 378 case KERN_CPTIME: 379 return (sysctl_rdstruct(oldp, oldlenp, newp, &cp_time, 380 sizeof(cp_time))); 381 case KERN_NCHSTATS: 382 return (sysctl_rdstruct(oldp, oldlenp, newp, &nchstats, 383 sizeof(struct nchstats))); 384 case KERN_FORKSTAT: 385 return (sysctl_rdstruct(oldp, oldlenp, newp, &forkstat, 386 sizeof(struct forkstat))); 387 case KERN_TTY: 388 return (sysctl_tty(name + 1, namelen - 1, oldp, oldlenp, 389 newp, newlen)); 390 case KERN_FSCALE: 391 return (sysctl_rdint(oldp, oldlenp, newp, fscale)); 392 case KERN_CCPU: 393 return (sysctl_rdint(oldp, oldlenp, newp, ccpu)); 394 case KERN_NPROCS: 395 return (sysctl_rdint(oldp, oldlenp, newp, nprocs)); 396 case KERN_POOL: 397 return (sysctl_dopool(name + 1, namelen - 1, oldp, oldlenp)); 398 case KERN_STACKGAPRANDOM: 399 oldsgap = stackgap_random; 400 401 error = sysctl_int(oldp, oldlenp, newp, newlen, &stackgap_random); 402 /* 403 * Safety harness. 404 */ 405 if ((stackgap_random < ALIGNBYTES && stackgap_random != 0) || 406 !powerof2(stackgap_random) || 407 stackgap_random > PAGE_SIZE * 2) { 408 stackgap_random = oldsgap; 409 return (EINVAL); 410 } 411 return (error); 412 default: 413 return (EOPNOTSUPP); 414 } 415 /* NOTREACHED */ 416 } 417 418 /* 419 * hardware related system variables. 420 */ 421 int 422 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 423 int *name; 424 u_int namelen; 425 void *oldp; 426 size_t *oldlenp; 427 void *newp; 428 size_t newlen; 429 struct proc *p; 430 { 431 extern char machine[], cpu_model[]; 432 int err; 433 434 /* all sysctl names at this level are terminal */ 435 if (namelen != 1) 436 return (ENOTDIR); /* overloaded */ 437 438 switch (name[0]) { 439 case HW_MACHINE: 440 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 441 case HW_MODEL: 442 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 443 case HW_NCPU: 444 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 445 case HW_BYTEORDER: 446 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 447 case HW_PHYSMEM: 448 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 449 case HW_USERMEM: 450 return (sysctl_rdint(oldp, oldlenp, newp, 451 ctob(physmem - uvmexp.wired))); 452 case HW_PAGESIZE: 453 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 454 case HW_DISKNAMES: 455 err = sysctl_diskinit(0, p); 456 if (err) 457 return err; 458 if (disknames) 459 return (sysctl_rdstring(oldp, oldlenp, newp, 460 disknames)); 461 else 462 return (sysctl_rdstring(oldp, oldlenp, newp, "")); 463 case HW_DISKSTATS: 464 err = sysctl_diskinit(1, p); 465 if (err) 466 return err; 467 return (sysctl_rdstruct(oldp, oldlenp, newp, diskstats, 468 disk_count * sizeof(struct diskstats))); 469 case HW_DISKCOUNT: 470 return (sysctl_rdint(oldp, oldlenp, newp, disk_count)); 471 default: 472 return (EOPNOTSUPP); 473 } 474 /* NOTREACHED */ 475 } 476 477 #ifdef DEBUG 478 /* 479 * Debugging related system variables. 480 */ 481 struct ctldebug debug0, debug1, debug2, debug3, debug4; 482 struct ctldebug debug5, debug6, debug7, debug8, debug9; 483 struct ctldebug debug10, debug11, debug12, debug13, debug14; 484 struct ctldebug debug15, debug16, debug17, debug18, debug19; 485 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 486 &debug0, &debug1, &debug2, &debug3, &debug4, 487 &debug5, &debug6, &debug7, &debug8, &debug9, 488 &debug10, &debug11, &debug12, &debug13, &debug14, 489 &debug15, &debug16, &debug17, &debug18, &debug19, 490 }; 491 int 492 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 493 int *name; 494 u_int namelen; 495 void *oldp; 496 size_t *oldlenp; 497 void *newp; 498 size_t newlen; 499 struct proc *p; 500 { 501 struct ctldebug *cdp; 502 503 /* all sysctl names at this level are name and field */ 504 if (namelen != 2) 505 return (ENOTDIR); /* overloaded */ 506 cdp = debugvars[name[0]]; 507 if (cdp->debugname == 0) 508 return (EOPNOTSUPP); 509 switch (name[1]) { 510 case CTL_DEBUG_NAME: 511 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 512 case CTL_DEBUG_VALUE: 513 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 514 default: 515 return (EOPNOTSUPP); 516 } 517 /* NOTREACHED */ 518 } 519 #endif /* DEBUG */ 520 521 /* 522 * Validate parameters and get old / set new parameters 523 * for an integer-valued sysctl function. 524 */ 525 int 526 sysctl_int(oldp, oldlenp, newp, newlen, valp) 527 void *oldp; 528 size_t *oldlenp; 529 void *newp; 530 size_t newlen; 531 int *valp; 532 { 533 int error = 0; 534 535 if (oldp && *oldlenp < sizeof(int)) 536 return (ENOMEM); 537 if (newp && newlen != sizeof(int)) 538 return (EINVAL); 539 *oldlenp = sizeof(int); 540 if (oldp) 541 error = copyout(valp, oldp, sizeof(int)); 542 if (error == 0 && newp) 543 error = copyin(newp, valp, sizeof(int)); 544 return (error); 545 } 546 547 /* 548 * As above, but read-only. 549 */ 550 int 551 sysctl_rdint(oldp, oldlenp, newp, val) 552 void *oldp; 553 size_t *oldlenp; 554 void *newp; 555 int val; 556 { 557 int error = 0; 558 559 if (oldp && *oldlenp < sizeof(int)) 560 return (ENOMEM); 561 if (newp) 562 return (EPERM); 563 *oldlenp = sizeof(int); 564 if (oldp) 565 error = copyout((caddr_t)&val, oldp, sizeof(int)); 566 return (error); 567 } 568 569 /* 570 * Validate parameters and get old / set new parameters 571 * for an integer-valued sysctl function. 572 */ 573 int 574 sysctl_quad(oldp, oldlenp, newp, newlen, valp) 575 void *oldp; 576 size_t *oldlenp; 577 void *newp; 578 size_t newlen; 579 int64_t *valp; 580 { 581 int error = 0; 582 583 if (oldp && *oldlenp < sizeof(int64_t)) 584 return (ENOMEM); 585 if (newp && newlen != sizeof(int64_t)) 586 return (EINVAL); 587 *oldlenp = sizeof(int64_t); 588 if (oldp) 589 error = copyout(valp, oldp, sizeof(int64_t)); 590 if (error == 0 && newp) 591 error = copyin(newp, valp, sizeof(int64_t)); 592 return (error); 593 } 594 595 /* 596 * As above, but read-only. 597 */ 598 int 599 sysctl_rdquad(oldp, oldlenp, newp, val) 600 void *oldp; 601 size_t *oldlenp; 602 void *newp; 603 int64_t val; 604 { 605 int error = 0; 606 607 if (oldp && *oldlenp < sizeof(int64_t)) 608 return (ENOMEM); 609 if (newp) 610 return (EPERM); 611 *oldlenp = sizeof(int64_t); 612 if (oldp) 613 error = copyout((caddr_t)&val, oldp, sizeof(int64_t)); 614 return (error); 615 } 616 617 /* 618 * Validate parameters and get old / set new parameters 619 * for a string-valued sysctl function. 620 */ 621 int 622 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 623 void *oldp; 624 size_t *oldlenp; 625 void *newp; 626 size_t newlen; 627 char *str; 628 int maxlen; 629 { 630 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 0); 631 } 632 633 int 634 sysctl_tstring(oldp, oldlenp, newp, newlen, str, maxlen) 635 void *oldp; 636 size_t *oldlenp; 637 void *newp; 638 size_t newlen; 639 char *str; 640 int maxlen; 641 { 642 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1); 643 } 644 645 int 646 sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, trunc) 647 void *oldp; 648 size_t *oldlenp; 649 void *newp; 650 size_t newlen; 651 char *str; 652 int maxlen; 653 int trunc; 654 { 655 int len, error = 0; 656 char c; 657 658 len = strlen(str) + 1; 659 if (oldp && *oldlenp < len) { 660 if (trunc == 0 || *oldlenp == 0) 661 return (ENOMEM); 662 } 663 if (newp && newlen >= maxlen) 664 return (EINVAL); 665 if (oldp) { 666 if (trunc && *oldlenp < len) { 667 /* save & zap NUL terminator while copying */ 668 c = str[*oldlenp-1]; 669 str[*oldlenp-1] = '\0'; 670 error = copyout(str, oldp, *oldlenp); 671 str[*oldlenp-1] = c; 672 } else { 673 *oldlenp = len; 674 error = copyout(str, oldp, len); 675 } 676 } 677 if (error == 0 && newp) { 678 error = copyin(newp, str, newlen); 679 str[newlen] = 0; 680 } 681 return (error); 682 } 683 684 /* 685 * As above, but read-only. 686 */ 687 int 688 sysctl_rdstring(oldp, oldlenp, newp, str) 689 void *oldp; 690 size_t *oldlenp; 691 void *newp; 692 char *str; 693 { 694 int len, error = 0; 695 696 len = strlen(str) + 1; 697 if (oldp && *oldlenp < len) 698 return (ENOMEM); 699 if (newp) 700 return (EPERM); 701 *oldlenp = len; 702 if (oldp) 703 error = copyout(str, oldp, len); 704 return (error); 705 } 706 707 /* 708 * Validate parameters and get old / set new parameters 709 * for a structure oriented sysctl function. 710 */ 711 int 712 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 713 void *oldp; 714 size_t *oldlenp; 715 void *newp; 716 size_t newlen; 717 void *sp; 718 int len; 719 { 720 int error = 0; 721 722 if (oldp && *oldlenp < len) 723 return (ENOMEM); 724 if (newp && newlen > len) 725 return (EINVAL); 726 if (oldp) { 727 *oldlenp = len; 728 error = copyout(sp, oldp, len); 729 } 730 if (error == 0 && newp) 731 error = copyin(newp, sp, len); 732 return (error); 733 } 734 735 /* 736 * Validate parameters and get old parameters 737 * for a structure oriented sysctl function. 738 */ 739 int 740 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 741 void *oldp; 742 size_t *oldlenp; 743 void *newp, *sp; 744 int len; 745 { 746 int error = 0; 747 748 if (oldp && *oldlenp < len) 749 return (ENOMEM); 750 if (newp) 751 return (EPERM); 752 *oldlenp = len; 753 if (oldp) 754 error = copyout(sp, oldp, len); 755 return (error); 756 } 757 758 /* 759 * Get file structures. 760 */ 761 int 762 sysctl_file(where, sizep) 763 char *where; 764 size_t *sizep; 765 { 766 int buflen, error; 767 struct file *fp; 768 char *start = where; 769 770 buflen = *sizep; 771 if (where == NULL) { 772 /* 773 * overestimate by 10 files 774 */ 775 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 776 return (0); 777 } 778 779 /* 780 * first copyout filehead 781 */ 782 if (buflen < sizeof(filehead)) { 783 *sizep = 0; 784 return (0); 785 } 786 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 787 if (error) 788 return (error); 789 buflen -= sizeof(filehead); 790 where += sizeof(filehead); 791 792 /* 793 * followed by an array of file structures 794 */ 795 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 796 if (buflen < sizeof(struct file)) { 797 *sizep = where - start; 798 return (ENOMEM); 799 } 800 error = copyout((caddr_t)fp, where, sizeof (struct file)); 801 if (error) 802 return (error); 803 buflen -= sizeof(struct file); 804 where += sizeof(struct file); 805 } 806 *sizep = where - start; 807 return (0); 808 } 809 810 /* 811 * try over estimating by 5 procs 812 */ 813 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 814 815 int 816 sysctl_doproc(name, namelen, where, sizep) 817 int *name; 818 u_int namelen; 819 char *where; 820 size_t *sizep; 821 { 822 register struct proc *p; 823 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 824 register int needed = 0; 825 int buflen = where != NULL ? *sizep : 0; 826 int doingzomb; 827 struct eproc eproc; 828 int error = 0; 829 830 if (namelen != 2 && !(namelen == 1 && 831 (name[0] == KERN_PROC_ALL || name[0] == KERN_PROC_KTHREAD))) 832 return (EINVAL); 833 p = LIST_FIRST(&allproc); 834 doingzomb = 0; 835 again: 836 for (; p != 0; p = LIST_NEXT(p, p_list)) { 837 /* 838 * Skip embryonic processes. 839 */ 840 if (p->p_stat == SIDL) 841 continue; 842 /* 843 * TODO - make more efficient (see notes below). 844 * do by session. 845 */ 846 switch (name[0]) { 847 848 case KERN_PROC_PID: 849 /* could do this with just a lookup */ 850 if (p->p_pid != (pid_t)name[1]) 851 continue; 852 break; 853 854 case KERN_PROC_PGRP: 855 /* could do this by traversing pgrp */ 856 if (p->p_pgrp->pg_id != (pid_t)name[1]) 857 continue; 858 break; 859 860 case KERN_PROC_TTY: 861 if ((p->p_flag & P_CONTROLT) == 0 || 862 p->p_session->s_ttyp == NULL || 863 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 864 continue; 865 break; 866 867 case KERN_PROC_UID: 868 if (p->p_ucred->cr_uid != (uid_t)name[1]) 869 continue; 870 break; 871 872 case KERN_PROC_RUID: 873 if (p->p_cred->p_ruid != (uid_t)name[1]) 874 continue; 875 break; 876 877 case KERN_PROC_ALL: 878 if (p->p_flag & P_SYSTEM) 879 continue; 880 break; 881 } 882 if (buflen >= sizeof(struct kinfo_proc)) { 883 fill_eproc(p, &eproc); 884 error = copyout((caddr_t)p, &dp->kp_proc, 885 sizeof(struct proc)); 886 if (error) 887 return (error); 888 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 889 sizeof(eproc)); 890 if (error) 891 return (error); 892 dp++; 893 buflen -= sizeof(struct kinfo_proc); 894 } 895 needed += sizeof(struct kinfo_proc); 896 } 897 if (doingzomb == 0) { 898 p = LIST_FIRST(&zombproc); 899 doingzomb++; 900 goto again; 901 } 902 if (where != NULL) { 903 *sizep = (caddr_t)dp - where; 904 if (needed > *sizep) 905 return (ENOMEM); 906 } else { 907 needed += KERN_PROCSLOP; 908 *sizep = needed; 909 } 910 return (0); 911 } 912 913 /* 914 * Fill in an eproc structure for the specified process. 915 */ 916 void 917 fill_eproc(p, ep) 918 register struct proc *p; 919 register struct eproc *ep; 920 { 921 register struct tty *tp; 922 923 ep->e_paddr = p; 924 ep->e_sess = p->p_pgrp->pg_session; 925 ep->e_pcred = *p->p_cred; 926 ep->e_ucred = *p->p_ucred; 927 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 928 ep->e_vm.vm_rssize = 0; 929 ep->e_vm.vm_tsize = 0; 930 ep->e_vm.vm_dsize = 0; 931 ep->e_vm.vm_ssize = 0; 932 } else { 933 register struct vmspace *vm = p->p_vmspace; 934 935 ep->e_vm.vm_rssize = vm_resident_count(vm); 936 ep->e_vm.vm_tsize = vm->vm_tsize; 937 ep->e_vm.vm_dsize = vm->vm_dsize; 938 ep->e_vm.vm_ssize = vm->vm_ssize; 939 } 940 if (p->p_pptr) 941 ep->e_ppid = p->p_pptr->p_pid; 942 else 943 ep->e_ppid = 0; 944 ep->e_pgid = p->p_pgrp->pg_id; 945 ep->e_jobc = p->p_pgrp->pg_jobc; 946 if ((p->p_flag & P_CONTROLT) && 947 (tp = ep->e_sess->s_ttyp)) { 948 ep->e_tdev = tp->t_dev; 949 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 950 ep->e_tsess = tp->t_session; 951 } else 952 ep->e_tdev = NODEV; 953 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 954 if (SESS_LEADER(p)) 955 ep->e_flag |= EPROC_SLEADER; 956 strncpy(ep->e_wmesg, p->p_wmesg ? p->p_wmesg : "", WMESGLEN); 957 ep->e_wmesg[WMESGLEN] = '\0'; 958 ep->e_xsize = ep->e_xrssize = 0; 959 ep->e_xccount = ep->e_xswrss = 0; 960 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME-1); 961 ep->e_login[MAXLOGNAME-1] = '\0'; 962 strncpy(ep->e_emul, p->p_emul->e_name, EMULNAMELEN); 963 ep->e_emul[EMULNAMELEN] = '\0'; 964 ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0; 965 } 966 967 /* 968 * Initialize disknames/diskstats for export by sysctl. If update is set, 969 * then we simply update the disk statistics information. 970 */ 971 int 972 sysctl_diskinit(update, p) 973 int update; 974 struct proc *p; 975 { 976 struct diskstats *sdk; 977 struct disk *dk; 978 int i, tlen, l; 979 980 if ((i = lockmgr(&sysctl_disklock, LK_EXCLUSIVE, NULL, p)) != 0) 981 return i; 982 983 if (disk_change) { 984 for (dk = TAILQ_FIRST(&disklist), tlen = 0; dk; 985 dk = TAILQ_NEXT(dk, dk_link)) 986 tlen += strlen(dk->dk_name) + 1; 987 tlen++; 988 989 if (disknames) 990 free(disknames, M_SYSCTL); 991 if (diskstats) 992 free(diskstats, M_SYSCTL); 993 diskstats = NULL; 994 disknames = NULL; 995 diskstats = malloc(disk_count * sizeof(struct diskstats), 996 M_SYSCTL, M_WAITOK); 997 disknames = malloc(tlen, M_SYSCTL, M_WAITOK); 998 disknames[0] = '\0'; 999 1000 for (dk = TAILQ_FIRST(&disklist), i = 0, l = 0; dk; 1001 dk = TAILQ_NEXT(dk, dk_link), i++) { 1002 l += sprintf(disknames + l, "%s,", 1003 dk->dk_name ? dk->dk_name : ""); 1004 sdk = diskstats + i; 1005 sdk->ds_busy = dk->dk_busy; 1006 sdk->ds_xfer = dk->dk_xfer; 1007 sdk->ds_seek = dk->dk_seek; 1008 sdk->ds_bytes = dk->dk_bytes; 1009 sdk->ds_attachtime = dk->dk_attachtime; 1010 sdk->ds_timestamp = dk->dk_timestamp; 1011 sdk->ds_time = dk->dk_time; 1012 } 1013 1014 /* Eliminate trailing comma */ 1015 if (l != 0) 1016 disknames[l - 1] = '\0'; 1017 disk_change = 0; 1018 } else if (update) { 1019 /* Just update, number of drives hasn't changed */ 1020 for (dk = TAILQ_FIRST(&disklist), i = 0; dk; 1021 dk = TAILQ_NEXT(dk, dk_link), i++) { 1022 sdk = diskstats + i; 1023 sdk->ds_busy = dk->dk_busy; 1024 sdk->ds_xfer = dk->dk_xfer; 1025 sdk->ds_seek = dk->dk_seek; 1026 sdk->ds_bytes = dk->dk_bytes; 1027 sdk->ds_attachtime = dk->dk_attachtime; 1028 sdk->ds_timestamp = dk->dk_timestamp; 1029 sdk->ds_time = dk->dk_time; 1030 } 1031 } 1032 lockmgr(&sysctl_disklock, LK_RELEASE, NULL, p); 1033 return 0; 1034 } 1035