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