1 /* $NetBSD: kern_sysctl.c,v 1.108 2002/05/14 02:58:32 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Mike Karels at Berkeley Software Design, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95 39 */ 40 41 /* 42 * sysctl system call. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: kern_sysctl.c,v 1.108 2002/05/14 02:58:32 matt Exp $"); 47 48 #include "opt_ddb.h" 49 #include "opt_insecure.h" 50 #include "opt_defcorename.h" 51 #include "opt_pipe.h" 52 #include "opt_sysv.h" 53 #include "pty.h" 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/kernel.h> 58 #include <sys/buf.h> 59 #include <sys/device.h> 60 #include <sys/disklabel.h> 61 #include <sys/dkstat.h> 62 #include <sys/exec.h> 63 #include <sys/file.h> 64 #include <sys/ioctl.h> 65 #include <sys/malloc.h> 66 #include <sys/mount.h> 67 #include <sys/msgbuf.h> 68 #include <sys/pool.h> 69 #include <sys/proc.h> 70 #include <sys/resource.h> 71 #include <sys/resourcevar.h> 72 #include <sys/syscallargs.h> 73 #include <sys/tty.h> 74 #include <sys/unistd.h> 75 #include <sys/vnode.h> 76 #include <sys/socketvar.h> 77 #define __SYSCTL_PRIVATE 78 #include <sys/sysctl.h> 79 #include <sys/lock.h> 80 #include <sys/namei.h> 81 82 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 83 #include <sys/ipc.h> 84 #endif 85 #ifdef SYSVMSG 86 #include <sys/msg.h> 87 #endif 88 #ifdef SYSVSEM 89 #include <sys/sem.h> 90 #endif 91 #ifdef SYSVSHM 92 #include <sys/shm.h> 93 #endif 94 95 #include <dev/cons.h> 96 97 #if defined(DDB) 98 #include <ddb/ddbvar.h> 99 #endif 100 101 #ifndef PIPE_SOCKETPAIR 102 #include <sys/pipe.h> 103 #endif 104 105 #define PTRTOINT64(foo) ((u_int64_t)(uintptr_t)(foo)) 106 107 static int sysctl_file(void *, size_t *); 108 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 109 static int sysctl_sysvipc(int *, u_int, void *, size_t *); 110 #endif 111 static int sysctl_msgbuf(void *, size_t *); 112 static int sysctl_doeproc(int *, u_int, void *, size_t *); 113 static int sysctl_dotkstat(int *, u_int, void *, size_t *, void *); 114 #ifdef MULTIPROCESSOR 115 static int sysctl_docptime(void *, size_t *, void *); 116 static int sysctl_ncpus(void); 117 #endif 118 static void fill_kproc2(struct proc *, struct kinfo_proc2 *); 119 static int sysctl_procargs(int *, u_int, void *, size_t *, struct proc *); 120 #if NPTY > 0 121 static int sysctl_pty(void *, size_t *, void *, size_t); 122 #endif 123 124 /* 125 * The `sysctl_memlock' is intended to keep too many processes from 126 * locking down memory by doing sysctls at once. Whether or not this 127 * is really a good idea to worry about it probably a subject of some 128 * debate. 129 */ 130 struct lock sysctl_memlock; 131 132 void 133 sysctl_init(void) 134 { 135 136 lockinit(&sysctl_memlock, PRIBIO|PCATCH, "sysctl", 0, 0); 137 } 138 139 int 140 sys___sysctl(struct proc *p, void *v, register_t *retval) 141 { 142 struct sys___sysctl_args /* { 143 syscallarg(int *) name; 144 syscallarg(u_int) namelen; 145 syscallarg(void *) old; 146 syscallarg(size_t *) oldlenp; 147 syscallarg(void *) new; 148 syscallarg(size_t) newlen; 149 } */ *uap = v; 150 int error; 151 size_t savelen = 0, oldlen = 0; 152 sysctlfn *fn; 153 int name[CTL_MAXNAME]; 154 size_t *oldlenp; 155 156 /* 157 * all top-level sysctl names are non-terminal 158 */ 159 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2) 160 return (EINVAL); 161 error = copyin(SCARG(uap, name), &name, 162 SCARG(uap, namelen) * sizeof(int)); 163 if (error) 164 return (error); 165 166 /* 167 * For all but CTL_PROC, must be root to change a value. 168 * For CTL_PROC, must be root, or owner of the proc (and not suid), 169 * this is checked in proc_sysctl() (once we know the targer proc). 170 */ 171 if (SCARG(uap, new) != NULL && name[0] != CTL_PROC && 172 (error = suser(p->p_ucred, &p->p_acflag))) 173 return error; 174 175 switch (name[0]) { 176 case CTL_KERN: 177 fn = kern_sysctl; 178 break; 179 case CTL_HW: 180 fn = hw_sysctl; 181 break; 182 case CTL_VM: 183 fn = uvm_sysctl; 184 break; 185 case CTL_NET: 186 fn = net_sysctl; 187 break; 188 case CTL_VFS: 189 fn = vfs_sysctl; 190 break; 191 case CTL_MACHDEP: 192 fn = cpu_sysctl; 193 break; 194 #ifdef DEBUG 195 case CTL_DEBUG: 196 fn = debug_sysctl; 197 break; 198 #endif 199 #ifdef DDB 200 case CTL_DDB: 201 fn = ddb_sysctl; 202 break; 203 #endif 204 case CTL_PROC: 205 fn = proc_sysctl; 206 break; 207 208 case CTL_EMUL: 209 fn = emul_sysctl; 210 break; 211 default: 212 return (EOPNOTSUPP); 213 } 214 215 /* 216 * XXX Hey, we wire `old', but what about `new'? 217 */ 218 219 oldlenp = SCARG(uap, oldlenp); 220 if (oldlenp) { 221 if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen)))) 222 return (error); 223 oldlenp = &oldlen; 224 } 225 if (SCARG(uap, old) != NULL) { 226 error = lockmgr(&sysctl_memlock, LK_EXCLUSIVE, NULL); 227 if (error) 228 return (error); 229 error = uvm_vslock(p, SCARG(uap, old), oldlen, VM_PROT_WRITE); 230 if (error) { 231 (void) lockmgr(&sysctl_memlock, LK_RELEASE, NULL); 232 return error; 233 } 234 savelen = oldlen; 235 } 236 error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old), 237 oldlenp, SCARG(uap, new), SCARG(uap, newlen), p); 238 if (SCARG(uap, old) != NULL) { 239 uvm_vsunlock(p, SCARG(uap, old), savelen); 240 (void) lockmgr(&sysctl_memlock, LK_RELEASE, NULL); 241 } 242 if (error) 243 return (error); 244 if (SCARG(uap, oldlenp)) 245 error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen)); 246 return (error); 247 } 248 249 /* 250 * Attributes stored in the kernel. 251 */ 252 char hostname[MAXHOSTNAMELEN]; 253 int hostnamelen; 254 255 char domainname[MAXHOSTNAMELEN]; 256 int domainnamelen; 257 258 long hostid; 259 260 #ifdef INSECURE 261 int securelevel = -1; 262 #else 263 int securelevel = 0; 264 #endif 265 266 #ifndef DEFCORENAME 267 #define DEFCORENAME "%n.core" 268 #endif 269 char defcorename[MAXPATHLEN] = DEFCORENAME; 270 int defcorenamelen = sizeof(DEFCORENAME); 271 272 extern int kern_logsigexit; 273 extern fixpt_t ccpu; 274 275 #ifndef MULTIPROCESSOR 276 #define sysctl_ncpus() 1 277 #endif 278 279 #ifdef MULTIPROCESSOR 280 281 #ifndef CPU_INFO_FOREACH 282 #define CPU_INFO_ITERATOR int 283 #define CPU_INFO_FOREACH(cii, ci) cii = 0, ci = curcpu(); ci != NULL; ci = NULL 284 #endif 285 286 static int 287 sysctl_docptime(void *oldp, size_t *oldlenp, void *newp) 288 { 289 u_int64_t cp_time[CPUSTATES]; 290 int i; 291 struct cpu_info *ci; 292 CPU_INFO_ITERATOR cii; 293 294 for (i=0; i<CPUSTATES; i++) 295 cp_time[i] = 0; 296 297 for (CPU_INFO_FOREACH(cii, ci)) { 298 for (i=0; i<CPUSTATES; i++) 299 cp_time[i] += ci->ci_schedstate.spc_cp_time[i]; 300 } 301 return (sysctl_rdstruct(oldp, oldlenp, newp, 302 cp_time, sizeof(cp_time))); 303 } 304 305 static int 306 sysctl_ncpus(void) 307 { 308 struct cpu_info *ci; 309 CPU_INFO_ITERATOR cii; 310 311 int ncpus = 0; 312 for (CPU_INFO_FOREACH(cii, ci)) 313 ncpus++; 314 return ncpus; 315 } 316 317 #endif 318 319 /* 320 * kernel related system variables. 321 */ 322 int 323 kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 324 void *newp, size_t newlen, struct proc *p) 325 { 326 int error, level, inthostid; 327 int old_autonicetime; 328 int old_vnodes; 329 dev_t consdev; 330 331 /* All sysctl names at this level, except for a few, are terminal. */ 332 switch (name[0]) { 333 case KERN_PROC: 334 case KERN_PROC2: 335 case KERN_PROF: 336 case KERN_MBUF: 337 case KERN_PROC_ARGS: 338 case KERN_SYSVIPC_INFO: 339 case KERN_PIPE: 340 case KERN_TKSTAT: 341 /* Not terminal. */ 342 break; 343 default: 344 if (namelen != 1) 345 return (ENOTDIR); /* overloaded */ 346 } 347 348 switch (name[0]) { 349 case KERN_OSTYPE: 350 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 351 case KERN_OSRELEASE: 352 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 353 case KERN_OSREV: 354 return (sysctl_rdint(oldp, oldlenp, newp, __NetBSD_Version__)); 355 case KERN_VERSION: 356 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 357 case KERN_MAXVNODES: 358 old_vnodes = desiredvnodes; 359 error = sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes); 360 if (newp && !error) { 361 if (old_vnodes > desiredvnodes) { 362 desiredvnodes = old_vnodes; 363 return (EINVAL); 364 } 365 vfs_reinit(); 366 nchreinit(); 367 } 368 return (error); 369 case KERN_MAXPROC: 370 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 371 case KERN_MAXFILES: 372 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 373 case KERN_ARGMAX: 374 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 375 case KERN_SECURELVL: 376 level = securelevel; 377 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 378 newp == NULL) 379 return (error); 380 if (level < securelevel && p->p_pid != 1) 381 return (EPERM); 382 securelevel = level; 383 return (0); 384 case KERN_HOSTNAME: 385 error = sysctl_string(oldp, oldlenp, newp, newlen, 386 hostname, sizeof(hostname)); 387 if (newp && !error) 388 hostnamelen = newlen; 389 return (error); 390 case KERN_DOMAINNAME: 391 error = sysctl_string(oldp, oldlenp, newp, newlen, 392 domainname, sizeof(domainname)); 393 if (newp && !error) 394 domainnamelen = newlen; 395 return (error); 396 case KERN_HOSTID: 397 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 398 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 399 if (newp && !error) 400 hostid = inthostid; 401 return (error); 402 case KERN_CLOCKRATE: 403 return (sysctl_clockrate(oldp, oldlenp)); 404 case KERN_BOOTTIME: 405 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 406 sizeof(struct timeval))); 407 case KERN_VNODE: 408 return (sysctl_vnode(oldp, oldlenp, p)); 409 case KERN_PROC: 410 case KERN_PROC2: 411 return (sysctl_doeproc(name, namelen, oldp, oldlenp)); 412 case KERN_PROC_ARGS: 413 return (sysctl_procargs(name + 1, namelen - 1, 414 oldp, oldlenp, p)); 415 case KERN_FILE: 416 return (sysctl_file(oldp, oldlenp)); 417 #ifdef GPROF 418 case KERN_PROF: 419 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 420 newp, newlen)); 421 #endif 422 case KERN_POSIX1: 423 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 424 case KERN_NGROUPS: 425 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 426 case KERN_JOB_CONTROL: 427 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 428 case KERN_SAVED_IDS: 429 #ifdef _POSIX_SAVED_IDS 430 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 431 #else 432 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 433 #endif 434 case KERN_MAXPARTITIONS: 435 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 436 case KERN_RAWPARTITION: 437 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 438 #ifdef NTP 439 case KERN_NTPTIME: 440 return (sysctl_ntptime(oldp, oldlenp)); 441 #endif 442 case KERN_AUTONICETIME: 443 old_autonicetime = autonicetime; 444 error = sysctl_int(oldp, oldlenp, newp, newlen, &autonicetime); 445 if (autonicetime < 0) 446 autonicetime = old_autonicetime; 447 return (error); 448 case KERN_AUTONICEVAL: 449 error = sysctl_int(oldp, oldlenp, newp, newlen, &autoniceval); 450 if (autoniceval < PRIO_MIN) 451 autoniceval = PRIO_MIN; 452 if (autoniceval > PRIO_MAX) 453 autoniceval = PRIO_MAX; 454 return (error); 455 case KERN_RTC_OFFSET: 456 return (sysctl_rdint(oldp, oldlenp, newp, rtc_offset)); 457 case KERN_ROOT_DEVICE: 458 return (sysctl_rdstring(oldp, oldlenp, newp, 459 root_device->dv_xname)); 460 case KERN_MSGBUFSIZE: 461 /* 462 * deal with cases where the message buffer has 463 * become corrupted. 464 */ 465 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 466 msgbufenabled = 0; 467 return (ENXIO); 468 } 469 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 470 case KERN_FSYNC: 471 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 472 case KERN_SYSVMSG: 473 #ifdef SYSVMSG 474 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 475 #else 476 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 477 #endif 478 case KERN_SYSVSEM: 479 #ifdef SYSVSEM 480 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 481 #else 482 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 483 #endif 484 case KERN_SYSVSHM: 485 #ifdef SYSVSHM 486 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 487 #else 488 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 489 #endif 490 case KERN_DEFCORENAME: 491 if (newp && newlen < 1) 492 return (EINVAL); 493 error = sysctl_string(oldp, oldlenp, newp, newlen, 494 defcorename, sizeof(defcorename)); 495 if (newp && !error) 496 defcorenamelen = newlen; 497 return (error); 498 case KERN_SYNCHRONIZED_IO: 499 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 500 case KERN_IOV_MAX: 501 return (sysctl_rdint(oldp, oldlenp, newp, IOV_MAX)); 502 case KERN_MBUF: 503 return (sysctl_dombuf(name + 1, namelen - 1, oldp, oldlenp, 504 newp, newlen)); 505 case KERN_MAPPED_FILES: 506 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 507 case KERN_MEMLOCK: 508 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 509 case KERN_MEMLOCK_RANGE: 510 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 511 case KERN_MEMORY_PROTECTION: 512 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 513 case KERN_LOGIN_NAME_MAX: 514 return (sysctl_rdint(oldp, oldlenp, newp, LOGIN_NAME_MAX)); 515 case KERN_LOGSIGEXIT: 516 return (sysctl_int(oldp, oldlenp, newp, newlen, 517 &kern_logsigexit)); 518 case KERN_FSCALE: 519 return (sysctl_rdint(oldp, oldlenp, newp, FSCALE)); 520 case KERN_CCPU: 521 return (sysctl_rdint(oldp, oldlenp, newp, ccpu)); 522 case KERN_CP_TIME: 523 #ifndef MULTIPROCESSOR 524 return (sysctl_rdstruct(oldp, oldlenp, newp, 525 curcpu()->ci_schedstate.spc_cp_time, 526 sizeof(curcpu()->ci_schedstate.spc_cp_time))); 527 #else 528 return (sysctl_docptime(oldp, oldlenp, newp)); 529 #endif 530 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 531 case KERN_SYSVIPC_INFO: 532 return (sysctl_sysvipc(name + 1, namelen - 1, oldp, oldlenp)); 533 #endif 534 case KERN_MSGBUF: 535 return (sysctl_msgbuf(oldp, oldlenp)); 536 case KERN_CONSDEV: 537 if (cn_tab != NULL) 538 consdev = cn_tab->cn_dev; 539 else 540 consdev = NODEV; 541 return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, 542 sizeof consdev)); 543 #if NPTY > 0 544 case KERN_MAXPTYS: 545 return sysctl_pty(oldp, oldlenp, newp, newlen); 546 #endif 547 #ifndef PIPE_SOCKETPAIR 548 case KERN_PIPE: 549 return (sysctl_dopipe(name + 1, namelen - 1, oldp, oldlenp, 550 newp, newlen)); 551 #endif 552 case KERN_MAXPHYS: 553 return (sysctl_rdint(oldp, oldlenp, newp, MAXPHYS)); 554 case KERN_SBMAX: 555 { 556 int new_sbmax = sb_max; 557 558 error = sysctl_int(oldp, oldlenp, newp, newlen, &new_sbmax); 559 if (newp && !error) { 560 if (new_sbmax < (16 * 1024)) /* sanity */ 561 return (EINVAL); 562 sb_max = new_sbmax; 563 } 564 return (error); 565 } 566 case KERN_TKSTAT: 567 return (sysctl_dotkstat(name + 1, namelen - 1, oldp, oldlenp, 568 newp)); 569 case KERN_MONOTONIC_CLOCK: /* XXX _POSIX_VERSION */ 570 return (sysctl_rdint(oldp, oldlenp, newp, 200112)); 571 default: 572 return (EOPNOTSUPP); 573 } 574 /* NOTREACHED */ 575 } 576 577 /* 578 * hardware related system variables. 579 */ 580 int 581 hw_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 582 void *newp, size_t newlen, struct proc *p) 583 { 584 585 /* All sysctl names at this level, except for a few, are terminal. */ 586 switch (name[0]) { 587 case HW_DISKSTATS: 588 /* Not terminal. */ 589 break; 590 default: 591 if (namelen != 1) 592 return (ENOTDIR); /* overloaded */ 593 } 594 595 switch (name[0]) { 596 case HW_MACHINE: 597 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 598 case HW_MACHINE_ARCH: 599 return (sysctl_rdstring(oldp, oldlenp, newp, machine_arch)); 600 case HW_MODEL: 601 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 602 case HW_NCPU: 603 return (sysctl_rdint(oldp, oldlenp, newp, sysctl_ncpus())); 604 case HW_BYTEORDER: 605 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 606 case HW_PHYSMEM: 607 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 608 case HW_USERMEM: 609 return (sysctl_rdint(oldp, oldlenp, newp, 610 ctob(physmem - uvmexp.wired))); 611 case HW_PAGESIZE: 612 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 613 case HW_ALIGNBYTES: 614 return (sysctl_rdint(oldp, oldlenp, newp, ALIGNBYTES)); 615 case HW_DISKNAMES: 616 return (sysctl_disknames(oldp, oldlenp)); 617 case HW_DISKSTATS: 618 return (sysctl_diskstats(name + 1, namelen - 1, oldp, oldlenp)); 619 case HW_CNMAGIC: { 620 char magic[CNS_LEN]; 621 int error; 622 623 if (oldp) 624 cn_get_magic(magic, CNS_LEN); 625 error = sysctl_string(oldp, oldlenp, newp, newlen, 626 magic, sizeof(magic)); 627 if (newp && !error) { 628 error = cn_set_magic(magic); 629 } 630 return (error); 631 } 632 default: 633 return (EOPNOTSUPP); 634 } 635 /* NOTREACHED */ 636 } 637 638 #ifdef DEBUG 639 /* 640 * Debugging related system variables. 641 */ 642 struct ctldebug /* debug0, */ /* debug1, */ debug2, debug3, debug4; 643 struct ctldebug debug5, debug6, debug7, debug8, debug9; 644 struct ctldebug debug10, debug11, debug12, debug13, debug14; 645 struct ctldebug debug15, debug16, debug17, debug18, debug19; 646 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 647 &debug0, &debug1, &debug2, &debug3, &debug4, 648 &debug5, &debug6, &debug7, &debug8, &debug9, 649 &debug10, &debug11, &debug12, &debug13, &debug14, 650 &debug15, &debug16, &debug17, &debug18, &debug19, 651 }; 652 653 int 654 debug_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 655 void *newp, size_t newlen, struct proc *p) 656 { 657 struct ctldebug *cdp; 658 659 /* all sysctl names at this level are name and field */ 660 if (namelen != 2) 661 return (ENOTDIR); /* overloaded */ 662 if (name[0] >= CTL_DEBUG_MAXID) 663 return (EOPNOTSUPP); 664 cdp = debugvars[name[0]]; 665 if (cdp->debugname == 0) 666 return (EOPNOTSUPP); 667 switch (name[1]) { 668 case CTL_DEBUG_NAME: 669 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 670 case CTL_DEBUG_VALUE: 671 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 672 default: 673 return (EOPNOTSUPP); 674 } 675 /* NOTREACHED */ 676 } 677 #endif /* DEBUG */ 678 679 int 680 proc_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 681 void *newp, size_t newlen, struct proc *p) 682 { 683 struct proc *ptmp = NULL; 684 const struct proclist_desc *pd; 685 int error = 0; 686 struct rlimit alim; 687 struct plimit *newplim; 688 char *tmps = NULL; 689 int i, curlen, len; 690 691 if (namelen < 2) 692 return EINVAL; 693 694 if (name[0] == PROC_CURPROC) { 695 ptmp = p; 696 } else { 697 proclist_lock_read(); 698 for (pd = proclists; pd->pd_list != NULL; pd++) { 699 for (ptmp = LIST_FIRST(pd->pd_list); ptmp != NULL; 700 ptmp = LIST_NEXT(ptmp, p_list)) { 701 /* Skip embryonic processes. */ 702 if (ptmp->p_stat == SIDL) 703 continue; 704 if (ptmp->p_pid == (pid_t)name[0]) 705 break; 706 } 707 if (ptmp != NULL) 708 break; 709 } 710 proclist_unlock_read(); 711 if (ptmp == NULL) 712 return(ESRCH); 713 if (p->p_ucred->cr_uid != 0) { 714 if(p->p_cred->p_ruid != ptmp->p_cred->p_ruid || 715 p->p_cred->p_ruid != ptmp->p_cred->p_svuid) 716 return EPERM; 717 if (ptmp->p_cred->p_rgid != ptmp->p_cred->p_svgid) 718 return EPERM; /* sgid proc */ 719 for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 720 if (p->p_ucred->cr_groups[i] == 721 ptmp->p_cred->p_rgid) 722 break; 723 } 724 if (i == p->p_ucred->cr_ngroups) 725 return EPERM; 726 } 727 } 728 if (name[1] == PROC_PID_CORENAME) { 729 if (namelen != 2) 730 return EINVAL; 731 /* 732 * Can't use sysctl_string() here because we may malloc a new 733 * area during the process, so we have to do it by hand. 734 */ 735 curlen = strlen(ptmp->p_limit->pl_corename) + 1; 736 if (oldlenp && *oldlenp < curlen) { 737 if (!oldp) 738 *oldlenp = curlen; 739 return (ENOMEM); 740 } 741 if (newp) { 742 if (securelevel > 2) 743 return EPERM; 744 if (newlen > MAXPATHLEN) 745 return ENAMETOOLONG; 746 tmps = malloc(newlen + 1, M_TEMP, M_WAITOK); 747 if (tmps == NULL) 748 return ENOMEM; 749 error = copyin(newp, tmps, newlen + 1); 750 tmps[newlen] = '\0'; 751 if (error) 752 goto cleanup; 753 /* Enforce to be either 'core' for end with '.core' */ 754 if (newlen < 4) { /* c.o.r.e */ 755 error = EINVAL; 756 goto cleanup; 757 } 758 len = newlen - 4; 759 if (len > 0) { 760 if (tmps[len - 1] != '.' && 761 tmps[len - 1] != '/') { 762 error = EINVAL; 763 goto cleanup; 764 } 765 } 766 if (strcmp(&tmps[len], "core") != 0) { 767 error = EINVAL; 768 goto cleanup; 769 } 770 } 771 if (oldp && oldlenp) { 772 *oldlenp = curlen; 773 error = copyout(ptmp->p_limit->pl_corename, oldp, 774 curlen); 775 } 776 if (newp && error == 0) { 777 /* if the 2 strings are identical, don't limcopy() */ 778 if (strcmp(tmps, ptmp->p_limit->pl_corename) == 0) { 779 error = 0; 780 goto cleanup; 781 } 782 if (ptmp->p_limit->p_refcnt > 1 && 783 (ptmp->p_limit->p_lflags & PL_SHAREMOD) == 0) { 784 newplim = limcopy(ptmp->p_limit); 785 limfree(ptmp->p_limit); 786 ptmp->p_limit = newplim; 787 } 788 if (ptmp->p_limit->pl_corename != defcorename) { 789 free(ptmp->p_limit->pl_corename, M_TEMP); 790 } 791 ptmp->p_limit->pl_corename = tmps; 792 return (0); 793 } 794 cleanup: 795 if (tmps) 796 free(tmps, M_TEMP); 797 return (error); 798 } 799 if (name[1] == PROC_PID_LIMIT) { 800 if (namelen != 4 || name[2] >= PROC_PID_LIMIT_MAXID) 801 return EINVAL; 802 memcpy(&alim, &ptmp->p_rlimit[name[2] - 1], sizeof(alim)); 803 if (name[3] == PROC_PID_LIMIT_TYPE_HARD) 804 error = sysctl_quad(oldp, oldlenp, newp, newlen, 805 &alim.rlim_max); 806 else if (name[3] == PROC_PID_LIMIT_TYPE_SOFT) 807 error = sysctl_quad(oldp, oldlenp, newp, newlen, 808 &alim.rlim_cur); 809 else 810 error = EINVAL; 811 812 if (error) 813 return error; 814 815 if (newp) 816 error = dosetrlimit(ptmp, p->p_cred, 817 name[2] - 1, &alim); 818 return error; 819 } 820 return (EINVAL); 821 } 822 823 int 824 emul_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 825 void *newp, size_t newlen, struct proc *p) 826 { 827 static struct { 828 const char *name; 829 int type; 830 } emulations[] = CTL_EMUL_NAMES; 831 const struct emul *e; 832 const char *ename; 833 #ifdef LKM 834 extern struct lock exec_lock; /* XXX */ 835 int error; 836 #else 837 extern int nexecs_builtin; 838 extern const struct execsw execsw_builtin[]; 839 int i; 840 #endif 841 842 /* all sysctl names at this level are name and field */ 843 if (namelen < 2) 844 return (ENOTDIR); /* overloaded */ 845 846 if ((u_int) name[0] >= EMUL_MAXID || name[0] == 0) 847 return (EOPNOTSUPP); 848 849 ename = emulations[name[0]].name; 850 851 #ifdef LKM 852 lockmgr(&exec_lock, LK_SHARED, NULL); 853 if ((e = emul_search(ename))) { 854 error = (*e->e_sysctl)(name + 1, namelen - 1, oldp, oldlenp, 855 newp, newlen, p); 856 } else 857 error = EOPNOTSUPP; 858 lockmgr(&exec_lock, LK_RELEASE, NULL); 859 860 return (error); 861 #else 862 for (i = 0; i < nexecs_builtin; i++) { 863 e = execsw_builtin[i].es_emul; 864 if (e == NULL || strcmp(ename, e->e_name) != 0 || 865 e->e_sysctl != NULL) 866 continue; 867 868 return (*e->e_sysctl)(name + 1, namelen - 1, oldp, oldlenp, 869 newp, newlen, p); 870 } 871 872 return (EOPNOTSUPP); 873 #endif 874 } 875 /* 876 * Convenience macros. 877 */ 878 879 #define SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, len) \ 880 if (oldlenp) { \ 881 if (!oldp) \ 882 *oldlenp = len; \ 883 else { \ 884 if (*oldlenp < len) \ 885 return(ENOMEM); \ 886 *oldlenp = len; \ 887 error = copyout((caddr_t)valp, oldp, len); \ 888 } \ 889 } 890 891 #define SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, typ) \ 892 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, sizeof(typ)) 893 894 #define SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len) \ 895 if (newp && newlen != len) \ 896 return (EINVAL); 897 898 #define SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, typ) \ 899 SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, sizeof(typ)) 900 901 #define SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, len) \ 902 if (error == 0 && newp) \ 903 error = copyin(newp, valp, len); 904 905 #define SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, typ) \ 906 SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, sizeof(typ)) 907 908 #define SYSCTL_STRING_CORE(oldp, oldlenp, str) \ 909 if (oldlenp) { \ 910 len = strlen(str) + 1; \ 911 if (!oldp) \ 912 *oldlenp = len; \ 913 else { \ 914 if (*oldlenp < len) { \ 915 err2 = ENOMEM; \ 916 len = *oldlenp; \ 917 } else \ 918 *oldlenp = len; \ 919 error = copyout(str, oldp, len);\ 920 if (error == 0) \ 921 error = err2; \ 922 } \ 923 } 924 925 /* 926 * Validate parameters and get old / set new parameters 927 * for an integer-valued sysctl function. 928 */ 929 int 930 sysctl_int(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int *valp) 931 { 932 int error = 0; 933 934 SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, int) 935 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, int) 936 SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, int) 937 938 return (error); 939 } 940 941 942 /* 943 * As above, but read-only. 944 */ 945 int 946 sysctl_rdint(void *oldp, size_t *oldlenp, void *newp, int val) 947 { 948 int error = 0; 949 950 if (newp) 951 return (EPERM); 952 953 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, int) 954 955 return (error); 956 } 957 958 /* 959 * Validate parameters and get old / set new parameters 960 * for an quad-valued sysctl function. 961 */ 962 int 963 sysctl_quad(void *oldp, size_t *oldlenp, void *newp, size_t newlen, 964 quad_t *valp) 965 { 966 int error = 0; 967 968 SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, quad_t) 969 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, quad_t) 970 SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, quad_t) 971 972 return (error); 973 } 974 975 /* 976 * As above, but read-only. 977 */ 978 int 979 sysctl_rdquad(void *oldp, size_t *oldlenp, void *newp, quad_t val) 980 { 981 int error = 0; 982 983 if (newp) 984 return (EPERM); 985 986 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, quad_t) 987 988 return (error); 989 } 990 991 /* 992 * Validate parameters and get old / set new parameters 993 * for a string-valued sysctl function. 994 */ 995 int 996 sysctl_string(void *oldp, size_t *oldlenp, void *newp, size_t newlen, char *str, 997 int maxlen) 998 { 999 int len, error = 0, err2 = 0; 1000 1001 if (newp && newlen >= maxlen) 1002 return (EINVAL); 1003 1004 SYSCTL_STRING_CORE(oldp, oldlenp, str); 1005 1006 if (error == 0 && newp) { 1007 error = copyin(newp, str, newlen); 1008 str[newlen] = 0; 1009 } 1010 return (error); 1011 } 1012 1013 /* 1014 * As above, but read-only. 1015 */ 1016 int 1017 sysctl_rdstring(void *oldp, size_t *oldlenp, void *newp, const char *str) 1018 { 1019 int len, error = 0, err2 = 0; 1020 1021 if (newp) 1022 return (EPERM); 1023 1024 SYSCTL_STRING_CORE(oldp, oldlenp, str); 1025 1026 return (error); 1027 } 1028 1029 /* 1030 * Validate parameters and get old / set new parameters 1031 * for a structure oriented sysctl function. 1032 */ 1033 int 1034 sysctl_struct(void *oldp, size_t *oldlenp, void *newp, size_t newlen, void *sp, 1035 int len) 1036 { 1037 int error = 0; 1038 1039 SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len) 1040 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len) 1041 SYSCTL_SCALAR_NEWPCOP_LEN(newp, sp, len) 1042 1043 return (error); 1044 } 1045 1046 /* 1047 * Validate parameters and get old parameters 1048 * for a structure oriented sysctl function. 1049 */ 1050 int 1051 sysctl_rdstruct(void *oldp, size_t *oldlenp, void *newp, const void *sp, 1052 int len) 1053 { 1054 int error = 0; 1055 1056 if (newp) 1057 return (EPERM); 1058 1059 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len) 1060 1061 return (error); 1062 } 1063 1064 /* 1065 * As above, but can return a truncated result. 1066 */ 1067 int 1068 sysctl_rdminstruct(void *oldp, size_t *oldlenp, void *newp, const void *sp, 1069 int len) 1070 { 1071 int error = 0; 1072 1073 if (newp) 1074 return (EPERM); 1075 1076 len = min(*oldlenp, len); 1077 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len) 1078 1079 return (error); 1080 } 1081 1082 /* 1083 * Get file structures. 1084 */ 1085 static int 1086 sysctl_file(void *vwhere, size_t *sizep) 1087 { 1088 int buflen, error; 1089 struct file *fp; 1090 char *start, *where; 1091 1092 start = where = vwhere; 1093 buflen = *sizep; 1094 if (where == NULL) { 1095 /* 1096 * overestimate by 10 files 1097 */ 1098 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 1099 return (0); 1100 } 1101 1102 /* 1103 * first copyout filehead 1104 */ 1105 if (buflen < sizeof(filehead)) { 1106 *sizep = 0; 1107 return (0); 1108 } 1109 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 1110 if (error) 1111 return (error); 1112 buflen -= sizeof(filehead); 1113 where += sizeof(filehead); 1114 1115 /* 1116 * followed by an array of file structures 1117 */ 1118 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 1119 if (buflen < sizeof(struct file)) { 1120 *sizep = where - start; 1121 return (ENOMEM); 1122 } 1123 error = copyout((caddr_t)fp, where, sizeof(struct file)); 1124 if (error) 1125 return (error); 1126 buflen -= sizeof(struct file); 1127 where += sizeof(struct file); 1128 } 1129 *sizep = where - start; 1130 return (0); 1131 } 1132 1133 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 1134 #define FILL_PERM(src, dst) do { \ 1135 (dst)._key = (src)._key; \ 1136 (dst).uid = (src).uid; \ 1137 (dst).gid = (src).gid; \ 1138 (dst).cuid = (src).cuid; \ 1139 (dst).cgid = (src).cgid; \ 1140 (dst).mode = (src).mode; \ 1141 (dst)._seq = (src)._seq; \ 1142 } while (0); 1143 #define FILL_MSG(src, dst) do { \ 1144 FILL_PERM((src).msg_perm, (dst).msg_perm); \ 1145 (dst).msg_qnum = (src).msg_qnum; \ 1146 (dst).msg_qbytes = (src).msg_qbytes; \ 1147 (dst)._msg_cbytes = (src)._msg_cbytes; \ 1148 (dst).msg_lspid = (src).msg_lspid; \ 1149 (dst).msg_lrpid = (src).msg_lrpid; \ 1150 (dst).msg_stime = (src).msg_stime; \ 1151 (dst).msg_rtime = (src).msg_rtime; \ 1152 (dst).msg_ctime = (src).msg_ctime; \ 1153 } while (0) 1154 #define FILL_SEM(src, dst) do { \ 1155 FILL_PERM((src).sem_perm, (dst).sem_perm); \ 1156 (dst).sem_nsems = (src).sem_nsems; \ 1157 (dst).sem_otime = (src).sem_otime; \ 1158 (dst).sem_ctime = (src).sem_ctime; \ 1159 } while (0) 1160 #define FILL_SHM(src, dst) do { \ 1161 FILL_PERM((src).shm_perm, (dst).shm_perm); \ 1162 (dst).shm_segsz = (src).shm_segsz; \ 1163 (dst).shm_lpid = (src).shm_lpid; \ 1164 (dst).shm_cpid = (src).shm_cpid; \ 1165 (dst).shm_atime = (src).shm_atime; \ 1166 (dst).shm_dtime = (src).shm_dtime; \ 1167 (dst).shm_ctime = (src).shm_ctime; \ 1168 (dst).shm_nattch = (src).shm_nattch; \ 1169 } while (0) 1170 1171 static int 1172 sysctl_sysvipc(int *name, u_int namelen, void *where, size_t *sizep) 1173 { 1174 #ifdef SYSVMSG 1175 struct msg_sysctl_info *msgsi; 1176 #endif 1177 #ifdef SYSVSEM 1178 struct sem_sysctl_info *semsi; 1179 #endif 1180 #ifdef SYSVSHM 1181 struct shm_sysctl_info *shmsi; 1182 #endif 1183 size_t infosize, dssize, tsize, buflen; 1184 void *buf = NULL; 1185 char *start; 1186 int32_t nds; 1187 int i, error, ret; 1188 1189 if (namelen != 1) 1190 return (EINVAL); 1191 1192 start = where; 1193 buflen = *sizep; 1194 1195 switch (*name) { 1196 case KERN_SYSVIPC_MSG_INFO: 1197 #ifdef SYSVMSG 1198 infosize = sizeof(msgsi->msginfo); 1199 nds = msginfo.msgmni; 1200 dssize = sizeof(msgsi->msgids[0]); 1201 break; 1202 #else 1203 return (EINVAL); 1204 #endif 1205 case KERN_SYSVIPC_SEM_INFO: 1206 #ifdef SYSVSEM 1207 infosize = sizeof(semsi->seminfo); 1208 nds = seminfo.semmni; 1209 dssize = sizeof(semsi->semids[0]); 1210 break; 1211 #else 1212 return (EINVAL); 1213 #endif 1214 case KERN_SYSVIPC_SHM_INFO: 1215 #ifdef SYSVSHM 1216 infosize = sizeof(shmsi->shminfo); 1217 nds = shminfo.shmmni; 1218 dssize = sizeof(shmsi->shmids[0]); 1219 break; 1220 #else 1221 return (EINVAL); 1222 #endif 1223 default: 1224 return (EINVAL); 1225 } 1226 /* 1227 * Round infosize to 64 bit boundary if requesting more than just 1228 * the info structure or getting the total data size. 1229 */ 1230 if (where == NULL || *sizep > infosize) 1231 infosize = ((infosize + 7) / 8) * 8; 1232 tsize = infosize + nds * dssize; 1233 1234 /* Return just the total size required. */ 1235 if (where == NULL) { 1236 *sizep = tsize; 1237 return (0); 1238 } 1239 1240 /* Not enough room for even the info struct. */ 1241 if (buflen < infosize) { 1242 *sizep = 0; 1243 return (ENOMEM); 1244 } 1245 buf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK); 1246 memset(buf, 0, min(tsize, buflen)); 1247 1248 switch (*name) { 1249 #ifdef SYSVMSG 1250 case KERN_SYSVIPC_MSG_INFO: 1251 msgsi = (struct msg_sysctl_info *)buf; 1252 msgsi->msginfo = msginfo; 1253 break; 1254 #endif 1255 #ifdef SYSVSEM 1256 case KERN_SYSVIPC_SEM_INFO: 1257 semsi = (struct sem_sysctl_info *)buf; 1258 semsi->seminfo = seminfo; 1259 break; 1260 #endif 1261 #ifdef SYSVSHM 1262 case KERN_SYSVIPC_SHM_INFO: 1263 shmsi = (struct shm_sysctl_info *)buf; 1264 shmsi->shminfo = shminfo; 1265 break; 1266 #endif 1267 } 1268 buflen -= infosize; 1269 1270 ret = 0; 1271 if (buflen > 0) { 1272 /* Fill in the IPC data structures. */ 1273 for (i = 0; i < nds; i++) { 1274 if (buflen < dssize) { 1275 ret = ENOMEM; 1276 break; 1277 } 1278 switch (*name) { 1279 #ifdef SYSVMSG 1280 case KERN_SYSVIPC_MSG_INFO: 1281 FILL_MSG(msqids[i], msgsi->msgids[i]); 1282 break; 1283 #endif 1284 #ifdef SYSVSEM 1285 case KERN_SYSVIPC_SEM_INFO: 1286 FILL_SEM(sema[i], semsi->semids[i]); 1287 break; 1288 #endif 1289 #ifdef SYSVSHM 1290 case KERN_SYSVIPC_SHM_INFO: 1291 FILL_SHM(shmsegs[i], shmsi->shmids[i]); 1292 break; 1293 #endif 1294 } 1295 buflen -= dssize; 1296 } 1297 } 1298 *sizep -= buflen; 1299 error = copyout(buf, start, *sizep); 1300 /* If copyout succeeded, use return code set earlier. */ 1301 if (error == 0) 1302 error = ret; 1303 if (buf) 1304 free(buf, M_TEMP); 1305 return (error); 1306 } 1307 #endif /* SYSVMSG || SYSVSEM || SYSVSHM */ 1308 1309 static int 1310 sysctl_msgbuf(void *vwhere, size_t *sizep) 1311 { 1312 char *where = vwhere; 1313 size_t len, maxlen = *sizep; 1314 long beg, end; 1315 int error; 1316 1317 /* 1318 * deal with cases where the message buffer has 1319 * become corrupted. 1320 */ 1321 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 1322 msgbufenabled = 0; 1323 return (ENXIO); 1324 } 1325 1326 if (where == NULL) { 1327 /* always return full buffer size */ 1328 *sizep = msgbufp->msg_bufs; 1329 return (0); 1330 } 1331 1332 error = 0; 1333 maxlen = min(msgbufp->msg_bufs, maxlen); 1334 1335 /* 1336 * First, copy from the write pointer to the end of 1337 * message buffer. 1338 */ 1339 beg = msgbufp->msg_bufx; 1340 end = msgbufp->msg_bufs; 1341 while (maxlen > 0) { 1342 len = min(end - beg, maxlen); 1343 if (len == 0) 1344 break; 1345 error = copyout(&msgbufp->msg_bufc[beg], where, len); 1346 if (error) 1347 break; 1348 where += len; 1349 maxlen -= len; 1350 1351 /* 1352 * ... then, copy from the beginning of message buffer to 1353 * the write pointer. 1354 */ 1355 beg = 0; 1356 end = msgbufp->msg_bufx; 1357 } 1358 return (error); 1359 } 1360 1361 /* 1362 * try over estimating by 5 procs 1363 */ 1364 #define KERN_PROCSLOP (5 * sizeof(struct kinfo_proc)) 1365 1366 static int 1367 sysctl_doeproc(int *name, u_int namelen, void *vwhere, size_t *sizep) 1368 { 1369 struct eproc eproc; 1370 struct kinfo_proc2 kproc2; 1371 struct kinfo_proc *dp; 1372 struct proc *p; 1373 const struct proclist_desc *pd; 1374 char *where, *dp2; 1375 int type, op, arg, elem_size, elem_count; 1376 int buflen, needed, error; 1377 1378 dp = vwhere; 1379 dp2 = where = vwhere; 1380 buflen = where != NULL ? *sizep : 0; 1381 error = needed = 0; 1382 type = name[0]; 1383 1384 if (type == KERN_PROC) { 1385 if (namelen != 3 && !(namelen == 2 && name[1] == KERN_PROC_ALL)) 1386 return (EINVAL); 1387 op = name[1]; 1388 if (op != KERN_PROC_ALL) 1389 arg = name[2]; 1390 } else { 1391 if (namelen != 5) 1392 return (EINVAL); 1393 op = name[1]; 1394 arg = name[2]; 1395 elem_size = name[3]; 1396 elem_count = name[4]; 1397 } 1398 1399 proclist_lock_read(); 1400 1401 pd = proclists; 1402 again: 1403 for (p = LIST_FIRST(pd->pd_list); p != NULL; p = LIST_NEXT(p, p_list)) { 1404 /* 1405 * Skip embryonic processes. 1406 */ 1407 if (p->p_stat == SIDL) 1408 continue; 1409 /* 1410 * TODO - make more efficient (see notes below). 1411 * do by session. 1412 */ 1413 switch (op) { 1414 1415 case KERN_PROC_PID: 1416 /* could do this with just a lookup */ 1417 if (p->p_pid != (pid_t)arg) 1418 continue; 1419 break; 1420 1421 case KERN_PROC_PGRP: 1422 /* could do this by traversing pgrp */ 1423 if (p->p_pgrp->pg_id != (pid_t)arg) 1424 continue; 1425 break; 1426 1427 case KERN_PROC_SESSION: 1428 if (p->p_session->s_sid != (pid_t)arg) 1429 continue; 1430 break; 1431 1432 case KERN_PROC_TTY: 1433 if (arg == KERN_PROC_TTY_REVOKE) { 1434 if ((p->p_flag & P_CONTROLT) == 0 || 1435 p->p_session->s_ttyp == NULL || 1436 p->p_session->s_ttyvp != NULL) 1437 continue; 1438 } else if ((p->p_flag & P_CONTROLT) == 0 || 1439 p->p_session->s_ttyp == NULL) { 1440 if ((dev_t)arg != KERN_PROC_TTY_NODEV) 1441 continue; 1442 } else if (p->p_session->s_ttyp->t_dev != (dev_t)arg) 1443 continue; 1444 break; 1445 1446 case KERN_PROC_UID: 1447 if (p->p_ucred->cr_uid != (uid_t)arg) 1448 continue; 1449 break; 1450 1451 case KERN_PROC_RUID: 1452 if (p->p_cred->p_ruid != (uid_t)arg) 1453 continue; 1454 break; 1455 1456 case KERN_PROC_GID: 1457 if (p->p_ucred->cr_gid != (uid_t)arg) 1458 continue; 1459 break; 1460 1461 case KERN_PROC_RGID: 1462 if (p->p_cred->p_rgid != (uid_t)arg) 1463 continue; 1464 break; 1465 1466 case KERN_PROC_ALL: 1467 /* allow everything */ 1468 break; 1469 1470 default: 1471 error = EINVAL; 1472 goto cleanup; 1473 } 1474 if (type == KERN_PROC) { 1475 if (buflen >= sizeof(struct kinfo_proc)) { 1476 fill_eproc(p, &eproc); 1477 error = copyout((caddr_t)p, &dp->kp_proc, 1478 sizeof(struct proc)); 1479 if (error) 1480 goto cleanup; 1481 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 1482 sizeof(eproc)); 1483 if (error) 1484 goto cleanup; 1485 dp++; 1486 buflen -= sizeof(struct kinfo_proc); 1487 } 1488 needed += sizeof(struct kinfo_proc); 1489 } else { /* KERN_PROC2 */ 1490 if (buflen >= elem_size && elem_count > 0) { 1491 fill_kproc2(p, &kproc2); 1492 /* 1493 * Copy out elem_size, but not larger than 1494 * the size of a struct kinfo_proc2. 1495 */ 1496 error = copyout(&kproc2, dp2, 1497 min(sizeof(kproc2), elem_size)); 1498 if (error) 1499 goto cleanup; 1500 dp2 += elem_size; 1501 buflen -= elem_size; 1502 elem_count--; 1503 } 1504 needed += elem_size; 1505 } 1506 } 1507 pd++; 1508 if (pd->pd_list != NULL) 1509 goto again; 1510 proclist_unlock_read(); 1511 1512 if (where != NULL) { 1513 if (type == KERN_PROC) 1514 *sizep = (caddr_t)dp - where; 1515 else 1516 *sizep = dp2 - where; 1517 if (needed > *sizep) 1518 return (ENOMEM); 1519 } else { 1520 needed += KERN_PROCSLOP; 1521 *sizep = needed; 1522 } 1523 return (0); 1524 cleanup: 1525 proclist_unlock_read(); 1526 return (error); 1527 } 1528 1529 /* 1530 * Fill in an eproc structure for the specified process. 1531 */ 1532 void 1533 fill_eproc(struct proc *p, struct eproc *ep) 1534 { 1535 struct tty *tp; 1536 1537 ep->e_paddr = p; 1538 ep->e_sess = p->p_session; 1539 ep->e_pcred = *p->p_cred; 1540 ep->e_ucred = *p->p_ucred; 1541 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 1542 ep->e_vm.vm_rssize = 0; 1543 ep->e_vm.vm_tsize = 0; 1544 ep->e_vm.vm_dsize = 0; 1545 ep->e_vm.vm_ssize = 0; 1546 /* ep->e_vm.vm_pmap = XXX; */ 1547 } else { 1548 struct vmspace *vm = p->p_vmspace; 1549 1550 ep->e_vm.vm_rssize = vm_resident_count(vm); 1551 ep->e_vm.vm_tsize = vm->vm_tsize; 1552 ep->e_vm.vm_dsize = vm->vm_dsize; 1553 ep->e_vm.vm_ssize = vm->vm_ssize; 1554 } 1555 if (p->p_pptr) 1556 ep->e_ppid = p->p_pptr->p_pid; 1557 else 1558 ep->e_ppid = 0; 1559 ep->e_pgid = p->p_pgrp->pg_id; 1560 ep->e_sid = ep->e_sess->s_sid; 1561 ep->e_jobc = p->p_pgrp->pg_jobc; 1562 if ((p->p_flag & P_CONTROLT) && 1563 (tp = ep->e_sess->s_ttyp)) { 1564 ep->e_tdev = tp->t_dev; 1565 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1566 ep->e_tsess = tp->t_session; 1567 } else 1568 ep->e_tdev = NODEV; 1569 if (p->p_wmesg) 1570 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 1571 ep->e_xsize = ep->e_xrssize = 0; 1572 ep->e_xccount = ep->e_xswrss = 0; 1573 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 1574 if (SESS_LEADER(p)) 1575 ep->e_flag |= EPROC_SLEADER; 1576 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME); 1577 } 1578 1579 /* 1580 * Fill in an eproc structure for the specified process. 1581 */ 1582 static void 1583 fill_kproc2(struct proc *p, struct kinfo_proc2 *ki) 1584 { 1585 struct tty *tp; 1586 1587 memset(ki, 0, sizeof(*ki)); 1588 1589 ki->p_forw = PTRTOINT64(p->p_forw); 1590 ki->p_back = PTRTOINT64(p->p_back); 1591 ki->p_paddr = PTRTOINT64(p); 1592 1593 ki->p_addr = PTRTOINT64(p->p_addr); 1594 ki->p_fd = PTRTOINT64(p->p_fd); 1595 ki->p_cwdi = PTRTOINT64(p->p_cwdi); 1596 ki->p_stats = PTRTOINT64(p->p_stats); 1597 ki->p_limit = PTRTOINT64(p->p_limit); 1598 ki->p_vmspace = PTRTOINT64(p->p_vmspace); 1599 ki->p_sigacts = PTRTOINT64(p->p_sigacts); 1600 ki->p_sess = PTRTOINT64(p->p_session); 1601 ki->p_tsess = 0; /* may be changed if controlling tty below */ 1602 ki->p_ru = PTRTOINT64(p->p_ru); 1603 1604 ki->p_eflag = 0; 1605 ki->p_exitsig = p->p_exitsig; 1606 ki->p_flag = p->p_flag; 1607 1608 ki->p_pid = p->p_pid; 1609 if (p->p_pptr) 1610 ki->p_ppid = p->p_pptr->p_pid; 1611 else 1612 ki->p_ppid = 0; 1613 ki->p_sid = p->p_session->s_sid; 1614 ki->p__pgid = p->p_pgrp->pg_id; 1615 1616 ki->p_tpgid = NO_PID; /* may be changed if controlling tty below */ 1617 1618 ki->p_uid = p->p_ucred->cr_uid; 1619 ki->p_ruid = p->p_cred->p_ruid; 1620 ki->p_gid = p->p_ucred->cr_gid; 1621 ki->p_rgid = p->p_cred->p_rgid; 1622 1623 memcpy(ki->p_groups, p->p_cred->pc_ucred->cr_groups, 1624 min(sizeof(ki->p_groups), sizeof(p->p_cred->pc_ucred->cr_groups))); 1625 ki->p_ngroups = p->p_cred->pc_ucred->cr_ngroups; 1626 1627 ki->p_jobc = p->p_pgrp->pg_jobc; 1628 if ((p->p_flag & P_CONTROLT) && (tp = p->p_session->s_ttyp)) { 1629 ki->p_tdev = tp->t_dev; 1630 ki->p_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1631 ki->p_tsess = PTRTOINT64(tp->t_session); 1632 } else { 1633 ki->p_tdev = NODEV; 1634 } 1635 1636 ki->p_estcpu = p->p_estcpu; 1637 ki->p_rtime_sec = p->p_rtime.tv_sec; 1638 ki->p_rtime_usec = p->p_rtime.tv_usec; 1639 ki->p_cpticks = p->p_cpticks; 1640 ki->p_pctcpu = p->p_pctcpu; 1641 ki->p_swtime = p->p_swtime; 1642 ki->p_slptime = p->p_slptime; 1643 if (p->p_stat == SONPROC) { 1644 KDASSERT(p->p_cpu != NULL); 1645 ki->p_schedflags = p->p_cpu->ci_schedstate.spc_flags; 1646 } else 1647 ki->p_schedflags = 0; 1648 1649 ki->p_uticks = p->p_uticks; 1650 ki->p_sticks = p->p_sticks; 1651 ki->p_iticks = p->p_iticks; 1652 1653 ki->p_tracep = PTRTOINT64(p->p_tracep); 1654 ki->p_traceflag = p->p_traceflag; 1655 1656 ki->p_holdcnt = p->p_holdcnt; 1657 1658 memcpy(&ki->p_siglist, &p->p_sigctx.ps_siglist, sizeof(ki_sigset_t)); 1659 memcpy(&ki->p_sigmask, &p->p_sigctx.ps_sigmask, sizeof(ki_sigset_t)); 1660 memcpy(&ki->p_sigignore, &p->p_sigctx.ps_sigignore,sizeof(ki_sigset_t)); 1661 memcpy(&ki->p_sigcatch, &p->p_sigctx.ps_sigcatch, sizeof(ki_sigset_t)); 1662 1663 ki->p_stat = p->p_stat; 1664 ki->p_priority = p->p_priority; 1665 ki->p_usrpri = p->p_usrpri; 1666 ki->p_nice = p->p_nice; 1667 1668 ki->p_xstat = p->p_xstat; 1669 ki->p_acflag = p->p_acflag; 1670 1671 strncpy(ki->p_comm, p->p_comm, 1672 min(sizeof(ki->p_comm), sizeof(p->p_comm))); 1673 1674 if (p->p_wmesg) 1675 strncpy(ki->p_wmesg, p->p_wmesg, sizeof(ki->p_wmesg)); 1676 ki->p_wchan = PTRTOINT64(p->p_wchan); 1677 1678 strncpy(ki->p_login, p->p_session->s_login, sizeof(ki->p_login)); 1679 1680 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 1681 ki->p_vm_rssize = 0; 1682 ki->p_vm_tsize = 0; 1683 ki->p_vm_dsize = 0; 1684 ki->p_vm_ssize = 0; 1685 } else { 1686 struct vmspace *vm = p->p_vmspace; 1687 1688 ki->p_vm_rssize = vm_resident_count(vm); 1689 ki->p_vm_tsize = vm->vm_tsize; 1690 ki->p_vm_dsize = vm->vm_dsize; 1691 ki->p_vm_ssize = vm->vm_ssize; 1692 } 1693 1694 if (p->p_session->s_ttyvp) 1695 ki->p_eflag |= EPROC_CTTY; 1696 if (SESS_LEADER(p)) 1697 ki->p_eflag |= EPROC_SLEADER; 1698 1699 /* XXX Is this double check necessary? */ 1700 if ((p->p_flag & P_INMEM) == 0 || P_ZOMBIE(p)) { 1701 ki->p_uvalid = 0; 1702 } else { 1703 ki->p_uvalid = 1; 1704 1705 ki->p_ustart_sec = p->p_stats->p_start.tv_sec; 1706 ki->p_ustart_usec = p->p_stats->p_start.tv_usec; 1707 1708 ki->p_uutime_sec = p->p_stats->p_ru.ru_utime.tv_sec; 1709 ki->p_uutime_usec = p->p_stats->p_ru.ru_utime.tv_usec; 1710 ki->p_ustime_sec = p->p_stats->p_ru.ru_stime.tv_sec; 1711 ki->p_ustime_usec = p->p_stats->p_ru.ru_stime.tv_usec; 1712 1713 ki->p_uru_maxrss = p->p_stats->p_ru.ru_maxrss; 1714 ki->p_uru_ixrss = p->p_stats->p_ru.ru_ixrss; 1715 ki->p_uru_idrss = p->p_stats->p_ru.ru_idrss; 1716 ki->p_uru_isrss = p->p_stats->p_ru.ru_isrss; 1717 ki->p_uru_minflt = p->p_stats->p_ru.ru_minflt; 1718 ki->p_uru_majflt = p->p_stats->p_ru.ru_majflt; 1719 ki->p_uru_nswap = p->p_stats->p_ru.ru_nswap; 1720 ki->p_uru_inblock = p->p_stats->p_ru.ru_inblock; 1721 ki->p_uru_oublock = p->p_stats->p_ru.ru_oublock; 1722 ki->p_uru_msgsnd = p->p_stats->p_ru.ru_msgsnd; 1723 ki->p_uru_msgrcv = p->p_stats->p_ru.ru_msgrcv; 1724 ki->p_uru_nsignals = p->p_stats->p_ru.ru_nsignals; 1725 ki->p_uru_nvcsw = p->p_stats->p_ru.ru_nvcsw; 1726 ki->p_uru_nivcsw = p->p_stats->p_ru.ru_nivcsw; 1727 1728 ki->p_uctime_sec = p->p_stats->p_cru.ru_utime.tv_sec + 1729 p->p_stats->p_cru.ru_stime.tv_sec; 1730 ki->p_uctime_usec = p->p_stats->p_cru.ru_utime.tv_usec + 1731 p->p_stats->p_cru.ru_stime.tv_usec; 1732 } 1733 #ifdef MULTIPROCESSOR 1734 if (p->p_cpu != NULL) 1735 ki->p_cpuid = p->p_cpu->ci_cpuid; 1736 else 1737 #endif 1738 ki->p_cpuid = KI_NOCPU; 1739 } 1740 1741 int 1742 sysctl_procargs(int *name, u_int namelen, void *where, size_t *sizep, 1743 struct proc *up) 1744 { 1745 struct ps_strings pss; 1746 struct proc *p; 1747 size_t len, upper_bound, xlen; 1748 struct uio auio; 1749 struct iovec aiov; 1750 vaddr_t argv; 1751 pid_t pid; 1752 int nargv, type, error, i; 1753 char *arg; 1754 char *tmp; 1755 1756 if (namelen != 2) 1757 return (EINVAL); 1758 pid = name[0]; 1759 type = name[1]; 1760 1761 switch (type) { 1762 case KERN_PROC_ARGV: 1763 case KERN_PROC_NARGV: 1764 case KERN_PROC_ENV: 1765 case KERN_PROC_NENV: 1766 /* ok */ 1767 break; 1768 default: 1769 return (EINVAL); 1770 } 1771 1772 /* check pid */ 1773 if ((p = pfind(pid)) == NULL) 1774 return (EINVAL); 1775 1776 /* only root or same user change look at the environment */ 1777 if (type == KERN_PROC_ENV || type == KERN_PROC_NENV) { 1778 if (up->p_ucred->cr_uid != 0) { 1779 if (up->p_cred->p_ruid != p->p_cred->p_ruid || 1780 up->p_cred->p_ruid != p->p_cred->p_svuid) 1781 return (EPERM); 1782 } 1783 } 1784 1785 if (sizep != NULL && where == NULL) { 1786 if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) 1787 *sizep = sizeof (int); 1788 else 1789 *sizep = ARG_MAX; /* XXX XXX XXX */ 1790 return (0); 1791 } 1792 if (where == NULL || sizep == NULL) 1793 return (EINVAL); 1794 1795 /* 1796 * Zombies don't have a stack, so we can't read their psstrings. 1797 * System processes also don't have a user stack. 1798 */ 1799 if (P_ZOMBIE(p) || (p->p_flag & P_SYSTEM) != 0) 1800 return (EINVAL); 1801 1802 /* 1803 * Lock the process down in memory. 1804 */ 1805 /* XXXCDC: how should locking work here? */ 1806 if ((p->p_flag & P_WEXIT) || (p->p_vmspace->vm_refcnt < 1)) 1807 return (EFAULT); 1808 p->p_vmspace->vm_refcnt++; /* XXX */ 1809 1810 /* 1811 * Allocate a temporary buffer to hold the arguments. 1812 */ 1813 arg = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 1814 1815 /* 1816 * Read in the ps_strings structure. 1817 */ 1818 aiov.iov_base = &pss; 1819 aiov.iov_len = sizeof(pss); 1820 auio.uio_iov = &aiov; 1821 auio.uio_iovcnt = 1; 1822 auio.uio_offset = (vaddr_t)p->p_psstr; 1823 auio.uio_resid = sizeof(pss); 1824 auio.uio_segflg = UIO_SYSSPACE; 1825 auio.uio_rw = UIO_READ; 1826 auio.uio_procp = NULL; 1827 error = uvm_io(&p->p_vmspace->vm_map, &auio); 1828 if (error) 1829 goto done; 1830 1831 if (type == KERN_PROC_ARGV || type == KERN_PROC_NARGV) 1832 memcpy(&nargv, (char *)&pss + p->p_psnargv, sizeof(nargv)); 1833 else 1834 memcpy(&nargv, (char *)&pss + p->p_psnenv, sizeof(nargv)); 1835 if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) { 1836 error = copyout(&nargv, where, sizeof(nargv)); 1837 *sizep = sizeof(nargv); 1838 goto done; 1839 } 1840 /* 1841 * Now read the address of the argument vector. 1842 */ 1843 switch (type) { 1844 case KERN_PROC_ARGV: 1845 /* XXX compat32 stuff here */ 1846 memcpy(&tmp, (char *)&pss + p->p_psargv, sizeof(tmp)); 1847 break; 1848 case KERN_PROC_ENV: 1849 memcpy(&tmp, (char *)&pss + p->p_psenv, sizeof(tmp)); 1850 break; 1851 default: 1852 return (EINVAL); 1853 } 1854 auio.uio_offset = (off_t)(long)tmp; 1855 aiov.iov_base = &argv; 1856 aiov.iov_len = sizeof(argv); 1857 auio.uio_iov = &aiov; 1858 auio.uio_iovcnt = 1; 1859 auio.uio_resid = sizeof(argv); 1860 auio.uio_segflg = UIO_SYSSPACE; 1861 auio.uio_rw = UIO_READ; 1862 auio.uio_procp = NULL; 1863 error = uvm_io(&p->p_vmspace->vm_map, &auio); 1864 if (error) 1865 goto done; 1866 1867 /* 1868 * Now copy in the actual argument vector, one page at a time, 1869 * since we don't know how long the vector is (though, we do 1870 * know how many NUL-terminated strings are in the vector). 1871 */ 1872 len = 0; 1873 upper_bound = *sizep; 1874 for (; nargv != 0 && len < upper_bound; len += xlen) { 1875 aiov.iov_base = arg; 1876 aiov.iov_len = PAGE_SIZE; 1877 auio.uio_iov = &aiov; 1878 auio.uio_iovcnt = 1; 1879 auio.uio_offset = argv + len; 1880 xlen = PAGE_SIZE - ((argv + len) & PAGE_MASK); 1881 auio.uio_resid = xlen; 1882 auio.uio_segflg = UIO_SYSSPACE; 1883 auio.uio_rw = UIO_READ; 1884 auio.uio_procp = NULL; 1885 error = uvm_io(&p->p_vmspace->vm_map, &auio); 1886 if (error) 1887 goto done; 1888 1889 for (i = 0; i < xlen && nargv != 0; i++) { 1890 if (arg[i] == '\0') 1891 nargv--; /* one full string */ 1892 } 1893 1894 /* make sure we don't copyout past the end of the user's buffer */ 1895 if (len + i > upper_bound) 1896 i = upper_bound - len; 1897 1898 error = copyout(arg, (char *)where + len, i); 1899 if (error) 1900 break; 1901 1902 if (nargv == 0) { 1903 len += i; 1904 break; 1905 } 1906 } 1907 *sizep = len; 1908 1909 done: 1910 uvmspace_free(p->p_vmspace); 1911 1912 free(arg, M_TEMP); 1913 return (error); 1914 } 1915 1916 #if NPTY > 0 1917 int pty_maxptys(int, int); /* defined in kern/tty_pty.c */ 1918 1919 /* 1920 * Validate parameters and get old / set new parameters 1921 * for pty sysctl function. 1922 */ 1923 static int 1924 sysctl_pty(void *oldp, size_t *oldlenp, void *newp, size_t newlen) 1925 { 1926 int error = 0; 1927 int oldmax = 0, newmax = 0; 1928 1929 /* get current value of maxptys */ 1930 oldmax = pty_maxptys(0, 0); 1931 1932 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &oldmax, int) 1933 1934 if (!error && newp) { 1935 SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, int) 1936 SYSCTL_SCALAR_NEWPCOP_TYP(newp, &newmax, int) 1937 1938 if (newmax != pty_maxptys(newmax, (newp != NULL))) 1939 return (EINVAL); 1940 1941 } 1942 1943 return (error); 1944 } 1945 #endif /* NPTY > 0 */ 1946 1947 static int 1948 sysctl_dotkstat(name, namelen, where, sizep, newp) 1949 int *name; 1950 u_int namelen; 1951 void *where; 1952 size_t *sizep; 1953 void *newp; 1954 { 1955 /* all sysctl names at this level are terminal */ 1956 if (namelen != 1) 1957 return (ENOTDIR); /* overloaded */ 1958 1959 switch (name[0]) { 1960 case KERN_TKSTAT_NIN: 1961 return (sysctl_rdquad(where, sizep, newp, tk_nin)); 1962 case KERN_TKSTAT_NOUT: 1963 return (sysctl_rdquad(where, sizep, newp, tk_nout)); 1964 case KERN_TKSTAT_CANCC: 1965 return (sysctl_rdquad(where, sizep, newp, tk_cancc)); 1966 case KERN_TKSTAT_RAWCC: 1967 return (sysctl_rdquad(where, sizep, newp, tk_rawcc)); 1968 default: 1969 return (EOPNOTSUPP); 1970 } 1971 } 1972