xref: /openbsd-src/sys/kern/kern_sysctl.c (revision 8445c53715e7030056b779e8ab40efb7820981f2)
1 /*	$OpenBSD: kern_sysctl.c,v 1.57 2001/09/07 22:03:21 angelos Exp $	*/
2 /*	$NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $	*/
3 
4 /*-
5  * Copyright (c) 1982, 1986, 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Mike Karels at Berkeley Software Design, Inc.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
40  */
41 
42 /*
43  * sysctl system call.
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/resourcevar.h>
52 #include <sys/file.h>
53 #include <sys/vnode.h>
54 #include <sys/unistd.h>
55 #include <sys/buf.h>
56 #include <sys/ioctl.h>
57 #include <sys/tty.h>
58 #include <sys/disklabel.h>
59 #include <sys/disk.h>
60 #include <vm/vm.h>
61 #include <sys/sysctl.h>
62 #include <sys/msgbuf.h>
63 #include <sys/dkstat.h>
64 #include <sys/vmmeter.h>
65 #include <sys/namei.h>
66 
67 #include <uvm/uvm_extern.h>
68 
69 #include <sys/mount.h>
70 #include <sys/syscallargs.h>
71 #include <dev/rndvar.h>
72 
73 #ifdef DDB
74 #include <ddb/db_var.h>
75 #endif
76 
77 extern struct forkstat forkstat;
78 extern struct nchstats nchstats;
79 extern int nselcoll, fscale;
80 extern struct disklist_head disklist;
81 extern fixpt_t ccpu;
82 
83 int sysctl_diskinit(int, struct proc *);
84 
85 /*
86  * Lock to avoid too many processes vslocking a large amount of memory
87  * at the same time.
88  */
89 struct lock sysctl_lock, sysctl_disklock;
90 
91 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES)
92 struct lock sysctl_kmemlock;
93 #endif
94 
95 void
96 sysctl_init()
97 {
98 	lockinit(&sysctl_lock, PLOCK|PCATCH, "sysctl", 0, 0);
99 	lockinit(&sysctl_disklock, PLOCK|PCATCH, "sysctl_disklock", 0, 0);
100 
101 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES)
102 	lockinit(&sysctl_kmemlock, PLOCK|PCATCH, "sysctl_kmemlock", 0, 0);
103 #endif
104 }
105 
106 int
107 sys___sysctl(p, v, retval)
108 	struct proc *p;
109 	void *v;
110 	register_t *retval;
111 {
112 	register struct sys___sysctl_args /* {
113 		syscallarg(int *) name;
114 		syscallarg(u_int) namelen;
115 		syscallarg(void *) old;
116 		syscallarg(size_t *) oldlenp;
117 		syscallarg(void *) new;
118 		syscallarg(size_t) newlen;
119 	} */ *uap = v;
120 	int error, dolock = 1;
121 	size_t savelen = 0, oldlen = 0;
122 	sysctlfn *fn;
123 	int name[CTL_MAXNAME];
124 
125 	if (SCARG(uap, new) != NULL &&
126 	    (error = suser(p->p_ucred, &p->p_acflag)))
127 		return (error);
128 	/*
129 	 * all top-level sysctl names are non-terminal
130 	 */
131 	if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2)
132 		return (EINVAL);
133 	error = copyin(SCARG(uap, name), &name,
134 		       SCARG(uap, namelen) * sizeof(int));
135 	if (error)
136 		return (error);
137 
138 	switch (name[0]) {
139 	case CTL_KERN:
140 		fn = kern_sysctl;
141 		if (name[2] == KERN_VNODE)	/* XXX */
142 			dolock = 0;
143 		break;
144 	case CTL_HW:
145 		fn = hw_sysctl;
146 		break;
147 	case CTL_VM:
148 		fn = uvm_sysctl;
149 		break;
150 	case CTL_NET:
151 		fn = net_sysctl;
152 		break;
153 	case CTL_FS:
154 		fn = fs_sysctl;
155 		break;
156 	case CTL_VFS:
157 		fn = vfs_sysctl;
158 		break;
159 	case CTL_MACHDEP:
160 		fn = cpu_sysctl;
161 		break;
162 #ifdef DEBUG
163 	case CTL_DEBUG:
164 		fn = debug_sysctl;
165 		break;
166 #endif
167 #ifdef DDB
168 	case CTL_DDB:
169 		fn = ddb_sysctl;
170 		break;
171 #endif
172 	default:
173 		return (EOPNOTSUPP);
174 	}
175 
176 	if (SCARG(uap, oldlenp) &&
177 	    (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen))))
178 		return (error);
179 	if (SCARG(uap, old) != NULL) {
180 		if ((error = lockmgr(&sysctl_lock, LK_EXCLUSIVE, NULL, p)) != 0)
181 			return (error);
182 		if (dolock)
183 			if (uvm_vslock(p, SCARG(uap, old), oldlen,
184 			    VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) {
185 				lockmgr(&sysctl_lock, LK_RELEASE, NULL, p);
186 				return EFAULT;
187 			}
188 		savelen = oldlen;
189 	}
190 	error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old),
191 	    &oldlen, SCARG(uap, new), SCARG(uap, newlen), p);
192 	if (SCARG(uap, old) != NULL) {
193 		if (dolock)
194 			uvm_vsunlock(p, SCARG(uap, old), savelen);
195 		lockmgr(&sysctl_lock, LK_RELEASE, NULL, p);
196 	}
197 	if (error)
198 		return (error);
199 	if (SCARG(uap, oldlenp))
200 		error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen));
201 	return (error);
202 }
203 
204 /*
205  * Attributes stored in the kernel.
206  */
207 char hostname[MAXHOSTNAMELEN];
208 int hostnamelen;
209 char domainname[MAXHOSTNAMELEN];
210 int domainnamelen;
211 long hostid;
212 char *disknames = NULL;
213 struct diskstats *diskstats = NULL;
214 #ifdef INSECURE
215 int securelevel = -1;
216 #else
217 int securelevel;
218 #endif
219 
220 /*
221  * kernel related system variables.
222  */
223 int
224 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
225 	int *name;
226 	u_int namelen;
227 	void *oldp;
228 	size_t *oldlenp;
229 	void *newp;
230 	size_t newlen;
231 	struct proc *p;
232 {
233 	int error, level, inthostid, oldsgap;
234 	extern char ostype[], osrelease[], osversion[], version[];
235 	extern int somaxconn, sominconn;
236 	extern int usermount, nosuidcoredump;
237 	extern long cp_time[CPUSTATES];
238 	extern int stackgap_random;
239 
240 	/* all sysctl names at this level are terminal */
241 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF ||
242 	    name[0] == KERN_MALLOCSTATS || name[0] == KERN_TTY ||
243 	    name[0] == KERN_POOL))
244 		return (ENOTDIR);		/* overloaded */
245 
246 	switch (name[0]) {
247 	case KERN_OSTYPE:
248 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
249 	case KERN_OSRELEASE:
250 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
251 	case KERN_OSREV:
252 		return (sysctl_rdint(oldp, oldlenp, newp, OpenBSD));
253 	case KERN_OSVERSION:
254 		return (sysctl_rdstring(oldp, oldlenp, newp, osversion));
255 	case KERN_VERSION:
256 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
257 	case KERN_MAXVNODES:
258 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
259 	case KERN_MAXPROC:
260 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
261 	case KERN_MAXFILES:
262 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
263 	case KERN_ARGMAX:
264 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
265 	case KERN_NSELCOLL:
266 		return (sysctl_rdint(oldp, oldlenp, newp, nselcoll));
267 	case KERN_SECURELVL:
268 		level = securelevel;
269 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
270 		    newp == NULL)
271 			return (error);
272 		if ((securelevel > 0 || level < -1)
273 		    && level < securelevel && p->p_pid != 1)
274 			return (EPERM);
275 		securelevel = level;
276 		return (0);
277 	case KERN_HOSTNAME:
278 		error = sysctl_tstring(oldp, oldlenp, newp, newlen,
279 		    hostname, sizeof(hostname));
280 		if (newp && !error)
281 			hostnamelen = newlen;
282 		return (error);
283 	case KERN_DOMAINNAME:
284 		error = sysctl_tstring(oldp, oldlenp, newp, newlen,
285 		    domainname, sizeof(domainname));
286 		if (newp && !error)
287 			domainnamelen = newlen;
288 		return (error);
289 	case KERN_HOSTID:
290 		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
291 		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
292 		hostid = inthostid;
293 		return (error);
294 	case KERN_CLOCKRATE:
295 		return (sysctl_clockrate(oldp, oldlenp));
296 	case KERN_BOOTTIME:
297 		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
298 		    sizeof(struct timeval)));
299 	case KERN_VNODE:
300 		return (sysctl_vnode(oldp, oldlenp, p));
301 	case KERN_PROC:
302 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
303 	case KERN_FILE:
304 		return (sysctl_file(oldp, oldlenp));
305 #ifdef GPROF
306 	case KERN_PROF:
307 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
308 		    newp, newlen));
309 #endif
310 	case KERN_POSIX1:
311 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
312 	case KERN_NGROUPS:
313 		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
314 	case KERN_JOB_CONTROL:
315 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
316 	case KERN_SAVED_IDS:
317 #ifdef _POSIX_SAVED_IDS
318 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
319 #else
320 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
321 #endif
322 	case KERN_MAXPARTITIONS:
323 		return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
324 	case KERN_RAWPARTITION:
325 		return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART));
326 	case KERN_NTPTIME:
327 		return (sysctl_ntptime(oldp, oldlenp));
328 	case KERN_SOMAXCONN:
329 		return (sysctl_int(oldp, oldlenp, newp, newlen, &somaxconn));
330 	case KERN_SOMINCONN:
331 		return (sysctl_int(oldp, oldlenp, newp, newlen, &sominconn));
332 	case KERN_USERMOUNT:
333 		return (sysctl_int(oldp, oldlenp, newp, newlen, &usermount));
334 	case KERN_RND:
335 		return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats,
336 		    sizeof(rndstats)));
337 	case KERN_ARND:
338 		return (sysctl_rdint(oldp, oldlenp, newp, arc4random()));
339 	case KERN_NOSUIDCOREDUMP:
340 		return (sysctl_int(oldp, oldlenp, newp, newlen, &nosuidcoredump));
341 	case KERN_FSYNC:
342 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
343 	case KERN_SYSVMSG:
344 #ifdef SYSVMSG
345 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
346 #else
347 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
348 #endif
349 	case KERN_SYSVSEM:
350 #ifdef SYSVSEM
351 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
352 #else
353 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
354 #endif
355 	case KERN_SYSVSHM:
356 #ifdef SYSVSHM
357 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
358 #else
359 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
360 #endif
361 	case KERN_MSGBUFSIZE:
362 		/*
363 		 * deal with cases where the message buffer has
364 		 * become corrupted.
365 		 */
366 		if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC)
367 			return (ENXIO);
368 		return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs));
369 	case KERN_MSGBUF:
370 		/* see note above */
371 		if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC)
372 			return (ENXIO);
373 		return (sysctl_rdstruct(oldp, oldlenp, newp, msgbufp,
374 		    msgbufp->msg_bufs + offsetof(struct msgbuf, msg_bufc)));
375 	case KERN_MALLOCSTATS:
376 		return (sysctl_malloc(name + 1, namelen - 1, oldp, oldlenp,
377 		    newp, newlen, p));
378 	case KERN_CPTIME:
379 		return (sysctl_rdstruct(oldp, oldlenp, newp, &cp_time,
380 		    sizeof(cp_time)));
381 	case KERN_NCHSTATS:
382 		return (sysctl_rdstruct(oldp, oldlenp, newp, &nchstats,
383 		    sizeof(struct nchstats)));
384 	case KERN_FORKSTAT:
385 		return (sysctl_rdstruct(oldp, oldlenp, newp, &forkstat,
386 		    sizeof(struct forkstat)));
387 	case KERN_TTY:
388 		return (sysctl_tty(name + 1, namelen - 1, oldp, oldlenp,
389 		    newp, newlen));
390 	case KERN_FSCALE:
391 		return (sysctl_rdint(oldp, oldlenp, newp, fscale));
392 	case KERN_CCPU:
393 		return (sysctl_rdint(oldp, oldlenp, newp, ccpu));
394 	case KERN_NPROCS:
395 		return (sysctl_rdint(oldp, oldlenp, newp, nprocs));
396 	case KERN_POOL:
397 		return (sysctl_dopool(name + 1, namelen - 1, oldp, oldlenp));
398 	case KERN_STACKGAPRANDOM:
399 		oldsgap = stackgap_random;
400 
401 		error = sysctl_int(oldp, oldlenp, newp, newlen, &stackgap_random);
402 		/*
403 		 * Safety harness.
404 		 */
405 		if ((stackgap_random < ALIGNBYTES && stackgap_random != 0) ||
406 		    !powerof2(stackgap_random) ||
407 		    stackgap_random > PAGE_SIZE * 2) {
408 			stackgap_random = oldsgap;
409 			return (EINVAL);
410 		}
411 		return (error);
412 	default:
413 		return (EOPNOTSUPP);
414 	}
415 	/* NOTREACHED */
416 }
417 
418 /*
419  * hardware related system variables.
420  */
421 int
422 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
423 	int *name;
424 	u_int namelen;
425 	void *oldp;
426 	size_t *oldlenp;
427 	void *newp;
428 	size_t newlen;
429 	struct proc *p;
430 {
431 	extern char machine[], cpu_model[];
432 	int err;
433 
434 	/* all sysctl names at this level are terminal */
435 	if (namelen != 1)
436 		return (ENOTDIR);		/* overloaded */
437 
438 	switch (name[0]) {
439 	case HW_MACHINE:
440 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
441 	case HW_MODEL:
442 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
443 	case HW_NCPU:
444 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
445 	case HW_BYTEORDER:
446 		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
447 	case HW_PHYSMEM:
448 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
449 	case HW_USERMEM:
450 		return (sysctl_rdint(oldp, oldlenp, newp,
451 		    ctob(physmem - uvmexp.wired)));
452 	case HW_PAGESIZE:
453 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
454 	case HW_DISKNAMES:
455 		err = sysctl_diskinit(0, p);
456 		if (err)
457 			return err;
458 		if (disknames)
459 			return (sysctl_rdstring(oldp, oldlenp, newp,
460 			    disknames));
461 		else
462 			return (sysctl_rdstring(oldp, oldlenp, newp, ""));
463 	case HW_DISKSTATS:
464 		err = sysctl_diskinit(1, p);
465 		if (err)
466 			return err;
467 		return (sysctl_rdstruct(oldp, oldlenp, newp, diskstats,
468 		    disk_count * sizeof(struct diskstats)));
469 	case HW_DISKCOUNT:
470 		return (sysctl_rdint(oldp, oldlenp, newp, disk_count));
471 	default:
472 		return (EOPNOTSUPP);
473 	}
474 	/* NOTREACHED */
475 }
476 
477 #ifdef DEBUG
478 /*
479  * Debugging related system variables.
480  */
481 struct ctldebug debug0, debug1, debug2, debug3, debug4;
482 struct ctldebug debug5, debug6, debug7, debug8, debug9;
483 struct ctldebug debug10, debug11, debug12, debug13, debug14;
484 struct ctldebug debug15, debug16, debug17, debug18, debug19;
485 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
486 	&debug0, &debug1, &debug2, &debug3, &debug4,
487 	&debug5, &debug6, &debug7, &debug8, &debug9,
488 	&debug10, &debug11, &debug12, &debug13, &debug14,
489 	&debug15, &debug16, &debug17, &debug18, &debug19,
490 };
491 int
492 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
493 	int *name;
494 	u_int namelen;
495 	void *oldp;
496 	size_t *oldlenp;
497 	void *newp;
498 	size_t newlen;
499 	struct proc *p;
500 {
501 	struct ctldebug *cdp;
502 
503 	/* all sysctl names at this level are name and field */
504 	if (namelen != 2)
505 		return (ENOTDIR);		/* overloaded */
506 	cdp = debugvars[name[0]];
507 	if (cdp->debugname == 0)
508 		return (EOPNOTSUPP);
509 	switch (name[1]) {
510 	case CTL_DEBUG_NAME:
511 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
512 	case CTL_DEBUG_VALUE:
513 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
514 	default:
515 		return (EOPNOTSUPP);
516 	}
517 	/* NOTREACHED */
518 }
519 #endif /* DEBUG */
520 
521 /*
522  * Validate parameters and get old / set new parameters
523  * for an integer-valued sysctl function.
524  */
525 int
526 sysctl_int(oldp, oldlenp, newp, newlen, valp)
527 	void *oldp;
528 	size_t *oldlenp;
529 	void *newp;
530 	size_t newlen;
531 	int *valp;
532 {
533 	int error = 0;
534 
535 	if (oldp && *oldlenp < sizeof(int))
536 		return (ENOMEM);
537 	if (newp && newlen != sizeof(int))
538 		return (EINVAL);
539 	*oldlenp = sizeof(int);
540 	if (oldp)
541 		error = copyout(valp, oldp, sizeof(int));
542 	if (error == 0 && newp)
543 		error = copyin(newp, valp, sizeof(int));
544 	return (error);
545 }
546 
547 /*
548  * As above, but read-only.
549  */
550 int
551 sysctl_rdint(oldp, oldlenp, newp, val)
552 	void *oldp;
553 	size_t *oldlenp;
554 	void *newp;
555 	int val;
556 {
557 	int error = 0;
558 
559 	if (oldp && *oldlenp < sizeof(int))
560 		return (ENOMEM);
561 	if (newp)
562 		return (EPERM);
563 	*oldlenp = sizeof(int);
564 	if (oldp)
565 		error = copyout((caddr_t)&val, oldp, sizeof(int));
566 	return (error);
567 }
568 
569 /*
570  * Validate parameters and get old / set new parameters
571  * for an integer-valued sysctl function.
572  */
573 int
574 sysctl_quad(oldp, oldlenp, newp, newlen, valp)
575 	void *oldp;
576 	size_t *oldlenp;
577 	void *newp;
578 	size_t newlen;
579 	int64_t *valp;
580 {
581 	int error = 0;
582 
583 	if (oldp && *oldlenp < sizeof(int64_t))
584 		return (ENOMEM);
585 	if (newp && newlen != sizeof(int64_t))
586 		return (EINVAL);
587 	*oldlenp = sizeof(int64_t);
588 	if (oldp)
589 		error = copyout(valp, oldp, sizeof(int64_t));
590 	if (error == 0 && newp)
591 		error = copyin(newp, valp, sizeof(int64_t));
592 	return (error);
593 }
594 
595 /*
596  * As above, but read-only.
597  */
598 int
599 sysctl_rdquad(oldp, oldlenp, newp, val)
600 	void *oldp;
601 	size_t *oldlenp;
602 	void *newp;
603 	int64_t val;
604 {
605 	int error = 0;
606 
607 	if (oldp && *oldlenp < sizeof(int64_t))
608 		return (ENOMEM);
609 	if (newp)
610 		return (EPERM);
611 	*oldlenp = sizeof(int64_t);
612 	if (oldp)
613 		error = copyout((caddr_t)&val, oldp, sizeof(int64_t));
614 	return (error);
615 }
616 
617 /*
618  * Validate parameters and get old / set new parameters
619  * for a string-valued sysctl function.
620  */
621 int
622 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
623 	void *oldp;
624 	size_t *oldlenp;
625 	void *newp;
626 	size_t newlen;
627 	char *str;
628 	int maxlen;
629 {
630 	return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 0);
631 }
632 
633 int
634 sysctl_tstring(oldp, oldlenp, newp, newlen, str, maxlen)
635 	void *oldp;
636 	size_t *oldlenp;
637 	void *newp;
638 	size_t newlen;
639 	char *str;
640 	int maxlen;
641 {
642 	return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1);
643 }
644 
645 int
646 sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, trunc)
647 	void *oldp;
648 	size_t *oldlenp;
649 	void *newp;
650 	size_t newlen;
651 	char *str;
652 	int maxlen;
653 	int trunc;
654 {
655 	int len, error = 0;
656 	char c;
657 
658 	len = strlen(str) + 1;
659 	if (oldp && *oldlenp < len) {
660 		if (trunc == 0 || *oldlenp == 0)
661 			return (ENOMEM);
662 	}
663 	if (newp && newlen >= maxlen)
664 		return (EINVAL);
665 	if (oldp) {
666 		if (trunc && *oldlenp < len) {
667 			/* save & zap NUL terminator while copying */
668 			c = str[*oldlenp-1];
669 			str[*oldlenp-1] = '\0';
670 			error = copyout(str, oldp, *oldlenp);
671 			str[*oldlenp-1] = c;
672 		} else {
673 			*oldlenp = len;
674 			error = copyout(str, oldp, len);
675 		}
676 	}
677 	if (error == 0 && newp) {
678 		error = copyin(newp, str, newlen);
679 		str[newlen] = 0;
680 	}
681 	return (error);
682 }
683 
684 /*
685  * As above, but read-only.
686  */
687 int
688 sysctl_rdstring(oldp, oldlenp, newp, str)
689 	void *oldp;
690 	size_t *oldlenp;
691 	void *newp;
692 	char *str;
693 {
694 	int len, error = 0;
695 
696 	len = strlen(str) + 1;
697 	if (oldp && *oldlenp < len)
698 		return (ENOMEM);
699 	if (newp)
700 		return (EPERM);
701 	*oldlenp = len;
702 	if (oldp)
703 		error = copyout(str, oldp, len);
704 	return (error);
705 }
706 
707 /*
708  * Validate parameters and get old / set new parameters
709  * for a structure oriented sysctl function.
710  */
711 int
712 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
713 	void *oldp;
714 	size_t *oldlenp;
715 	void *newp;
716 	size_t newlen;
717 	void *sp;
718 	int len;
719 {
720 	int error = 0;
721 
722 	if (oldp && *oldlenp < len)
723 		return (ENOMEM);
724 	if (newp && newlen > len)
725 		return (EINVAL);
726 	if (oldp) {
727 		*oldlenp = len;
728 		error = copyout(sp, oldp, len);
729 	}
730 	if (error == 0 && newp)
731 		error = copyin(newp, sp, len);
732 	return (error);
733 }
734 
735 /*
736  * Validate parameters and get old parameters
737  * for a structure oriented sysctl function.
738  */
739 int
740 sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
741 	void *oldp;
742 	size_t *oldlenp;
743 	void *newp, *sp;
744 	int len;
745 {
746 	int error = 0;
747 
748 	if (oldp && *oldlenp < len)
749 		return (ENOMEM);
750 	if (newp)
751 		return (EPERM);
752 	*oldlenp = len;
753 	if (oldp)
754 		error = copyout(sp, oldp, len);
755 	return (error);
756 }
757 
758 /*
759  * Get file structures.
760  */
761 int
762 sysctl_file(where, sizep)
763 	char *where;
764 	size_t *sizep;
765 {
766 	int buflen, error;
767 	struct file *fp;
768 	char *start = where;
769 
770 	buflen = *sizep;
771 	if (where == NULL) {
772 		/*
773 		 * overestimate by 10 files
774 		 */
775 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
776 		return (0);
777 	}
778 
779 	/*
780 	 * first copyout filehead
781 	 */
782 	if (buflen < sizeof(filehead)) {
783 		*sizep = 0;
784 		return (0);
785 	}
786 	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
787 	if (error)
788 		return (error);
789 	buflen -= sizeof(filehead);
790 	where += sizeof(filehead);
791 
792 	/*
793 	 * followed by an array of file structures
794 	 */
795 	for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
796 		if (buflen < sizeof(struct file)) {
797 			*sizep = where - start;
798 			return (ENOMEM);
799 		}
800 		error = copyout((caddr_t)fp, where, sizeof (struct file));
801 		if (error)
802 			return (error);
803 		buflen -= sizeof(struct file);
804 		where += sizeof(struct file);
805 	}
806 	*sizep = where - start;
807 	return (0);
808 }
809 
810 /*
811  * try over estimating by 5 procs
812  */
813 #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
814 
815 int
816 sysctl_doproc(name, namelen, where, sizep)
817 	int *name;
818 	u_int namelen;
819 	char *where;
820 	size_t *sizep;
821 {
822 	register struct proc *p;
823 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
824 	register int needed = 0;
825 	int buflen = where != NULL ? *sizep : 0;
826 	int doingzomb;
827 	struct eproc eproc;
828 	int error = 0;
829 
830 	if (namelen != 2 && !(namelen == 1 &&
831 	    (name[0] == KERN_PROC_ALL || name[0] == KERN_PROC_KTHREAD)))
832 		return (EINVAL);
833 	p = LIST_FIRST(&allproc);
834 	doingzomb = 0;
835 again:
836 	for (; p != 0; p = LIST_NEXT(p, p_list)) {
837 		/*
838 		 * Skip embryonic processes.
839 		 */
840 		if (p->p_stat == SIDL)
841 			continue;
842 		/*
843 		 * TODO - make more efficient (see notes below).
844 		 * do by session.
845 		 */
846 		switch (name[0]) {
847 
848 		case KERN_PROC_PID:
849 			/* could do this with just a lookup */
850 			if (p->p_pid != (pid_t)name[1])
851 				continue;
852 			break;
853 
854 		case KERN_PROC_PGRP:
855 			/* could do this by traversing pgrp */
856 			if (p->p_pgrp->pg_id != (pid_t)name[1])
857 				continue;
858 			break;
859 
860 		case KERN_PROC_TTY:
861 			if ((p->p_flag & P_CONTROLT) == 0 ||
862 			    p->p_session->s_ttyp == NULL ||
863 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
864 				continue;
865 			break;
866 
867 		case KERN_PROC_UID:
868 			if (p->p_ucred->cr_uid != (uid_t)name[1])
869 				continue;
870 			break;
871 
872 		case KERN_PROC_RUID:
873 			if (p->p_cred->p_ruid != (uid_t)name[1])
874 				continue;
875 			break;
876 
877 		case KERN_PROC_ALL:
878 			if (p->p_flag & P_SYSTEM)
879 				continue;
880 			break;
881 		}
882 		if (buflen >= sizeof(struct kinfo_proc)) {
883 			fill_eproc(p, &eproc);
884 			error = copyout((caddr_t)p, &dp->kp_proc,
885 					sizeof(struct proc));
886 			if (error)
887 				return (error);
888 			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
889 					sizeof(eproc));
890 			if (error)
891 				return (error);
892 			dp++;
893 			buflen -= sizeof(struct kinfo_proc);
894 		}
895 		needed += sizeof(struct kinfo_proc);
896 	}
897 	if (doingzomb == 0) {
898 		p = LIST_FIRST(&zombproc);
899 		doingzomb++;
900 		goto again;
901 	}
902 	if (where != NULL) {
903 		*sizep = (caddr_t)dp - where;
904 		if (needed > *sizep)
905 			return (ENOMEM);
906 	} else {
907 		needed += KERN_PROCSLOP;
908 		*sizep = needed;
909 	}
910 	return (0);
911 }
912 
913 /*
914  * Fill in an eproc structure for the specified process.
915  */
916 void
917 fill_eproc(p, ep)
918 	register struct proc *p;
919 	register struct eproc *ep;
920 {
921 	register struct tty *tp;
922 
923 	ep->e_paddr = p;
924 	ep->e_sess = p->p_pgrp->pg_session;
925 	ep->e_pcred = *p->p_cred;
926 	ep->e_ucred = *p->p_ucred;
927 	if (p->p_stat == SIDL || P_ZOMBIE(p)) {
928 		ep->e_vm.vm_rssize = 0;
929 		ep->e_vm.vm_tsize = 0;
930 		ep->e_vm.vm_dsize = 0;
931 		ep->e_vm.vm_ssize = 0;
932 	} else {
933 		register struct vmspace *vm = p->p_vmspace;
934 
935 		ep->e_vm.vm_rssize = vm_resident_count(vm);
936 		ep->e_vm.vm_tsize = vm->vm_tsize;
937 		ep->e_vm.vm_dsize = vm->vm_dsize;
938 		ep->e_vm.vm_ssize = vm->vm_ssize;
939 	}
940 	if (p->p_pptr)
941 		ep->e_ppid = p->p_pptr->p_pid;
942 	else
943 		ep->e_ppid = 0;
944 	ep->e_pgid = p->p_pgrp->pg_id;
945 	ep->e_jobc = p->p_pgrp->pg_jobc;
946 	if ((p->p_flag & P_CONTROLT) &&
947 	     (tp = ep->e_sess->s_ttyp)) {
948 		ep->e_tdev = tp->t_dev;
949 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
950 		ep->e_tsess = tp->t_session;
951 	} else
952 		ep->e_tdev = NODEV;
953 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
954 	if (SESS_LEADER(p))
955 		ep->e_flag |= EPROC_SLEADER;
956 	strncpy(ep->e_wmesg, p->p_wmesg ? p->p_wmesg : "", WMESGLEN);
957 	ep->e_wmesg[WMESGLEN] = '\0';
958 	ep->e_xsize = ep->e_xrssize = 0;
959 	ep->e_xccount = ep->e_xswrss = 0;
960 	strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME-1);
961 	ep->e_login[MAXLOGNAME-1] = '\0';
962 	strncpy(ep->e_emul, p->p_emul->e_name, EMULNAMELEN);
963 	ep->e_emul[EMULNAMELEN] = '\0';
964 	ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0;
965 }
966 
967 /*
968  * Initialize disknames/diskstats for export by sysctl. If update is set,
969  * then we simply update the disk statistics information.
970  */
971 int
972 sysctl_diskinit(update, p)
973 	int update;
974 	struct proc *p;
975 {
976 	struct diskstats *sdk;
977 	struct disk *dk;
978 	int i, tlen, l;
979 
980 	if ((i = lockmgr(&sysctl_disklock, LK_EXCLUSIVE, NULL, p)) != 0)
981 		return i;
982 
983 	if (disk_change) {
984 		for (dk = TAILQ_FIRST(&disklist), tlen = 0; dk;
985 		    dk = TAILQ_NEXT(dk, dk_link))
986 			tlen += strlen(dk->dk_name) + 1;
987 		tlen++;
988 
989 		if (disknames)
990 			free(disknames, M_SYSCTL);
991 		if (diskstats)
992 			free(diskstats, M_SYSCTL);
993 		diskstats = NULL;
994 		disknames = NULL;
995 		diskstats = malloc(disk_count * sizeof(struct diskstats),
996 		    M_SYSCTL, M_WAITOK);
997 		disknames = malloc(tlen, M_SYSCTL, M_WAITOK);
998 		disknames[0] = '\0';
999 
1000 		for (dk = TAILQ_FIRST(&disklist), i = 0, l = 0; dk;
1001 		    dk = TAILQ_NEXT(dk, dk_link), i++) {
1002 			l += sprintf(disknames + l, "%s,",
1003 			    dk->dk_name ? dk->dk_name : "");
1004 			sdk = diskstats + i;
1005 			sdk->ds_busy = dk->dk_busy;
1006 			sdk->ds_xfer = dk->dk_xfer;
1007 			sdk->ds_seek = dk->dk_seek;
1008 			sdk->ds_bytes = dk->dk_bytes;
1009 			sdk->ds_attachtime = dk->dk_attachtime;
1010 			sdk->ds_timestamp = dk->dk_timestamp;
1011 			sdk->ds_time = dk->dk_time;
1012 		}
1013 
1014 		/* Eliminate trailing comma */
1015 		if (l != 0)
1016 			disknames[l - 1] = '\0';
1017 		disk_change = 0;
1018 	} else if (update) {
1019 		/* Just update, number of drives hasn't changed */
1020 		for (dk = TAILQ_FIRST(&disklist), i = 0; dk;
1021 		    dk = TAILQ_NEXT(dk, dk_link), i++) {
1022 			sdk = diskstats + i;
1023 			sdk->ds_busy = dk->dk_busy;
1024 			sdk->ds_xfer = dk->dk_xfer;
1025 			sdk->ds_seek = dk->dk_seek;
1026 			sdk->ds_bytes = dk->dk_bytes;
1027 			sdk->ds_attachtime = dk->dk_attachtime;
1028 			sdk->ds_timestamp = dk->dk_timestamp;
1029 			sdk->ds_time = dk->dk_time;
1030 		}
1031 	}
1032 	lockmgr(&sysctl_disklock, LK_RELEASE, NULL, p);
1033 	return 0;
1034 }
1035