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