1 /* $OpenBSD: kern_sysctl.c,v 1.83 2003/06/10 21:50:26 mickey 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. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 36 */ 37 38 /* 39 * sysctl system call. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/malloc.h> 46 #include <sys/proc.h> 47 #include <sys/resourcevar.h> 48 #include <sys/file.h> 49 #include <sys/vnode.h> 50 #include <sys/unistd.h> 51 #include <sys/buf.h> 52 #include <sys/ioctl.h> 53 #include <sys/tty.h> 54 #include <sys/disklabel.h> 55 #include <sys/disk.h> 56 #include <uvm/uvm_extern.h> 57 #include <sys/sysctl.h> 58 #include <sys/msgbuf.h> 59 #include <sys/dkstat.h> 60 #include <sys/vmmeter.h> 61 #include <sys/namei.h> 62 #include <sys/exec.h> 63 #include <sys/mbuf.h> 64 #include <sys/sensors.h> 65 66 #include <sys/mount.h> 67 #include <sys/syscallargs.h> 68 #include <dev/rndvar.h> 69 70 #ifdef DDB 71 #include <ddb/db_var.h> 72 #endif 73 74 #ifdef SYSVMSG 75 #include <sys/msg.h> 76 #endif 77 #ifdef SYSVSEM 78 #include <sys/sem.h> 79 #endif 80 #ifdef SYSVSHM 81 #include <sys/shm.h> 82 #endif 83 84 extern struct forkstat forkstat; 85 extern struct nchstats nchstats; 86 extern int nselcoll, fscale; 87 extern struct disklist_head disklist; 88 extern fixpt_t ccpu; 89 extern long numvnodes; 90 91 int sysctl_diskinit(int, struct proc *); 92 int sysctl_proc_args(int *, u_int, void *, size_t *, struct proc *); 93 int sysctl_intrcnt(int *, u_int, void *, size_t *); 94 int sysctl_sensors(int *, u_int, void *, size_t *, void *, size_t); 95 96 /* 97 * Lock to avoid too many processes vslocking a large amount of memory 98 * at the same time. 99 */ 100 struct lock sysctl_lock, sysctl_disklock; 101 102 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES) 103 struct lock sysctl_kmemlock; 104 #endif 105 106 void 107 sysctl_init() 108 { 109 lockinit(&sysctl_lock, PLOCK|PCATCH, "sysctl", 0, 0); 110 lockinit(&sysctl_disklock, PLOCK|PCATCH, "sysctl_disklock", 0, 0); 111 112 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES) 113 lockinit(&sysctl_kmemlock, PLOCK|PCATCH, "sysctl_kmemlock", 0, 0); 114 #endif 115 } 116 117 int 118 sys___sysctl(p, v, retval) 119 struct proc *p; 120 void *v; 121 register_t *retval; 122 { 123 register struct sys___sysctl_args /* { 124 syscallarg(int *) name; 125 syscallarg(u_int) namelen; 126 syscallarg(void *) old; 127 syscallarg(size_t *) oldlenp; 128 syscallarg(void *) new; 129 syscallarg(size_t) newlen; 130 } */ *uap = v; 131 int error, dolock = 1; 132 size_t savelen = 0, oldlen = 0; 133 sysctlfn *fn; 134 int name[CTL_MAXNAME]; 135 136 if (SCARG(uap, new) != NULL && 137 (error = suser(p->p_ucred, &p->p_acflag))) 138 return (error); 139 /* 140 * all top-level sysctl names are non-terminal 141 */ 142 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2) 143 return (EINVAL); 144 error = copyin(SCARG(uap, name), name, 145 SCARG(uap, namelen) * sizeof(int)); 146 if (error) 147 return (error); 148 149 switch (name[0]) { 150 case CTL_KERN: 151 fn = kern_sysctl; 152 if (name[2] == KERN_VNODE) /* XXX */ 153 dolock = 0; 154 break; 155 case CTL_HW: 156 fn = hw_sysctl; 157 break; 158 case CTL_VM: 159 fn = uvm_sysctl; 160 break; 161 case CTL_NET: 162 fn = net_sysctl; 163 break; 164 case CTL_FS: 165 fn = fs_sysctl; 166 break; 167 case CTL_VFS: 168 fn = vfs_sysctl; 169 break; 170 case CTL_MACHDEP: 171 fn = cpu_sysctl; 172 break; 173 #ifdef DEBUG 174 case CTL_DEBUG: 175 fn = debug_sysctl; 176 break; 177 #endif 178 #ifdef DDB 179 case CTL_DDB: 180 fn = ddb_sysctl; 181 break; 182 #endif 183 default: 184 return (EOPNOTSUPP); 185 } 186 187 if (SCARG(uap, oldlenp) && 188 (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen)))) 189 return (error); 190 if (SCARG(uap, old) != NULL) { 191 if ((error = lockmgr(&sysctl_lock, LK_EXCLUSIVE, NULL, p)) != 0) 192 return (error); 193 if (dolock) { 194 error = uvm_vslock(p, SCARG(uap, old), oldlen, 195 VM_PROT_READ|VM_PROT_WRITE); 196 if (error) { 197 lockmgr(&sysctl_lock, LK_RELEASE, NULL, p); 198 return (error); 199 } 200 } 201 savelen = oldlen; 202 } 203 error = (*fn)(&name[1], SCARG(uap, namelen) - 1, SCARG(uap, old), 204 &oldlen, SCARG(uap, new), SCARG(uap, newlen), p); 205 if (SCARG(uap, old) != NULL) { 206 if (dolock) 207 uvm_vsunlock(p, SCARG(uap, old), savelen); 208 lockmgr(&sysctl_lock, LK_RELEASE, NULL, p); 209 } 210 if (error) 211 return (error); 212 if (SCARG(uap, oldlenp)) 213 error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen)); 214 return (error); 215 } 216 217 /* 218 * Attributes stored in the kernel. 219 */ 220 char hostname[MAXHOSTNAMELEN]; 221 int hostnamelen; 222 char domainname[MAXHOSTNAMELEN]; 223 int domainnamelen; 224 long hostid; 225 char *disknames = NULL; 226 struct diskstats *diskstats = NULL; 227 #ifdef INSECURE 228 int securelevel = -1; 229 #else 230 int securelevel; 231 #endif 232 233 /* 234 * kernel related system variables. 235 */ 236 int 237 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 238 int *name; 239 u_int namelen; 240 void *oldp; 241 size_t *oldlenp; 242 void *newp; 243 size_t newlen; 244 struct proc *p; 245 { 246 int error, level, inthostid, oldsgap; 247 extern int somaxconn, sominconn; 248 extern int usermount, nosuidcoredump; 249 extern long cp_time[CPUSTATES]; 250 extern int stackgap_random; 251 #ifdef CRYPTO 252 extern int usercrypto; 253 extern int userasymcrypto; 254 extern int cryptodevallowsoft; 255 #endif 256 257 /* all sysctl names at this level are terminal except a ton of them */ 258 if (namelen != 1) { 259 switch (name[0]) { 260 case KERN_PROC: 261 case KERN_PROF: 262 case KERN_MALLOCSTATS: 263 case KERN_TTY: 264 case KERN_POOL: 265 case KERN_PROC_ARGS: 266 case KERN_SYSVIPC_INFO: 267 case KERN_SEMINFO: 268 case KERN_SHMINFO: 269 case KERN_INTRCNT: 270 case KERN_WATCHDOG: 271 break; 272 default: 273 return (ENOTDIR); /* overloaded */ 274 } 275 } 276 277 switch (name[0]) { 278 case KERN_OSTYPE: 279 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 280 case KERN_OSRELEASE: 281 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 282 case KERN_OSREV: 283 return (sysctl_rdint(oldp, oldlenp, newp, OpenBSD)); 284 case KERN_OSVERSION: 285 return (sysctl_rdstring(oldp, oldlenp, newp, osversion)); 286 case KERN_VERSION: 287 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 288 case KERN_MAXVNODES: 289 return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes)); 290 case KERN_MAXPROC: 291 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 292 case KERN_MAXFILES: 293 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 294 case KERN_NFILES: 295 return (sysctl_rdint(oldp, oldlenp, newp, nfiles)); 296 case KERN_TTYCOUNT: 297 return (sysctl_rdint(oldp, oldlenp, newp, tty_count)); 298 case KERN_NUMVNODES: 299 return (sysctl_rdint(oldp, oldlenp, newp, numvnodes)); 300 case KERN_ARGMAX: 301 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 302 case KERN_NSELCOLL: 303 return (sysctl_rdint(oldp, oldlenp, newp, nselcoll)); 304 case KERN_SECURELVL: 305 level = securelevel; 306 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 307 newp == NULL) 308 return (error); 309 if ((securelevel > 0 || level < -1) 310 && level < securelevel && p->p_pid != 1) 311 return (EPERM); 312 securelevel = level; 313 return (0); 314 case KERN_HOSTNAME: 315 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 316 hostname, sizeof(hostname)); 317 if (newp && !error) 318 hostnamelen = newlen; 319 return (error); 320 case KERN_DOMAINNAME: 321 error = sysctl_tstring(oldp, oldlenp, newp, newlen, 322 domainname, sizeof(domainname)); 323 if (newp && !error) 324 domainnamelen = newlen; 325 return (error); 326 case KERN_HOSTID: 327 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 328 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 329 hostid = inthostid; 330 return (error); 331 case KERN_CLOCKRATE: 332 return (sysctl_clockrate(oldp, oldlenp)); 333 case KERN_BOOTTIME: 334 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 335 sizeof(struct timeval))); 336 case KERN_VNODE: 337 return (sysctl_vnode(oldp, oldlenp, p)); 338 case KERN_PROC: 339 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 340 case KERN_PROC_ARGS: 341 return (sysctl_proc_args(name + 1, namelen - 1, oldp, oldlenp, 342 p)); 343 case KERN_FILE: 344 return (sysctl_file(oldp, oldlenp)); 345 case KERN_MBSTAT: 346 return (sysctl_rdstruct(oldp, oldlenp, newp, &mbstat, 347 sizeof(mbstat))); 348 #ifdef GPROF 349 case KERN_PROF: 350 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 351 newp, newlen)); 352 #endif 353 case KERN_POSIX1: 354 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 355 case KERN_NGROUPS: 356 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 357 case KERN_JOB_CONTROL: 358 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 359 case KERN_SAVED_IDS: 360 #ifdef _POSIX_SAVED_IDS 361 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 362 #else 363 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 364 #endif 365 case KERN_MAXPARTITIONS: 366 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 367 case KERN_RAWPARTITION: 368 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 369 case KERN_SOMAXCONN: 370 return (sysctl_int(oldp, oldlenp, newp, newlen, &somaxconn)); 371 case KERN_SOMINCONN: 372 return (sysctl_int(oldp, oldlenp, newp, newlen, &sominconn)); 373 case KERN_USERMOUNT: 374 return (sysctl_int(oldp, oldlenp, newp, newlen, &usermount)); 375 case KERN_RND: 376 return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats, 377 sizeof(rndstats))); 378 case KERN_ARND: 379 return (sysctl_rdint(oldp, oldlenp, newp, arc4random())); 380 case KERN_NOSUIDCOREDUMP: 381 return (sysctl_int(oldp, oldlenp, newp, newlen, &nosuidcoredump)); 382 case KERN_FSYNC: 383 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 384 case KERN_SYSVMSG: 385 #ifdef SYSVMSG 386 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 387 #else 388 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 389 #endif 390 case KERN_SYSVSEM: 391 #ifdef SYSVSEM 392 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 393 #else 394 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 395 #endif 396 case KERN_SYSVSHM: 397 #ifdef SYSVSHM 398 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 399 #else 400 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 401 #endif 402 case KERN_MSGBUFSIZE: 403 /* 404 * deal with cases where the message buffer has 405 * become corrupted. 406 */ 407 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 408 return (ENXIO); 409 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 410 case KERN_MSGBUF: 411 /* see note above */ 412 if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC) 413 return (ENXIO); 414 return (sysctl_rdstruct(oldp, oldlenp, newp, msgbufp, 415 msgbufp->msg_bufs + offsetof(struct msgbuf, msg_bufc))); 416 case KERN_MALLOCSTATS: 417 return (sysctl_malloc(name + 1, namelen - 1, oldp, oldlenp, 418 newp, newlen, p)); 419 case KERN_CPTIME: 420 return (sysctl_rdstruct(oldp, oldlenp, newp, &cp_time, 421 sizeof(cp_time))); 422 case KERN_NCHSTATS: 423 return (sysctl_rdstruct(oldp, oldlenp, newp, &nchstats, 424 sizeof(struct nchstats))); 425 case KERN_FORKSTAT: 426 return (sysctl_rdstruct(oldp, oldlenp, newp, &forkstat, 427 sizeof(struct forkstat))); 428 case KERN_TTY: 429 return (sysctl_tty(name + 1, namelen - 1, oldp, oldlenp, 430 newp, newlen)); 431 case KERN_FSCALE: 432 return (sysctl_rdint(oldp, oldlenp, newp, fscale)); 433 case KERN_CCPU: 434 return (sysctl_rdint(oldp, oldlenp, newp, ccpu)); 435 case KERN_NPROCS: 436 return (sysctl_rdint(oldp, oldlenp, newp, nprocs)); 437 case KERN_POOL: 438 return (sysctl_dopool(name + 1, namelen - 1, oldp, oldlenp)); 439 case KERN_STACKGAPRANDOM: 440 oldsgap = stackgap_random; 441 442 error = sysctl_int(oldp, oldlenp, newp, newlen, &stackgap_random); 443 /* 444 * Safety harness. 445 */ 446 if ((stackgap_random < ALIGNBYTES && stackgap_random != 0) || 447 !powerof2(stackgap_random) || 448 stackgap_random > PAGE_SIZE * 2) { 449 stackgap_random = oldsgap; 450 return (EINVAL); 451 } 452 return (error); 453 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 454 case KERN_SYSVIPC_INFO: 455 return (sysctl_sysvipc(name + 1, namelen - 1, oldp, oldlenp)); 456 #endif 457 #ifdef CRYPTO 458 case KERN_USERCRYPTO: 459 return (sysctl_int(oldp, oldlenp, newp, newlen, &usercrypto)); 460 case KERN_USERASYMCRYPTO: 461 return (sysctl_int(oldp, oldlenp, newp, newlen, 462 &userasymcrypto)); 463 case KERN_CRYPTODEVALLOWSOFT: 464 return (sysctl_int(oldp, oldlenp, newp, newlen, 465 &cryptodevallowsoft)); 466 #endif 467 case KERN_SPLASSERT: 468 return (sysctl_int(oldp, oldlenp, newp, newlen, 469 &splassert_ctl)); 470 #ifdef SYSVSEM 471 case KERN_SEMINFO: 472 return (sysctl_sysvsem(name + 1, namelen - 1, oldp, oldlenp, 473 newp, newlen)); 474 #endif 475 #ifdef SYSVSHM 476 case KERN_SHMINFO: 477 return (sysctl_sysvshm(name + 1, namelen - 1, oldp, oldlenp, 478 newp, newlen)); 479 #endif 480 case KERN_INTRCNT: 481 return (sysctl_intrcnt(name + 1, namelen - 1, oldp, oldlenp)); 482 case KERN_WATCHDOG: 483 return (sysctl_wdog(name + 1, namelen - 1, oldp, oldlenp, 484 newp, newlen)); 485 default: 486 return (EOPNOTSUPP); 487 } 488 /* NOTREACHED */ 489 } 490 491 /* 492 * hardware related system variables. 493 */ 494 int 495 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 496 int *name; 497 u_int namelen; 498 void *oldp; 499 size_t *oldlenp; 500 void *newp; 501 size_t newlen; 502 struct proc *p; 503 { 504 extern char machine[], cpu_model[]; 505 int err; 506 507 /* all sysctl names at this level except sensors are terminal */ 508 if (name[0] != HW_SENSORS && namelen != 1) 509 return (ENOTDIR); /* overloaded */ 510 511 switch (name[0]) { 512 case HW_MACHINE: 513 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 514 case HW_MODEL: 515 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 516 case HW_NCPU: 517 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 518 case HW_BYTEORDER: 519 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 520 case HW_PHYSMEM: 521 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 522 case HW_USERMEM: 523 return (sysctl_rdint(oldp, oldlenp, newp, 524 ctob(physmem - uvmexp.wired))); 525 case HW_PAGESIZE: 526 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 527 case HW_DISKNAMES: 528 err = sysctl_diskinit(0, p); 529 if (err) 530 return err; 531 if (disknames) 532 return (sysctl_rdstring(oldp, oldlenp, newp, 533 disknames)); 534 else 535 return (sysctl_rdstring(oldp, oldlenp, newp, "")); 536 case HW_DISKSTATS: 537 err = sysctl_diskinit(1, p); 538 if (err) 539 return err; 540 return (sysctl_rdstruct(oldp, oldlenp, newp, diskstats, 541 disk_count * sizeof(struct diskstats))); 542 case HW_DISKCOUNT: 543 return (sysctl_rdint(oldp, oldlenp, newp, disk_count)); 544 case HW_SENSORS: 545 return (sysctl_sensors(name + 1, namelen - 1, oldp, oldlenp, 546 newp, newlen)); 547 default: 548 return (EOPNOTSUPP); 549 } 550 /* NOTREACHED */ 551 } 552 553 #ifdef DEBUG 554 /* 555 * Debugging related system variables. 556 */ 557 extern struct ctldebug debug0, debug1; 558 struct ctldebug debug2, debug3, debug4; 559 struct ctldebug debug5, debug6, debug7, debug8, debug9; 560 struct ctldebug debug10, debug11, debug12, debug13, debug14; 561 struct ctldebug debug15, debug16, debug17, debug18, debug19; 562 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 563 &debug0, &debug1, &debug2, &debug3, &debug4, 564 &debug5, &debug6, &debug7, &debug8, &debug9, 565 &debug10, &debug11, &debug12, &debug13, &debug14, 566 &debug15, &debug16, &debug17, &debug18, &debug19, 567 }; 568 int 569 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 570 int *name; 571 u_int namelen; 572 void *oldp; 573 size_t *oldlenp; 574 void *newp; 575 size_t newlen; 576 struct proc *p; 577 { 578 struct ctldebug *cdp; 579 580 /* all sysctl names at this level are name and field */ 581 if (namelen != 2) 582 return (ENOTDIR); /* overloaded */ 583 cdp = debugvars[name[0]]; 584 if (cdp->debugname == 0) 585 return (EOPNOTSUPP); 586 switch (name[1]) { 587 case CTL_DEBUG_NAME: 588 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 589 case CTL_DEBUG_VALUE: 590 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 591 default: 592 return (EOPNOTSUPP); 593 } 594 /* NOTREACHED */ 595 } 596 #endif /* DEBUG */ 597 598 /* 599 * Validate parameters and get old / set new parameters 600 * for an integer-valued sysctl function. 601 */ 602 int 603 sysctl_int(oldp, oldlenp, newp, newlen, valp) 604 void *oldp; 605 size_t *oldlenp; 606 void *newp; 607 size_t newlen; 608 int *valp; 609 { 610 int error = 0; 611 612 if (oldp && *oldlenp < sizeof(int)) 613 return (ENOMEM); 614 if (newp && newlen != sizeof(int)) 615 return (EINVAL); 616 *oldlenp = sizeof(int); 617 if (oldp) 618 error = copyout(valp, oldp, sizeof(int)); 619 if (error == 0 && newp) 620 error = copyin(newp, valp, sizeof(int)); 621 return (error); 622 } 623 624 /* 625 * As above, but read-only. 626 */ 627 int 628 sysctl_rdint(oldp, oldlenp, newp, val) 629 void *oldp; 630 size_t *oldlenp; 631 void *newp; 632 int val; 633 { 634 int error = 0; 635 636 if (oldp && *oldlenp < sizeof(int)) 637 return (ENOMEM); 638 if (newp) 639 return (EPERM); 640 *oldlenp = sizeof(int); 641 if (oldp) 642 error = copyout((caddr_t)&val, oldp, sizeof(int)); 643 return (error); 644 } 645 646 /* 647 * Validate parameters and get old / set new parameters 648 * for an integer-valued sysctl function. 649 */ 650 int 651 sysctl_quad(oldp, oldlenp, newp, newlen, valp) 652 void *oldp; 653 size_t *oldlenp; 654 void *newp; 655 size_t newlen; 656 int64_t *valp; 657 { 658 int error = 0; 659 660 if (oldp && *oldlenp < sizeof(int64_t)) 661 return (ENOMEM); 662 if (newp && newlen != sizeof(int64_t)) 663 return (EINVAL); 664 *oldlenp = sizeof(int64_t); 665 if (oldp) 666 error = copyout(valp, oldp, sizeof(int64_t)); 667 if (error == 0 && newp) 668 error = copyin(newp, valp, sizeof(int64_t)); 669 return (error); 670 } 671 672 /* 673 * As above, but read-only. 674 */ 675 int 676 sysctl_rdquad(oldp, oldlenp, newp, val) 677 void *oldp; 678 size_t *oldlenp; 679 void *newp; 680 int64_t val; 681 { 682 int error = 0; 683 684 if (oldp && *oldlenp < sizeof(int64_t)) 685 return (ENOMEM); 686 if (newp) 687 return (EPERM); 688 *oldlenp = sizeof(int64_t); 689 if (oldp) 690 error = copyout((caddr_t)&val, oldp, sizeof(int64_t)); 691 return (error); 692 } 693 694 /* 695 * Validate parameters and get old / set new parameters 696 * for a string-valued sysctl function. 697 */ 698 int 699 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 700 void *oldp; 701 size_t *oldlenp; 702 void *newp; 703 size_t newlen; 704 char *str; 705 int maxlen; 706 { 707 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 0); 708 } 709 710 int 711 sysctl_tstring(oldp, oldlenp, newp, newlen, str, maxlen) 712 void *oldp; 713 size_t *oldlenp; 714 void *newp; 715 size_t newlen; 716 char *str; 717 int maxlen; 718 { 719 return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1); 720 } 721 722 int 723 sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, trunc) 724 void *oldp; 725 size_t *oldlenp; 726 void *newp; 727 size_t newlen; 728 char *str; 729 int maxlen; 730 int trunc; 731 { 732 int len, error = 0; 733 char c; 734 735 len = strlen(str) + 1; 736 if (oldp && *oldlenp < len) { 737 if (trunc == 0 || *oldlenp == 0) 738 return (ENOMEM); 739 } 740 if (newp && newlen >= maxlen) 741 return (EINVAL); 742 if (oldp) { 743 if (trunc && *oldlenp < len) { 744 /* save & zap NUL terminator while copying */ 745 c = str[*oldlenp-1]; 746 str[*oldlenp-1] = '\0'; 747 error = copyout(str, oldp, *oldlenp); 748 str[*oldlenp-1] = c; 749 } else { 750 *oldlenp = len; 751 error = copyout(str, oldp, len); 752 } 753 } 754 if (error == 0 && newp) { 755 error = copyin(newp, str, newlen); 756 str[newlen] = 0; 757 } 758 return (error); 759 } 760 761 /* 762 * As above, but read-only. 763 */ 764 int 765 sysctl_rdstring(oldp, oldlenp, newp, str) 766 void *oldp; 767 size_t *oldlenp; 768 void *newp; 769 const char *str; 770 { 771 int len, error = 0; 772 773 len = strlen(str) + 1; 774 if (oldp && *oldlenp < len) 775 return (ENOMEM); 776 if (newp) 777 return (EPERM); 778 *oldlenp = len; 779 if (oldp) 780 error = copyout(str, oldp, len); 781 return (error); 782 } 783 784 /* 785 * Validate parameters and get old / set new parameters 786 * for a structure oriented sysctl function. 787 */ 788 int 789 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 790 void *oldp; 791 size_t *oldlenp; 792 void *newp; 793 size_t newlen; 794 void *sp; 795 int len; 796 { 797 int error = 0; 798 799 if (oldp && *oldlenp < len) 800 return (ENOMEM); 801 if (newp && newlen > len) 802 return (EINVAL); 803 if (oldp) { 804 *oldlenp = len; 805 error = copyout(sp, oldp, len); 806 } 807 if (error == 0 && newp) 808 error = copyin(newp, sp, len); 809 return (error); 810 } 811 812 /* 813 * Validate parameters and get old parameters 814 * for a structure oriented sysctl function. 815 */ 816 int 817 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 818 void *oldp; 819 size_t *oldlenp; 820 void *newp; 821 const void *sp; 822 int len; 823 { 824 int error = 0; 825 826 if (oldp && *oldlenp < len) 827 return (ENOMEM); 828 if (newp) 829 return (EPERM); 830 *oldlenp = len; 831 if (oldp) 832 error = copyout(sp, oldp, len); 833 return (error); 834 } 835 836 /* 837 * Get file structures. 838 */ 839 int 840 sysctl_file(where, sizep) 841 char *where; 842 size_t *sizep; 843 { 844 int buflen, error; 845 struct file *fp; 846 char *start = where; 847 848 buflen = *sizep; 849 if (where == NULL) { 850 /* 851 * overestimate by 10 files 852 */ 853 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 854 return (0); 855 } 856 857 /* 858 * first copyout filehead 859 */ 860 if (buflen < sizeof(filehead)) { 861 *sizep = 0; 862 return (0); 863 } 864 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 865 if (error) 866 return (error); 867 buflen -= sizeof(filehead); 868 where += sizeof(filehead); 869 870 /* 871 * followed by an array of file structures 872 */ 873 LIST_FOREACH(fp, &filehead, f_list) { 874 if (buflen < sizeof(struct file)) { 875 *sizep = where - start; 876 return (ENOMEM); 877 } 878 error = copyout((caddr_t)fp, where, sizeof (struct file)); 879 if (error) 880 return (error); 881 buflen -= sizeof(struct file); 882 where += sizeof(struct file); 883 } 884 *sizep = where - start; 885 return (0); 886 } 887 888 /* 889 * try over estimating by 5 procs 890 */ 891 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 892 893 int 894 sysctl_doproc(name, namelen, where, sizep) 895 int *name; 896 u_int namelen; 897 char *where; 898 size_t *sizep; 899 { 900 register struct proc *p; 901 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 902 register int needed = 0; 903 int buflen = where != NULL ? *sizep : 0; 904 int doingzomb; 905 struct eproc eproc; 906 int error = 0; 907 908 if (namelen != 2 && !(namelen == 1 && 909 (name[0] == KERN_PROC_ALL || name[0] == KERN_PROC_KTHREAD))) 910 return (EINVAL); 911 p = LIST_FIRST(&allproc); 912 doingzomb = 0; 913 again: 914 for (; p != 0; p = LIST_NEXT(p, p_list)) { 915 /* 916 * Skip embryonic processes. 917 */ 918 if (p->p_stat == SIDL) 919 continue; 920 /* 921 * TODO - make more efficient (see notes below). 922 * do by session. 923 */ 924 switch (name[0]) { 925 926 case KERN_PROC_PID: 927 /* could do this with just a lookup */ 928 if (p->p_pid != (pid_t)name[1]) 929 continue; 930 break; 931 932 case KERN_PROC_PGRP: 933 /* could do this by traversing pgrp */ 934 if (p->p_pgrp->pg_id != (pid_t)name[1]) 935 continue; 936 break; 937 938 case KERN_PROC_TTY: 939 if ((p->p_flag & P_CONTROLT) == 0 || 940 p->p_session->s_ttyp == NULL || 941 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 942 continue; 943 break; 944 945 case KERN_PROC_UID: 946 if (p->p_ucred->cr_uid != (uid_t)name[1]) 947 continue; 948 break; 949 950 case KERN_PROC_RUID: 951 if (p->p_cred->p_ruid != (uid_t)name[1]) 952 continue; 953 break; 954 955 case KERN_PROC_ALL: 956 if (p->p_flag & P_SYSTEM) 957 continue; 958 break; 959 } 960 if (buflen >= sizeof(struct kinfo_proc)) { 961 fill_eproc(p, &eproc); 962 error = copyout((caddr_t)p, &dp->kp_proc, 963 sizeof(struct proc)); 964 if (error) 965 return (error); 966 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 967 sizeof(eproc)); 968 if (error) 969 return (error); 970 dp++; 971 buflen -= sizeof(struct kinfo_proc); 972 } 973 needed += sizeof(struct kinfo_proc); 974 } 975 if (doingzomb == 0) { 976 p = LIST_FIRST(&zombproc); 977 doingzomb++; 978 goto again; 979 } 980 if (where != NULL) { 981 *sizep = (caddr_t)dp - where; 982 if (needed > *sizep) 983 return (ENOMEM); 984 } else { 985 needed += KERN_PROCSLOP; 986 *sizep = needed; 987 } 988 return (0); 989 } 990 991 /* 992 * Fill in an eproc structure for the specified process. 993 */ 994 void 995 fill_eproc(struct proc *p, struct eproc *ep) 996 { 997 struct tty *tp; 998 999 ep->e_paddr = p; 1000 ep->e_sess = p->p_pgrp->pg_session; 1001 ep->e_pcred = *p->p_cred; 1002 ep->e_ucred = *p->p_ucred; 1003 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 1004 ep->e_vm.vm_rssize = 0; 1005 ep->e_vm.vm_tsize = 0; 1006 ep->e_vm.vm_dsize = 0; 1007 ep->e_vm.vm_ssize = 0; 1008 bzero(&ep->e_pstats, sizeof(ep->e_pstats)); 1009 ep->e_pstats_valid = 0; 1010 } else { 1011 struct vmspace *vm = p->p_vmspace; 1012 1013 PHOLD(p); /* need for pstats */ 1014 ep->e_vm.vm_rssize = vm_resident_count(vm); 1015 ep->e_vm.vm_tsize = vm->vm_tsize; 1016 ep->e_vm.vm_dsize = vm->vm_dsize; 1017 ep->e_vm.vm_ssize = vm->vm_ssize; 1018 ep->e_pstats = *p->p_stats; 1019 ep->e_pstats_valid = 1; 1020 PRELE(p); 1021 } 1022 if (p->p_pptr) 1023 ep->e_ppid = p->p_pptr->p_pid; 1024 else 1025 ep->e_ppid = 0; 1026 ep->e_pgid = p->p_pgrp->pg_id; 1027 ep->e_jobc = p->p_pgrp->pg_jobc; 1028 if ((p->p_flag & P_CONTROLT) && 1029 (tp = ep->e_sess->s_ttyp)) { 1030 ep->e_tdev = tp->t_dev; 1031 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1032 ep->e_tsess = tp->t_session; 1033 } else 1034 ep->e_tdev = NODEV; 1035 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 1036 if (SESS_LEADER(p)) 1037 ep->e_flag |= EPROC_SLEADER; 1038 strncpy(ep->e_wmesg, p->p_wmesg ? p->p_wmesg : "", WMESGLEN); 1039 ep->e_wmesg[WMESGLEN] = '\0'; 1040 ep->e_xsize = ep->e_xrssize = 0; 1041 ep->e_xccount = ep->e_xswrss = 0; 1042 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME-1); 1043 ep->e_login[MAXLOGNAME-1] = '\0'; 1044 strncpy(ep->e_emul, p->p_emul->e_name, EMULNAMELEN); 1045 ep->e_emul[EMULNAMELEN] = '\0'; 1046 ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0; 1047 } 1048 1049 int 1050 sysctl_proc_args(int *name, u_int namelen, void *oldp, size_t *oldlenp, 1051 struct proc *cp) 1052 { 1053 struct proc *vp; 1054 pid_t pid; 1055 int op; 1056 struct ps_strings pss; 1057 struct iovec iov; 1058 struct uio uio; 1059 int error; 1060 size_t limit; 1061 int cnt; 1062 char **rargv, **vargv; /* reader vs. victim */ 1063 char *rarg, *varg; 1064 char *buf; 1065 1066 if (namelen > 2) 1067 return (ENOTDIR); 1068 if (namelen < 2) 1069 return (EINVAL); 1070 1071 pid = name[0]; 1072 op = name[1]; 1073 1074 switch (op) { 1075 case KERN_PROC_ARGV: 1076 case KERN_PROC_NARGV: 1077 case KERN_PROC_ENV: 1078 case KERN_PROC_NENV: 1079 break; 1080 default: 1081 return (EOPNOTSUPP); 1082 } 1083 1084 if ((vp = pfind(pid)) == NULL) 1085 return (ESRCH); 1086 1087 if (P_ZOMBIE(vp) || (vp->p_flag & P_SYSTEM)) 1088 return (EINVAL); 1089 1090 /* Exiting - don't bother, it will be gone soon anyway */ 1091 if ((vp->p_flag & P_WEXIT)) 1092 return (ESRCH); 1093 1094 /* Execing - danger. */ 1095 if ((vp->p_flag & P_INEXEC)) 1096 return (EBUSY); 1097 1098 vp->p_vmspace->vm_refcnt++; /* XXX */ 1099 buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 1100 1101 iov.iov_base = &pss; 1102 iov.iov_len = sizeof(pss); 1103 uio.uio_iov = &iov; 1104 uio.uio_iovcnt = 1; 1105 uio.uio_offset = (off_t)PS_STRINGS; 1106 uio.uio_resid = sizeof(pss); 1107 uio.uio_segflg = UIO_SYSSPACE; 1108 uio.uio_rw = UIO_READ; 1109 uio.uio_procp = cp; 1110 1111 if ((error = uvm_io(&vp->p_vmspace->vm_map, &uio)) != 0) 1112 goto out; 1113 1114 if (op == KERN_PROC_NARGV) { 1115 error = sysctl_rdint(oldp, oldlenp, NULL, pss.ps_nargvstr); 1116 goto out; 1117 } 1118 if (op == KERN_PROC_NENV) { 1119 error = sysctl_rdint(oldp, oldlenp, NULL, pss.ps_nenvstr); 1120 goto out; 1121 } 1122 1123 if (op == KERN_PROC_ARGV) { 1124 cnt = pss.ps_nargvstr; 1125 vargv = pss.ps_argvstr; 1126 } else { 1127 cnt = pss.ps_nenvstr; 1128 vargv = pss.ps_envstr; 1129 } 1130 1131 /* -1 to have space for a terminating NUL */ 1132 limit = *oldlenp - 1; 1133 *oldlenp = 0; 1134 1135 if (limit > 8 * PAGE_SIZE) { 1136 /* Don't allow a denial of service. */ 1137 error = E2BIG; 1138 goto out; 1139 } 1140 1141 rargv = oldp; 1142 1143 /* 1144 * *oldlenp - number of bytes copied out into readers buffer. 1145 * limit - maximal number of bytes allowed into readers buffer. 1146 * rarg - pointer into readers buffer where next arg will be stored. 1147 * rargv - pointer into readers buffer where the next rarg pointer 1148 * will be stored. 1149 * vargv - pointer into victim address space where the next argument 1150 * will be read. 1151 */ 1152 1153 /* space for cnt pointers and a NULL */ 1154 rarg = (char *)(rargv + cnt + 1); 1155 *oldlenp += (cnt + 1) * sizeof(char **); 1156 1157 while (cnt > 0 && *oldlenp < limit) { 1158 size_t len, vstrlen; 1159 1160 /* Write to readers argv */ 1161 if ((error = copyout(&rarg, rargv, sizeof(rarg))) != 0) 1162 goto out; 1163 1164 /* read the victim argv */ 1165 iov.iov_base = &varg; 1166 iov.iov_len = sizeof(varg); 1167 uio.uio_iov = &iov; 1168 uio.uio_iovcnt = 1; 1169 uio.uio_offset = (off_t)(vaddr_t)vargv; 1170 uio.uio_resid = sizeof(varg); 1171 uio.uio_segflg = UIO_SYSSPACE; 1172 uio.uio_rw = UIO_READ; 1173 uio.uio_procp = cp; 1174 if ((error = uvm_io(&vp->p_vmspace->vm_map, &uio)) != 0) 1175 goto out; 1176 1177 if (varg == NULL) 1178 break; 1179 1180 /* 1181 * read the victim arg. We must jump through hoops to avoid 1182 * crossing a page boundary too much and returning an error. 1183 */ 1184 more: 1185 len = PAGE_SIZE - (((vaddr_t)varg) & PAGE_MASK); 1186 /* leave space for the terminating NUL */ 1187 iov.iov_base = buf; 1188 iov.iov_len = len; 1189 uio.uio_iov = &iov; 1190 uio.uio_iovcnt = 1; 1191 uio.uio_offset = (off_t)(vaddr_t)varg; 1192 uio.uio_resid = len; 1193 uio.uio_segflg = UIO_SYSSPACE; 1194 uio.uio_rw = UIO_READ; 1195 uio.uio_procp = cp; 1196 if ((error = uvm_io(&vp->p_vmspace->vm_map, &uio)) != 0) 1197 goto out; 1198 1199 for (vstrlen = 0; vstrlen < len; vstrlen++) { 1200 if (buf[vstrlen] == '\0') 1201 break; 1202 } 1203 1204 /* Don't overflow readers buffer. */ 1205 if (*oldlenp + vstrlen + 1 >= limit) { 1206 error = ENOMEM; 1207 goto out; 1208 } 1209 1210 if ((error = copyout(buf, rarg, vstrlen)) != 0) 1211 goto out; 1212 1213 *oldlenp += vstrlen; 1214 rarg += vstrlen; 1215 1216 /* The string didn't end in this page? */ 1217 if (vstrlen == len) { 1218 varg += vstrlen; 1219 goto more; 1220 } 1221 1222 /* End of string. Terminate it with a NUL */ 1223 buf[0] = '\0'; 1224 if ((error = copyout(buf, rarg, 1)) != 0) 1225 goto out; 1226 *oldlenp += 1;; 1227 rarg += 1; 1228 1229 vargv++; 1230 rargv++; 1231 cnt--; 1232 } 1233 1234 if (*oldlenp >= limit) { 1235 error = ENOMEM; 1236 goto out; 1237 } 1238 1239 /* Write the terminating null */ 1240 rarg = NULL; 1241 error = copyout(&rarg, rargv, sizeof(rarg)); 1242 1243 out: 1244 uvmspace_free(vp->p_vmspace); 1245 free(buf, M_TEMP); 1246 return (error); 1247 } 1248 1249 /* 1250 * Initialize disknames/diskstats for export by sysctl. If update is set, 1251 * then we simply update the disk statistics information. 1252 */ 1253 int 1254 sysctl_diskinit(update, p) 1255 int update; 1256 struct proc *p; 1257 { 1258 struct diskstats *sdk; 1259 struct disk *dk; 1260 int i, tlen, l; 1261 1262 if ((i = lockmgr(&sysctl_disklock, LK_EXCLUSIVE, NULL, p)) != 0) 1263 return i; 1264 1265 if (disk_change) { 1266 for (dk = TAILQ_FIRST(&disklist), tlen = 0; dk; 1267 dk = TAILQ_NEXT(dk, dk_link)) 1268 tlen += strlen(dk->dk_name) + 1; 1269 tlen++; 1270 1271 if (disknames) 1272 free(disknames, M_SYSCTL); 1273 if (diskstats) 1274 free(diskstats, M_SYSCTL); 1275 diskstats = NULL; 1276 disknames = NULL; 1277 diskstats = malloc(disk_count * sizeof(struct diskstats), 1278 M_SYSCTL, M_WAITOK); 1279 disknames = malloc(tlen, M_SYSCTL, M_WAITOK); 1280 disknames[0] = '\0'; 1281 1282 for (dk = TAILQ_FIRST(&disklist), i = 0, l = 0; dk; 1283 dk = TAILQ_NEXT(dk, dk_link), i++) { 1284 snprintf(disknames + l, tlen - l, "%s,", 1285 dk->dk_name ? dk->dk_name : ""); 1286 l += strlen(disknames + l); 1287 sdk = diskstats + i; 1288 sdk->ds_busy = dk->dk_busy; 1289 sdk->ds_xfer = dk->dk_xfer; 1290 sdk->ds_seek = dk->dk_seek; 1291 sdk->ds_bytes = dk->dk_bytes; 1292 sdk->ds_attachtime = dk->dk_attachtime; 1293 sdk->ds_timestamp = dk->dk_timestamp; 1294 sdk->ds_time = dk->dk_time; 1295 } 1296 1297 /* Eliminate trailing comma */ 1298 if (l != 0) 1299 disknames[l - 1] = '\0'; 1300 disk_change = 0; 1301 } else if (update) { 1302 /* Just update, number of drives hasn't changed */ 1303 for (dk = TAILQ_FIRST(&disklist), i = 0; dk; 1304 dk = TAILQ_NEXT(dk, dk_link), i++) { 1305 sdk = diskstats + i; 1306 sdk->ds_busy = dk->dk_busy; 1307 sdk->ds_xfer = dk->dk_xfer; 1308 sdk->ds_seek = dk->dk_seek; 1309 sdk->ds_bytes = dk->dk_bytes; 1310 sdk->ds_attachtime = dk->dk_attachtime; 1311 sdk->ds_timestamp = dk->dk_timestamp; 1312 sdk->ds_time = dk->dk_time; 1313 } 1314 } 1315 lockmgr(&sysctl_disklock, LK_RELEASE, NULL, p); 1316 return 0; 1317 } 1318 1319 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 1320 int 1321 sysctl_sysvipc(name, namelen, where, sizep) 1322 int *name; 1323 u_int namelen; 1324 void *where; 1325 size_t *sizep; 1326 { 1327 #ifdef SYSVMSG 1328 struct msg_sysctl_info *msgsi; 1329 #endif 1330 #ifdef SYSVSEM 1331 struct sem_sysctl_info *semsi; 1332 #endif 1333 #ifdef SYSVSHM 1334 struct shm_sysctl_info *shmsi; 1335 #endif 1336 size_t infosize, dssize, tsize, buflen; 1337 int i, nds, error, ret; 1338 void *buf; 1339 1340 if (namelen != 1) 1341 return (EINVAL); 1342 1343 buflen = *sizep; 1344 1345 switch (*name) { 1346 case KERN_SYSVIPC_MSG_INFO: 1347 #ifdef SYSVMSG 1348 infosize = sizeof(msgsi->msginfo); 1349 nds = msginfo.msgmni; 1350 dssize = sizeof(msgsi->msgids[0]); 1351 break; 1352 #else 1353 return (EOPNOTSUPP); 1354 #endif 1355 case KERN_SYSVIPC_SEM_INFO: 1356 #ifdef SYSVSEM 1357 infosize = sizeof(semsi->seminfo); 1358 nds = seminfo.semmni; 1359 dssize = sizeof(semsi->semids[0]); 1360 break; 1361 #else 1362 return (EOPNOTSUPP); 1363 #endif 1364 case KERN_SYSVIPC_SHM_INFO: 1365 #ifdef SYSVSHM 1366 infosize = sizeof(shmsi->shminfo); 1367 nds = shminfo.shmmni; 1368 dssize = sizeof(shmsi->shmids[0]); 1369 break; 1370 #else 1371 return (EOPNOTSUPP); 1372 #endif 1373 default: 1374 return (EINVAL); 1375 } 1376 tsize = infosize + (nds * dssize); 1377 1378 /* Return just the total size required. */ 1379 if (where == NULL) { 1380 *sizep = tsize; 1381 return (0); 1382 } 1383 1384 /* Not enough room for even the info struct. */ 1385 if (buflen < infosize) { 1386 *sizep = 0; 1387 return (ENOMEM); 1388 } 1389 buf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK); 1390 bzero(buf, min(tsize, buflen)); 1391 1392 switch (*name) { 1393 #ifdef SYSVMSG 1394 case KERN_SYSVIPC_MSG_INFO: 1395 msgsi = (struct msg_sysctl_info *)buf; 1396 msgsi->msginfo = msginfo; 1397 break; 1398 #endif 1399 #ifdef SYSVSEM 1400 case KERN_SYSVIPC_SEM_INFO: 1401 semsi = (struct sem_sysctl_info *)buf; 1402 semsi->seminfo = seminfo; 1403 break; 1404 #endif 1405 #ifdef SYSVSHM 1406 case KERN_SYSVIPC_SHM_INFO: 1407 shmsi = (struct shm_sysctl_info *)buf; 1408 shmsi->shminfo = shminfo; 1409 break; 1410 #endif 1411 } 1412 buflen -= infosize; 1413 1414 ret = 0; 1415 if (buflen > 0) { 1416 /* Fill in the IPC data structures. */ 1417 for (i = 0; i < nds; i++) { 1418 if (buflen < dssize) { 1419 ret = ENOMEM; 1420 break; 1421 } 1422 switch (*name) { 1423 #ifdef SYSVMSG 1424 case KERN_SYSVIPC_MSG_INFO: 1425 bcopy(&msqids[i], &msgsi->msgids[i], dssize); 1426 break; 1427 #endif 1428 #ifdef SYSVSEM 1429 case KERN_SYSVIPC_SEM_INFO: 1430 if (sema[i] != NULL) 1431 bcopy(sema[i], &semsi->semids[i], 1432 dssize); 1433 else 1434 bzero(&semsi->semids[i], dssize); 1435 break; 1436 #endif 1437 #ifdef SYSVSHM 1438 case KERN_SYSVIPC_SHM_INFO: 1439 if (shmsegs[i] != NULL) 1440 bcopy(shmsegs[i], &shmsi->shmids[i], 1441 dssize); 1442 else 1443 bzero(&shmsi->shmids[i], dssize); 1444 break; 1445 #endif 1446 } 1447 buflen -= dssize; 1448 } 1449 } 1450 *sizep -= buflen; 1451 error = copyout(buf, where, *sizep); 1452 free(buf, M_TEMP); 1453 /* If copyout succeeded, use return code set earlier. */ 1454 return (error ? error : ret); 1455 } 1456 #endif /* SYSVMSG || SYSVSEM || SYSVSHM */ 1457 1458 int 1459 sysctl_intrcnt(int *name, u_int namelen, void *oldp, size_t *oldlenp) 1460 { 1461 extern int intrcnt[], eintrcnt[]; 1462 extern char intrnames[], eintrnames[]; 1463 char *intrname; 1464 int nintr, i; 1465 1466 nintr = (off_t)(eintrcnt - intrcnt); 1467 1468 if (name[0] != KERN_INTRCNT_NUM) { 1469 if (namelen != 2) 1470 return (ENOTDIR); 1471 if (name[1] < 0 || name[1] >= nintr) 1472 return (EINVAL); 1473 i = name[1]; 1474 } 1475 1476 switch (name[0]) { 1477 case KERN_INTRCNT_NUM: 1478 return (sysctl_rdint(oldp, oldlenp, NULL, nintr)); 1479 break; 1480 case KERN_INTRCNT_CNT: 1481 return (sysctl_rdint(oldp, oldlenp, NULL, intrcnt[i])); 1482 case KERN_INTRCNT_NAME: 1483 intrname = intrnames; 1484 while (i > 0) { 1485 intrname += strlen(intrname) + 1; 1486 i--; 1487 if (intrname > eintrnames) 1488 return (EINVAL); 1489 } 1490 return (sysctl_rdstring(oldp, oldlenp, NULL, intrname)); 1491 default: 1492 return (EOPNOTSUPP); 1493 } 1494 } 1495 1496 int nsensors = 0; 1497 struct sensors_head sensors = SLIST_HEAD_INITIALIZER(&sensors); 1498 1499 int 1500 sysctl_sensors(int *name, u_int namelen, void *oldp, size_t *oldlenp, 1501 void *newp, size_t newlen) 1502 { 1503 struct sensor *s = NULL; 1504 int num; 1505 1506 if (namelen != 1) 1507 return (ENOTDIR); 1508 1509 num = name[0]; 1510 if (num >= nsensors) 1511 return (ENXIO); 1512 1513 SLIST_FOREACH(s, &sensors, list) 1514 if (s->num == num) 1515 break; 1516 1517 return (sysctl_rdstruct(oldp, oldlenp, newp, s, sizeof(struct sensor))); 1518 } 1519