1 /* $OpenBSD: kern_sysctl.c,v 1.60 2001/11/28 13:47:39 art 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 <uvm/uvm_extern.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 <sys/mount.h> 68 #include <sys/syscallargs.h> 69 #include <dev/rndvar.h> 70 71 #ifdef DDB 72 #include <ddb/db_var.h> 73 #endif 74 75 #ifdef SYSVMSG 76 #include <sys/msg.h> 77 #endif 78 #ifdef SYSVSEM 79 #include <sys/sem.h> 80 #endif 81 #ifdef SYSVSHM 82 #include <sys/shm.h> 83 #endif 84 85 extern struct forkstat forkstat; 86 extern struct nchstats nchstats; 87 extern int nselcoll, fscale; 88 extern struct disklist_head disklist; 89 extern fixpt_t ccpu; 90 91 int sysctl_diskinit(int, struct proc *); 92 93 /* 94 * Lock to avoid too many processes vslocking a large amount of memory 95 * at the same time. 96 */ 97 struct lock sysctl_lock, sysctl_disklock; 98 99 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES) 100 struct lock sysctl_kmemlock; 101 #endif 102 103 void 104 sysctl_init() 105 { 106 lockinit(&sysctl_lock, PLOCK|PCATCH, "sysctl", 0, 0); 107 lockinit(&sysctl_disklock, PLOCK|PCATCH, "sysctl_disklock", 0, 0); 108 109 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES) 110 lockinit(&sysctl_kmemlock, PLOCK|PCATCH, "sysctl_kmemlock", 0, 0); 111 #endif 112 } 113 114 int 115 sys___sysctl(p, v, retval) 116 struct proc *p; 117 void *v; 118 register_t *retval; 119 { 120 register struct sys___sysctl_args /* { 121 syscallarg(int *) name; 122 syscallarg(u_int) namelen; 123 syscallarg(void *) old; 124 syscallarg(size_t *) oldlenp; 125 syscallarg(void *) new; 126 syscallarg(size_t) newlen; 127 } */ *uap = v; 128 int error, dolock = 1; 129 size_t savelen = 0, oldlen = 0; 130 sysctlfn *fn; 131 int name[CTL_MAXNAME]; 132 133 if (SCARG(uap, new) != NULL && 134 (error = suser(p->p_ucred, &p->p_acflag))) 135 return (error); 136 /* 137 * all top-level sysctl names are non-terminal 138 */ 139 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2) 140 return (EINVAL); 141 error = copyin(SCARG(uap, name), &name, 142 SCARG(uap, namelen) * sizeof(int)); 143 if (error) 144 return (error); 145 146 switch (name[0]) { 147 case CTL_KERN: 148 fn = kern_sysctl; 149 if (name[2] == KERN_VNODE) /* XXX */ 150 dolock = 0; 151 break; 152 case CTL_HW: 153 fn = hw_sysctl; 154 break; 155 case CTL_VM: 156 fn = uvm_sysctl; 157 break; 158 case CTL_NET: 159 fn = net_sysctl; 160 break; 161 case CTL_FS: 162 fn = fs_sysctl; 163 break; 164 case CTL_VFS: 165 fn = vfs_sysctl; 166 break; 167 case CTL_MACHDEP: 168 fn = cpu_sysctl; 169 break; 170 #ifdef DEBUG 171 case CTL_DEBUG: 172 fn = debug_sysctl; 173 break; 174 #endif 175 #ifdef DDB 176 case CTL_DDB: 177 fn = ddb_sysctl; 178 break; 179 #endif 180 default: 181 return (EOPNOTSUPP); 182 } 183 184 if (SCARG(uap, oldlenp) && 185 (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen)))) 186 return (error); 187 if (SCARG(uap, old) != NULL) { 188 if ((error = lockmgr(&sysctl_lock, LK_EXCLUSIVE, NULL, p)) != 0) 189 return (error); 190 if (dolock) { 191 error = uvm_vslock(p, SCARG(uap, old), oldlen, 192 VM_PROT_READ|VM_PROT_WRITE); 193 if (error) { 194 lockmgr(&sysctl_lock, LK_RELEASE, NULL, p); 195 return (error); 196 } 197 } 198 savelen = oldlen; 199 } 200 error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old), 201 &oldlen, SCARG(uap, new), SCARG(uap, newlen), p); 202 if (SCARG(uap, old) != NULL) { 203 if (dolock) 204 uvm_vsunlock(p, SCARG(uap, old), savelen); 205 lockmgr(&sysctl_lock, LK_RELEASE, NULL, p); 206 } 207 if (error) 208 return (error); 209 if (SCARG(uap, oldlenp)) 210 error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen)); 211 return (error); 212 } 213 214 /* 215 * Attributes stored in the kernel. 216 */ 217 char hostname[MAXHOSTNAMELEN]; 218 int hostnamelen; 219 char domainname[MAXHOSTNAMELEN]; 220 int domainnamelen; 221 long hostid; 222 char *disknames = NULL; 223 struct diskstats *diskstats = NULL; 224 #ifdef INSECURE 225 int securelevel = -1; 226 #else 227 int securelevel; 228 #endif 229 230 /* 231 * kernel related system variables. 232 */ 233 int 234 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 235 int *name; 236 u_int namelen; 237 void *oldp; 238 size_t *oldlenp; 239 void *newp; 240 size_t newlen; 241 struct proc *p; 242 { 243 int error, level, inthostid, oldsgap; 244 extern char ostype[], osrelease[], osversion[], version[]; 245 extern int somaxconn, sominconn; 246 extern int usermount, nosuidcoredump; 247 extern long cp_time[CPUSTATES]; 248 extern int stackgap_random; 249 250 /* all sysctl names at this level are terminal */ 251 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF || 252 name[0] == KERN_MALLOCSTATS || name[0] == KERN_TTY || 253 name[0] == KERN_POOL || name[0] == KERN_SYSVIPC_INFO)) 254 return (ENOTDIR); /* overloaded */ 255 256 switch (name[0]) { 257 case KERN_OSTYPE: 258 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 259 case KERN_OSRELEASE: 260 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 261 case KERN_OSREV: 262 return (sysctl_rdint(oldp, oldlenp, newp, OpenBSD)); 263 case KERN_OSVERSION: 264 return (sysctl_rdstring(oldp, oldlenp, newp, osversion)); 265 case KERN_VERSION: 266 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 267 case KERN_MAXVNODES: 268 return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 269 case KERN_MAXPROC: 270 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 271 case KERN_MAXFILES: 272 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 273 case KERN_ARGMAX: 274 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 275 case KERN_NSELCOLL: 276 return (sysctl_rdint(oldp, oldlenp, newp, nselcoll)); 277 case KERN_SECURELVL: 278 level = securelevel; 279 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 280 newp == NULL) 281 return (error); 282 if ((securelevel > 0 || level < -1) 283 && level < securelevel && p->p_pid != 1) 284 return (EPERM); 285 securelevel = level; 286 return (0); 287 case KERN_HOSTNAME: 288 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 289 hostname, sizeof(hostname)); 290 if (newp && !error) 291 hostnamelen = newlen; 292 return (error); 293 case KERN_DOMAINNAME: 294 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 295 domainname, sizeof(domainname)); 296 if (newp && !error) 297 domainnamelen = newlen; 298 return (error); 299 case KERN_HOSTID: 300 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 301 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 302 hostid = inthostid; 303 return (error); 304 case KERN_CLOCKRATE: 305 return (sysctl_clockrate(oldp, oldlenp)); 306 case KERN_BOOTTIME: 307 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 308 sizeof(struct timeval))); 309 case KERN_VNODE: 310 return (sysctl_vnode(oldp, oldlenp, p)); 311 case KERN_PROC: 312 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 313 case KERN_FILE: 314 return (sysctl_file(oldp, oldlenp)); 315 #ifdef GPROF 316 case KERN_PROF: 317 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 318 newp, newlen)); 319 #endif 320 case KERN_POSIX1: 321 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 322 case KERN_NGROUPS: 323 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 324 case KERN_JOB_CONTROL: 325 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 326 case KERN_SAVED_IDS: 327 #ifdef _POSIX_SAVED_IDS 328 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 329 #else 330 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 331 #endif 332 case KERN_MAXPARTITIONS: 333 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 334 case KERN_RAWPARTITION: 335 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 336 case KERN_NTPTIME: 337 return (sysctl_ntptime(oldp, oldlenp)); 338 case KERN_SOMAXCONN: 339 return (sysctl_int(oldp, oldlenp, newp, newlen, &somaxconn)); 340 case KERN_SOMINCONN: 341 return (sysctl_int(oldp, oldlenp, newp, newlen, &sominconn)); 342 case KERN_USERMOUNT: 343 return (sysctl_int(oldp, oldlenp, newp, newlen, &usermount)); 344 case KERN_RND: 345 return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats, 346 sizeof(rndstats))); 347 case KERN_ARND: 348 return (sysctl_rdint(oldp, oldlenp, newp, arc4random())); 349 case KERN_NOSUIDCOREDUMP: 350 return (sysctl_int(oldp, oldlenp, newp, newlen, &nosuidcoredump)); 351 case KERN_FSYNC: 352 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 353 case KERN_SYSVMSG: 354 #ifdef SYSVMSG 355 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 356 #else 357 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 358 #endif 359 case KERN_SYSVSEM: 360 #ifdef SYSVSEM 361 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 362 #else 363 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 364 #endif 365 case KERN_SYSVSHM: 366 #ifdef SYSVSHM 367 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 368 #else 369 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 370 #endif 371 case KERN_MSGBUFSIZE: 372 /* 373 * deal with cases where the message buffer has 374 * become corrupted. 375 */ 376 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 377 return (ENXIO); 378 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 379 case KERN_MSGBUF: 380 /* see note above */ 381 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 382 return (ENXIO); 383 return (sysctl_rdstruct(oldp, oldlenp, newp, msgbufp, 384 msgbufp->msg_bufs + offsetof(struct msgbuf, msg_bufc))); 385 case KERN_MALLOCSTATS: 386 return (sysctl_malloc(name + 1, namelen - 1, oldp, oldlenp, 387 newp, newlen, p)); 388 case KERN_CPTIME: 389 return (sysctl_rdstruct(oldp, oldlenp, newp, &cp_time, 390 sizeof(cp_time))); 391 case KERN_NCHSTATS: 392 return (sysctl_rdstruct(oldp, oldlenp, newp, &nchstats, 393 sizeof(struct nchstats))); 394 case KERN_FORKSTAT: 395 return (sysctl_rdstruct(oldp, oldlenp, newp, &forkstat, 396 sizeof(struct forkstat))); 397 case KERN_TTY: 398 return (sysctl_tty(name + 1, namelen - 1, oldp, oldlenp, 399 newp, newlen)); 400 case KERN_FSCALE: 401 return (sysctl_rdint(oldp, oldlenp, newp, fscale)); 402 case KERN_CCPU: 403 return (sysctl_rdint(oldp, oldlenp, newp, ccpu)); 404 case KERN_NPROCS: 405 return (sysctl_rdint(oldp, oldlenp, newp, nprocs)); 406 case KERN_POOL: 407 return (sysctl_dopool(name + 1, namelen - 1, oldp, oldlenp)); 408 case KERN_STACKGAPRANDOM: 409 oldsgap = stackgap_random; 410 411 error = sysctl_int(oldp, oldlenp, newp, newlen, &stackgap_random); 412 /* 413 * Safety harness. 414 */ 415 if ((stackgap_random < ALIGNBYTES && stackgap_random != 0) || 416 !powerof2(stackgap_random) || 417 stackgap_random > PAGE_SIZE * 2) { 418 stackgap_random = oldsgap; 419 return (EINVAL); 420 } 421 return (error); 422 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 423 case KERN_SYSVIPC_INFO: 424 return (sysctl_sysvipc(name + 1, namelen - 1, oldp, oldlenp)); 425 #endif 426 default: 427 return (EOPNOTSUPP); 428 } 429 /* NOTREACHED */ 430 } 431 432 /* 433 * hardware related system variables. 434 */ 435 int 436 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 437 int *name; 438 u_int namelen; 439 void *oldp; 440 size_t *oldlenp; 441 void *newp; 442 size_t newlen; 443 struct proc *p; 444 { 445 extern char machine[], cpu_model[]; 446 int err; 447 448 /* all sysctl names at this level are terminal */ 449 if (namelen != 1) 450 return (ENOTDIR); /* overloaded */ 451 452 switch (name[0]) { 453 case HW_MACHINE: 454 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 455 case HW_MODEL: 456 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 457 case HW_NCPU: 458 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 459 case HW_BYTEORDER: 460 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 461 case HW_PHYSMEM: 462 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 463 case HW_USERMEM: 464 return (sysctl_rdint(oldp, oldlenp, newp, 465 ctob(physmem - uvmexp.wired))); 466 case HW_PAGESIZE: 467 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 468 case HW_DISKNAMES: 469 err = sysctl_diskinit(0, p); 470 if (err) 471 return err; 472 if (disknames) 473 return (sysctl_rdstring(oldp, oldlenp, newp, 474 disknames)); 475 else 476 return (sysctl_rdstring(oldp, oldlenp, newp, "")); 477 case HW_DISKSTATS: 478 err = sysctl_diskinit(1, p); 479 if (err) 480 return err; 481 return (sysctl_rdstruct(oldp, oldlenp, newp, diskstats, 482 disk_count * sizeof(struct diskstats))); 483 case HW_DISKCOUNT: 484 return (sysctl_rdint(oldp, oldlenp, newp, disk_count)); 485 default: 486 return (EOPNOTSUPP); 487 } 488 /* NOTREACHED */ 489 } 490 491 #ifdef DEBUG 492 /* 493 * Debugging related system variables. 494 */ 495 struct ctldebug debug0, debug1, debug2, debug3, debug4; 496 struct ctldebug debug5, debug6, debug7, debug8, debug9; 497 struct ctldebug debug10, debug11, debug12, debug13, debug14; 498 struct ctldebug debug15, debug16, debug17, debug18, debug19; 499 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 500 &debug0, &debug1, &debug2, &debug3, &debug4, 501 &debug5, &debug6, &debug7, &debug8, &debug9, 502 &debug10, &debug11, &debug12, &debug13, &debug14, 503 &debug15, &debug16, &debug17, &debug18, &debug19, 504 }; 505 int 506 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 507 int *name; 508 u_int namelen; 509 void *oldp; 510 size_t *oldlenp; 511 void *newp; 512 size_t newlen; 513 struct proc *p; 514 { 515 struct ctldebug *cdp; 516 517 /* all sysctl names at this level are name and field */ 518 if (namelen != 2) 519 return (ENOTDIR); /* overloaded */ 520 cdp = debugvars[name[0]]; 521 if (cdp->debugname == 0) 522 return (EOPNOTSUPP); 523 switch (name[1]) { 524 case CTL_DEBUG_NAME: 525 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 526 case CTL_DEBUG_VALUE: 527 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 528 default: 529 return (EOPNOTSUPP); 530 } 531 /* NOTREACHED */ 532 } 533 #endif /* DEBUG */ 534 535 /* 536 * Validate parameters and get old / set new parameters 537 * for an integer-valued sysctl function. 538 */ 539 int 540 sysctl_int(oldp, oldlenp, newp, newlen, valp) 541 void *oldp; 542 size_t *oldlenp; 543 void *newp; 544 size_t newlen; 545 int *valp; 546 { 547 int error = 0; 548 549 if (oldp && *oldlenp < sizeof(int)) 550 return (ENOMEM); 551 if (newp && newlen != sizeof(int)) 552 return (EINVAL); 553 *oldlenp = sizeof(int); 554 if (oldp) 555 error = copyout(valp, oldp, sizeof(int)); 556 if (error == 0 && newp) 557 error = copyin(newp, valp, sizeof(int)); 558 return (error); 559 } 560 561 /* 562 * As above, but read-only. 563 */ 564 int 565 sysctl_rdint(oldp, oldlenp, newp, val) 566 void *oldp; 567 size_t *oldlenp; 568 void *newp; 569 int val; 570 { 571 int error = 0; 572 573 if (oldp && *oldlenp < sizeof(int)) 574 return (ENOMEM); 575 if (newp) 576 return (EPERM); 577 *oldlenp = sizeof(int); 578 if (oldp) 579 error = copyout((caddr_t)&val, oldp, sizeof(int)); 580 return (error); 581 } 582 583 /* 584 * Validate parameters and get old / set new parameters 585 * for an integer-valued sysctl function. 586 */ 587 int 588 sysctl_quad(oldp, oldlenp, newp, newlen, valp) 589 void *oldp; 590 size_t *oldlenp; 591 void *newp; 592 size_t newlen; 593 int64_t *valp; 594 { 595 int error = 0; 596 597 if (oldp && *oldlenp < sizeof(int64_t)) 598 return (ENOMEM); 599 if (newp && newlen != sizeof(int64_t)) 600 return (EINVAL); 601 *oldlenp = sizeof(int64_t); 602 if (oldp) 603 error = copyout(valp, oldp, sizeof(int64_t)); 604 if (error == 0 && newp) 605 error = copyin(newp, valp, sizeof(int64_t)); 606 return (error); 607 } 608 609 /* 610 * As above, but read-only. 611 */ 612 int 613 sysctl_rdquad(oldp, oldlenp, newp, val) 614 void *oldp; 615 size_t *oldlenp; 616 void *newp; 617 int64_t val; 618 { 619 int error = 0; 620 621 if (oldp && *oldlenp < sizeof(int64_t)) 622 return (ENOMEM); 623 if (newp) 624 return (EPERM); 625 *oldlenp = sizeof(int64_t); 626 if (oldp) 627 error = copyout((caddr_t)&val, oldp, sizeof(int64_t)); 628 return (error); 629 } 630 631 /* 632 * Validate parameters and get old / set new parameters 633 * for a string-valued sysctl function. 634 */ 635 int 636 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 637 void *oldp; 638 size_t *oldlenp; 639 void *newp; 640 size_t newlen; 641 char *str; 642 int maxlen; 643 { 644 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 0); 645 } 646 647 int 648 sysctl_tstring(oldp, oldlenp, newp, newlen, str, maxlen) 649 void *oldp; 650 size_t *oldlenp; 651 void *newp; 652 size_t newlen; 653 char *str; 654 int maxlen; 655 { 656 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1); 657 } 658 659 int 660 sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, trunc) 661 void *oldp; 662 size_t *oldlenp; 663 void *newp; 664 size_t newlen; 665 char *str; 666 int maxlen; 667 int trunc; 668 { 669 int len, error = 0; 670 char c; 671 672 len = strlen(str) + 1; 673 if (oldp && *oldlenp < len) { 674 if (trunc == 0 || *oldlenp == 0) 675 return (ENOMEM); 676 } 677 if (newp && newlen >= maxlen) 678 return (EINVAL); 679 if (oldp) { 680 if (trunc && *oldlenp < len) { 681 /* save & zap NUL terminator while copying */ 682 c = str[*oldlenp-1]; 683 str[*oldlenp-1] = '\0'; 684 error = copyout(str, oldp, *oldlenp); 685 str[*oldlenp-1] = c; 686 } else { 687 *oldlenp = len; 688 error = copyout(str, oldp, len); 689 } 690 } 691 if (error == 0 && newp) { 692 error = copyin(newp, str, newlen); 693 str[newlen] = 0; 694 } 695 return (error); 696 } 697 698 /* 699 * As above, but read-only. 700 */ 701 int 702 sysctl_rdstring(oldp, oldlenp, newp, str) 703 void *oldp; 704 size_t *oldlenp; 705 void *newp; 706 char *str; 707 { 708 int len, error = 0; 709 710 len = strlen(str) + 1; 711 if (oldp && *oldlenp < len) 712 return (ENOMEM); 713 if (newp) 714 return (EPERM); 715 *oldlenp = len; 716 if (oldp) 717 error = copyout(str, oldp, len); 718 return (error); 719 } 720 721 /* 722 * Validate parameters and get old / set new parameters 723 * for a structure oriented sysctl function. 724 */ 725 int 726 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 727 void *oldp; 728 size_t *oldlenp; 729 void *newp; 730 size_t newlen; 731 void *sp; 732 int len; 733 { 734 int error = 0; 735 736 if (oldp && *oldlenp < len) 737 return (ENOMEM); 738 if (newp && newlen > len) 739 return (EINVAL); 740 if (oldp) { 741 *oldlenp = len; 742 error = copyout(sp, oldp, len); 743 } 744 if (error == 0 && newp) 745 error = copyin(newp, sp, len); 746 return (error); 747 } 748 749 /* 750 * Validate parameters and get old parameters 751 * for a structure oriented sysctl function. 752 */ 753 int 754 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 755 void *oldp; 756 size_t *oldlenp; 757 void *newp, *sp; 758 int len; 759 { 760 int error = 0; 761 762 if (oldp && *oldlenp < len) 763 return (ENOMEM); 764 if (newp) 765 return (EPERM); 766 *oldlenp = len; 767 if (oldp) 768 error = copyout(sp, oldp, len); 769 return (error); 770 } 771 772 /* 773 * Get file structures. 774 */ 775 int 776 sysctl_file(where, sizep) 777 char *where; 778 size_t *sizep; 779 { 780 int buflen, error; 781 struct file *fp; 782 char *start = where; 783 784 buflen = *sizep; 785 if (where == NULL) { 786 /* 787 * overestimate by 10 files 788 */ 789 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 790 return (0); 791 } 792 793 /* 794 * first copyout filehead 795 */ 796 if (buflen < sizeof(filehead)) { 797 *sizep = 0; 798 return (0); 799 } 800 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 801 if (error) 802 return (error); 803 buflen -= sizeof(filehead); 804 where += sizeof(filehead); 805 806 /* 807 * followed by an array of file structures 808 */ 809 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 810 if (buflen < sizeof(struct file)) { 811 *sizep = where - start; 812 return (ENOMEM); 813 } 814 error = copyout((caddr_t)fp, where, sizeof (struct file)); 815 if (error) 816 return (error); 817 buflen -= sizeof(struct file); 818 where += sizeof(struct file); 819 } 820 *sizep = where - start; 821 return (0); 822 } 823 824 /* 825 * try over estimating by 5 procs 826 */ 827 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 828 829 int 830 sysctl_doproc(name, namelen, where, sizep) 831 int *name; 832 u_int namelen; 833 char *where; 834 size_t *sizep; 835 { 836 register struct proc *p; 837 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 838 register int needed = 0; 839 int buflen = where != NULL ? *sizep : 0; 840 int doingzomb; 841 struct eproc eproc; 842 int error = 0; 843 844 if (namelen != 2 && !(namelen == 1 && 845 (name[0] == KERN_PROC_ALL || name[0] == KERN_PROC_KTHREAD))) 846 return (EINVAL); 847 p = LIST_FIRST(&allproc); 848 doingzomb = 0; 849 again: 850 for (; p != 0; p = LIST_NEXT(p, p_list)) { 851 /* 852 * Skip embryonic processes. 853 */ 854 if (p->p_stat == SIDL) 855 continue; 856 /* 857 * TODO - make more efficient (see notes below). 858 * do by session. 859 */ 860 switch (name[0]) { 861 862 case KERN_PROC_PID: 863 /* could do this with just a lookup */ 864 if (p->p_pid != (pid_t)name[1]) 865 continue; 866 break; 867 868 case KERN_PROC_PGRP: 869 /* could do this by traversing pgrp */ 870 if (p->p_pgrp->pg_id != (pid_t)name[1]) 871 continue; 872 break; 873 874 case KERN_PROC_TTY: 875 if ((p->p_flag & P_CONTROLT) == 0 || 876 p->p_session->s_ttyp == NULL || 877 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 878 continue; 879 break; 880 881 case KERN_PROC_UID: 882 if (p->p_ucred->cr_uid != (uid_t)name[1]) 883 continue; 884 break; 885 886 case KERN_PROC_RUID: 887 if (p->p_cred->p_ruid != (uid_t)name[1]) 888 continue; 889 break; 890 891 case KERN_PROC_ALL: 892 if (p->p_flag & P_SYSTEM) 893 continue; 894 break; 895 } 896 if (buflen >= sizeof(struct kinfo_proc)) { 897 fill_eproc(p, &eproc); 898 error = copyout((caddr_t)p, &dp->kp_proc, 899 sizeof(struct proc)); 900 if (error) 901 return (error); 902 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 903 sizeof(eproc)); 904 if (error) 905 return (error); 906 dp++; 907 buflen -= sizeof(struct kinfo_proc); 908 } 909 needed += sizeof(struct kinfo_proc); 910 } 911 if (doingzomb == 0) { 912 p = LIST_FIRST(&zombproc); 913 doingzomb++; 914 goto again; 915 } 916 if (where != NULL) { 917 *sizep = (caddr_t)dp - where; 918 if (needed > *sizep) 919 return (ENOMEM); 920 } else { 921 needed += KERN_PROCSLOP; 922 *sizep = needed; 923 } 924 return (0); 925 } 926 927 /* 928 * Fill in an eproc structure for the specified process. 929 */ 930 void 931 fill_eproc(p, ep) 932 register struct proc *p; 933 register struct eproc *ep; 934 { 935 register struct tty *tp; 936 937 ep->e_paddr = p; 938 ep->e_sess = p->p_pgrp->pg_session; 939 ep->e_pcred = *p->p_cred; 940 ep->e_ucred = *p->p_ucred; 941 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 942 ep->e_vm.vm_rssize = 0; 943 ep->e_vm.vm_tsize = 0; 944 ep->e_vm.vm_dsize = 0; 945 ep->e_vm.vm_ssize = 0; 946 } else { 947 register struct vmspace *vm = p->p_vmspace; 948 949 ep->e_vm.vm_rssize = vm_resident_count(vm); 950 ep->e_vm.vm_tsize = vm->vm_tsize; 951 ep->e_vm.vm_dsize = vm->vm_dsize; 952 ep->e_vm.vm_ssize = vm->vm_ssize; 953 } 954 if (p->p_pptr) 955 ep->e_ppid = p->p_pptr->p_pid; 956 else 957 ep->e_ppid = 0; 958 ep->e_pgid = p->p_pgrp->pg_id; 959 ep->e_jobc = p->p_pgrp->pg_jobc; 960 if ((p->p_flag & P_CONTROLT) && 961 (tp = ep->e_sess->s_ttyp)) { 962 ep->e_tdev = tp->t_dev; 963 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 964 ep->e_tsess = tp->t_session; 965 } else 966 ep->e_tdev = NODEV; 967 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 968 if (SESS_LEADER(p)) 969 ep->e_flag |= EPROC_SLEADER; 970 strncpy(ep->e_wmesg, p->p_wmesg ? p->p_wmesg : "", WMESGLEN); 971 ep->e_wmesg[WMESGLEN] = '\0'; 972 ep->e_xsize = ep->e_xrssize = 0; 973 ep->e_xccount = ep->e_xswrss = 0; 974 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME-1); 975 ep->e_login[MAXLOGNAME-1] = '\0'; 976 strncpy(ep->e_emul, p->p_emul->e_name, EMULNAMELEN); 977 ep->e_emul[EMULNAMELEN] = '\0'; 978 ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0; 979 } 980 981 /* 982 * Initialize disknames/diskstats for export by sysctl. If update is set, 983 * then we simply update the disk statistics information. 984 */ 985 int 986 sysctl_diskinit(update, p) 987 int update; 988 struct proc *p; 989 { 990 struct diskstats *sdk; 991 struct disk *dk; 992 int i, tlen, l; 993 994 if ((i = lockmgr(&sysctl_disklock, LK_EXCLUSIVE, NULL, p)) != 0) 995 return i; 996 997 if (disk_change) { 998 for (dk = TAILQ_FIRST(&disklist), tlen = 0; dk; 999 dk = TAILQ_NEXT(dk, dk_link)) 1000 tlen += strlen(dk->dk_name) + 1; 1001 tlen++; 1002 1003 if (disknames) 1004 free(disknames, M_SYSCTL); 1005 if (diskstats) 1006 free(diskstats, M_SYSCTL); 1007 diskstats = NULL; 1008 disknames = NULL; 1009 diskstats = malloc(disk_count * sizeof(struct diskstats), 1010 M_SYSCTL, M_WAITOK); 1011 disknames = malloc(tlen, M_SYSCTL, M_WAITOK); 1012 disknames[0] = '\0'; 1013 1014 for (dk = TAILQ_FIRST(&disklist), i = 0, l = 0; dk; 1015 dk = TAILQ_NEXT(dk, dk_link), i++) { 1016 l += sprintf(disknames + l, "%s,", 1017 dk->dk_name ? dk->dk_name : ""); 1018 sdk = diskstats + i; 1019 sdk->ds_busy = dk->dk_busy; 1020 sdk->ds_xfer = dk->dk_xfer; 1021 sdk->ds_seek = dk->dk_seek; 1022 sdk->ds_bytes = dk->dk_bytes; 1023 sdk->ds_attachtime = dk->dk_attachtime; 1024 sdk->ds_timestamp = dk->dk_timestamp; 1025 sdk->ds_time = dk->dk_time; 1026 } 1027 1028 /* Eliminate trailing comma */ 1029 if (l != 0) 1030 disknames[l - 1] = '\0'; 1031 disk_change = 0; 1032 } else if (update) { 1033 /* Just update, number of drives hasn't changed */ 1034 for (dk = TAILQ_FIRST(&disklist), i = 0; dk; 1035 dk = TAILQ_NEXT(dk, dk_link), i++) { 1036 sdk = diskstats + i; 1037 sdk->ds_busy = dk->dk_busy; 1038 sdk->ds_xfer = dk->dk_xfer; 1039 sdk->ds_seek = dk->dk_seek; 1040 sdk->ds_bytes = dk->dk_bytes; 1041 sdk->ds_attachtime = dk->dk_attachtime; 1042 sdk->ds_timestamp = dk->dk_timestamp; 1043 sdk->ds_time = dk->dk_time; 1044 } 1045 } 1046 lockmgr(&sysctl_disklock, LK_RELEASE, NULL, p); 1047 return 0; 1048 } 1049 1050 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 1051 int 1052 sysctl_sysvipc(name, namelen, where, sizep) 1053 int *name; 1054 u_int namelen; 1055 void *where; 1056 size_t *sizep; 1057 { 1058 #ifdef SYSVMSG 1059 struct msg_sysctl_info *msgsi; 1060 #endif 1061 #ifdef SYSVSEM 1062 struct sem_sysctl_info *semsi; 1063 #endif 1064 #ifdef SYSVSHM 1065 struct shm_sysctl_info *shmsi; 1066 #endif 1067 size_t infosize, dssize, tsize, buflen; 1068 int i, nds, error, ret; 1069 void *buf; 1070 1071 if (namelen != 1) 1072 return (EINVAL); 1073 1074 buflen = *sizep; 1075 1076 switch (*name) { 1077 case KERN_SYSVIPC_MSG_INFO: 1078 #ifdef SYSVMSG 1079 infosize = sizeof(msgsi->msginfo); 1080 nds = msginfo.msgmni; 1081 dssize = sizeof(msgsi->msgids[0]); 1082 break; 1083 #else 1084 return (EOPNOTSUPP); 1085 #endif 1086 case KERN_SYSVIPC_SEM_INFO: 1087 #ifdef SYSVSEM 1088 infosize = sizeof(semsi->seminfo); 1089 nds = seminfo.semmni; 1090 dssize = sizeof(semsi->semids[0]); 1091 break; 1092 #else 1093 return (EOPNOTSUPP); 1094 #endif 1095 case KERN_SYSVIPC_SHM_INFO: 1096 #ifdef SYSVSHM 1097 infosize = sizeof(shmsi->shminfo); 1098 nds = shminfo.shmmni; 1099 dssize = sizeof(shmsi->shmids[0]); 1100 break; 1101 #else 1102 return (EOPNOTSUPP); 1103 #endif 1104 default: 1105 return (EINVAL); 1106 } 1107 tsize = infosize + (nds * dssize); 1108 1109 /* Return just the total size required. */ 1110 if (where == NULL) { 1111 *sizep = tsize; 1112 return (0); 1113 } 1114 1115 /* Not enough room for even the info struct. */ 1116 if (buflen < infosize) { 1117 *sizep = 0; 1118 return (ENOMEM); 1119 } 1120 buf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK); 1121 bzero(buf, min(tsize, buflen)); 1122 1123 switch (*name) { 1124 #ifdef SYSVMSG 1125 case KERN_SYSVIPC_MSG_INFO: 1126 msgsi = (struct msg_sysctl_info *)buf; 1127 msgsi->msginfo = msginfo; 1128 break; 1129 #endif 1130 #ifdef SYSVSEM 1131 case KERN_SYSVIPC_SEM_INFO: 1132 semsi = (struct sem_sysctl_info *)buf; 1133 semsi->seminfo = seminfo; 1134 break; 1135 #endif 1136 #ifdef SYSVSHM 1137 case KERN_SYSVIPC_SHM_INFO: 1138 shmsi = (struct shm_sysctl_info *)buf; 1139 shmsi->shminfo = shminfo; 1140 break; 1141 #endif 1142 } 1143 buflen -= infosize; 1144 1145 ret = 0; 1146 if (buflen > 0) { 1147 /* Fill in the IPC data structures. */ 1148 for (i = 0; i < nds; i++) { 1149 if (buflen < dssize) { 1150 ret = ENOMEM; 1151 break; 1152 } 1153 switch (*name) { 1154 #ifdef SYSVMSG 1155 case KERN_SYSVIPC_MSG_INFO: 1156 bcopy(&msqids[i], &msgsi->msgids[i], dssize); 1157 break; 1158 #endif 1159 #ifdef SYSVSEM 1160 case KERN_SYSVIPC_SEM_INFO: 1161 bcopy(&sema[i], &semsi->semids[i], dssize); 1162 break; 1163 #endif 1164 #ifdef SYSVSHM 1165 case KERN_SYSVIPC_SHM_INFO: 1166 bcopy(&shmsegs[i], &shmsi->shmids[i], dssize); 1167 break; 1168 #endif 1169 } 1170 buflen -= dssize; 1171 } 1172 } 1173 *sizep -= buflen; 1174 error = copyout(buf, where, *sizep); 1175 free(buf, M_TEMP); 1176 /* If copyout succeeded, use return code set earlier. */ 1177 return (error ? error : ret); 1178 } 1179 #endif /* SYSVMSG || SYSVSEM || SYSVSHM */ 1180