kern_sysctl.c revision 12131
1/*-
2 * Copyright (c) 1982, 1986, 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Mike Karels at Berkeley Software Design, Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
37 * $Id: kern_sysctl.c,v 1.30 1995/10/28 13:07:23 phk Exp $
38 */
39
40/*
41 * sysctl system call.
42 */
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/malloc.h>
48#include <sys/proc.h>
49#include <sys/file.h>
50#include <sys/vnode.h>
51#include <sys/unistd.h>
52#include <sys/buf.h>
53#include <sys/ioctl.h>
54#include <sys/tty.h>
55#include <sys/conf.h>
56#include <vm/vm.h>
57#include <sys/sysctl.h>
58#include <sys/user.h>
59
60/* BEGIN_MIB */
61SYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW, 0,
62	"High kernel, proc, limits &c");
63SYSCTL_NODE(, CTL_VM,	  vm,     CTLFLAG_RW, 0,
64	"Virtual memory");
65SYSCTL_NODE(, CTL_FS,	  fs,     CTLFLAG_RW, 0,
66	"File system");
67SYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
68	"Network, (see socket.h)");
69SYSCTL_NODE(, CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
70	"Debugging");
71SYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
72	"hardware");
73SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
74	"machine dependent");
75SYSCTL_NODE(, CTL_USER,	  user,   CTLFLAG_RW, 0,
76	"user-level");
77
78SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, "");
79
80SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, "");
81
82SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, "");
83
84SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "");
85
86extern int osreldate;
87SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "");
88
89SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, "");
90
91SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, "");
92
93SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid,
94	CTLFLAG_RD, &maxprocperuid, 0, "");
95
96SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc,
97	CTLFLAG_RD, &maxfilesperproc, 0, "");
98
99SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, "");
100
101SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, "");
102
103SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, "");
104
105SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, "");
106
107SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, "");
108
109#ifdef _POSIX_SAVED_IDS
110SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, "");
111#else
112SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, "");
113#endif
114
115char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
116
117SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile,
118	CTLFLAG_RW, kernelname, sizeof kernelname, "");
119
120SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime,
121	CTLFLAG_RW, &boottime, timeval, "");
122
123SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
124
125SYSCTL_STRING(_hw, HW_MACHINE, model, CTLFLAG_RD, cpu_model, 0, "");
126
127SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, "");
128
129SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, "");
130
131SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, "");
132
133/* END_MIB */
134
135extern int vfs_update_wakeup;
136extern int vfs_update_interval;
137static int
138sysctl_kern_updateinterval SYSCTL_HANDLER_ARGS
139{
140	int error = sysctl_handle_int(oidp,
141		oidp->oid_arg1, oidp->oid_arg2,
142		oldp, oldlenp, newp, newlen);
143	if (!error)
144		wakeup(&vfs_update_wakeup);
145	return error;
146}
147
148SYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW,
149	&vfs_update_interval, 0, sysctl_kern_updateinterval, "");
150
151
152char hostname[MAXHOSTNAMELEN];
153int hostnamelen;
154static int
155sysctl_kern_hostname SYSCTL_HANDLER_ARGS
156{
157	int error = sysctl_handle_string(oidp,
158		oidp->oid_arg1, oidp->oid_arg2,
159		oldp, oldlenp, newp, newlen);
160	if (newp && (error == 0 || error == ENOMEM))
161		hostnamelen = newlen;
162	return error;
163}
164
165SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW,
166	&hostname, sizeof(hostname), sysctl_kern_hostname, "");
167
168
169char domainname[MAXHOSTNAMELEN];
170int domainnamelen;
171static int
172sysctl_kern_domainname SYSCTL_HANDLER_ARGS
173{
174	int error = sysctl_handle_string(oidp,
175		oidp->oid_arg1, oidp->oid_arg2,
176		oldp, oldlenp, newp, newlen);
177	if (newp && (error == 0 || error == ENOMEM))
178		domainnamelen = newlen;
179	return error;
180}
181
182SYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW,
183	&domainname, sizeof(domainname), sysctl_kern_domainname, "");
184
185long hostid;
186/* Some trouble here, if sizeof (int) != sizeof (long) */
187SYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "");
188
189int
190sysctl_handle_int SYSCTL_HANDLER_ARGS
191{
192	/* If there isn't sufficient space to return */
193	if (oldp && *oldlenp < sizeof(int))
194		return (ENOMEM);
195
196	/* If it is a constant, don't write */
197	if (newp && !arg1)
198		return (EPERM);
199
200	/* If we get more than an int */
201	if (newp && newlen != sizeof(int))
202		return (EINVAL);
203
204	*oldlenp = sizeof(int);
205	if (oldp && arg1 )
206		bcopy(arg1, oldp, sizeof(int));
207	else if (oldp)
208		bcopy(&arg2, oldp, sizeof(int));
209	if (newp)
210		bcopy(newp, arg1, sizeof(int));
211	return (0);
212}
213
214int
215sysctl_handle_string SYSCTL_HANDLER_ARGS
216{
217	int len, error=0;
218	char *str = (char *)arg1;
219
220	len = strlen(str) + 1;
221
222	if (oldp && *oldlenp < len) {
223		len = *oldlenp;
224		error=ENOMEM;
225	}
226
227	if (newp && newlen >= arg2)
228		return (EINVAL);
229
230	if (oldp) {
231		*oldlenp = len;
232		bcopy(str, oldp, len);
233	}
234
235	if (newp) {
236		bcopy(newp, str, newlen);
237		str[newlen] = 0;
238	}
239	return (error);
240}
241
242int
243sysctl_handle_opaque SYSCTL_HANDLER_ARGS
244{
245	if (oldp && *oldlenp < arg2)
246		return (ENOMEM);
247
248	if (newp && newlen != arg2)
249		return (EINVAL);
250
251	if (oldp) {
252		*oldlenp = arg2;
253		bcopy(arg1, oldp, arg2);
254	}
255	if (newp)
256		bcopy(newp, arg1, arg2);
257	return (0);
258}
259
260#ifdef DEBUG
261static sysctlfn debug_sysctl;
262#endif
263
264/*
265 * Locking and stats
266 */
267static struct sysctl_lock {
268	int	sl_lock;
269	int	sl_want;
270	int	sl_locked;
271} memlock;
272
273struct sysctl_args {
274	int	*name;
275	u_int	namelen;
276	void	*old;
277	size_t	*oldlenp;
278	void	*new;
279	size_t	newlen;
280};
281
282
283
284/*
285 * Traverse our tree, and find the right node, execute whatever it points
286 * at, and return the resulting error code.
287 * We work entirely in kernel-space at this time.
288 */
289
290extern struct linker_set sysctl_;
291
292int sysctl_dummy;
293
294int
295sysctl_root SYSCTL_HANDLER_ARGS
296{
297	int *name = (int *) arg1;
298	int namelen = arg2;
299	int indx, i, j;
300	struct sysctl_oid **oidpp;
301	struct linker_set *lsp = &sysctl_;
302
303	j = lsp->ls_length;
304	oidpp = (struct sysctl_oid **) lsp->ls_items;
305
306	indx = 0;
307	while (j-- && indx < CTL_MAXNAME) {
308		if (*oidpp &&
309		    ((void *)&sysctl_dummy != (void *)*oidpp) &&
310		    ((*oidpp)->oid_number == name[indx])) {
311			indx++;
312			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
313				if ((*oidpp)->oid_handler)
314					goto found;
315				if (indx == namelen)
316					return ENOENT;
317				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
318				j = lsp->ls_length;
319				oidpp = (struct sysctl_oid **)lsp->ls_items;
320			} else {
321				if (indx != namelen)
322					return EISDIR;
323				goto found;
324			}
325		} else {
326			oidpp++;
327		}
328	}
329	return EJUSTRETURN;
330found:
331
332	/* If writing isn't allowed */
333	if (newp && !((*oidpp)->oid_kind & CTLFLAG_WR))
334		return (EPERM);
335
336	if (!(*oidpp)->oid_handler)
337		return EINVAL;
338
339	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
340		i = ((*oidpp)->oid_handler) (*oidpp,
341					name + indx, namelen - indx,
342					oldp, oldlenp, newp, newlen);
343	} else {
344		i = ((*oidpp)->oid_handler) (*oidpp,
345					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
346					oldp, oldlenp, newp, newlen);
347	}
348	return (i);
349}
350
351int
352__sysctl(p, uap, retval)
353	struct proc *p;
354	register struct sysctl_args *uap;
355	int *retval;
356{
357	int error, dolock = 1, i;
358	u_int savelen = 0, oldlen = 0;
359	sysctlfn *fn;
360	int name[CTL_MAXNAME];
361	void *oldp = 0;
362	void *newp = 0;
363
364	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
365		return (error);
366
367	/*
368	 * all top-level sysctl names are non-terminal
369	 */
370
371	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
372		return (EINVAL);
373
374 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
375 	if (error)
376		return (error);
377
378	if (uap->oldlenp &&
379	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
380		return (error);
381
382	if (uap->old)
383		oldp = malloc(oldlen, M_TEMP, M_WAITOK);
384
385	if (uap->newlen) {
386		newp = malloc(uap->newlen, M_TEMP, M_WAITOK);
387		error = copyin(uap->new, newp, uap->newlen);
388	}
389	if (error) {
390		if (oldp)
391			free(oldp, M_TEMP);
392		if (newp)
393			free(newp, M_TEMP);
394		return error;
395	}
396
397	error = sysctl_root(0, name, uap->namelen, oldp, &oldlen,
398	newp, uap->newlen);
399#if 0
400	if (error) {
401		printf("SYSCTL_ROOT: ");
402		for(i=0;i<uap->namelen;i++)
403			printf("%d ", name[i]);
404		printf("= %d\n", error);
405	}
406#endif
407
408        if (!error || error == ENOMEM) {
409		if (uap->oldlenp) {
410			i = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
411			if (i)
412				error = i;
413		}
414		if ((error == ENOMEM || !error ) && oldp) {
415			i = copyout(oldp, uap->old, oldlen);
416			if (i)
417				error = i;
418			free(oldp, M_TEMP);
419		}
420		if (newp)
421			free(newp, M_TEMP);
422		return (error);
423	}
424
425	if (oldp)
426		free(oldp, M_TEMP);
427	if (newp)
428		free(newp, M_TEMP);
429
430	switch (name[0]) {
431	case CTL_KERN:
432		fn = kern_sysctl;
433		if (name[1] != KERN_VNODE)      /* XXX */
434			dolock = 0;
435		break;
436	case CTL_HW:
437		fn = hw_sysctl;
438		break;
439	case CTL_VM:
440		fn = vm_sysctl;
441		break;
442	case CTL_NET:
443#if 0
444		printf("SYSCTL_NET: ");
445		for(i=0;i<uap->namelen;i++)
446			printf("%d ", name[i]);
447		printf("\n");
448#endif
449		fn = net_sysctl;
450		break;
451	case CTL_FS:
452		fn = fs_sysctl;
453		break;
454	case CTL_MACHDEP:
455		fn = cpu_sysctl;
456		break;
457#ifdef DEBUG
458	case CTL_DEBUG:
459		fn = debug_sysctl;
460		break;
461#endif
462	default:
463		return (EOPNOTSUPP);
464	}
465	if (uap->old != NULL) {
466		if (!useracc(uap->old, oldlen, B_WRITE))
467			return (EFAULT);
468		while (memlock.sl_lock) {
469			memlock.sl_want = 1;
470			(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
471			memlock.sl_locked++;
472		}
473		memlock.sl_lock = 1;
474		if (dolock)
475			vslock(uap->old, oldlen);
476		savelen = oldlen;
477	}
478
479
480	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
481	    uap->new, uap->newlen, p);
482
483
484	if (uap->old != NULL) {
485		if (dolock)
486			vsunlock(uap->old, savelen, B_WRITE);
487		memlock.sl_lock = 0;
488		if (memlock.sl_want) {
489			memlock.sl_want = 0;
490			wakeup((caddr_t)&memlock);
491		}
492	}
493	if (error)
494		return (error);
495	if (uap->oldlenp)
496		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
497	*retval = oldlen;
498	return (0);
499}
500
501/*
502 * Attributes stored in the kernel.
503 */
504int securelevel = -1;
505
506/*
507 * kernel related system variables.
508 */
509int
510kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
511	int *name;
512	u_int namelen;
513	void *oldp;
514	size_t *oldlenp;
515	void *newp;
516	size_t newlen;
517	struct proc *p;
518{
519	int error, level;
520	dev_t ndumpdev;
521
522	/* all sysctl names at this level are terminal */
523	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
524			      || name[0] == KERN_NTP_PLL))
525		return (ENOTDIR);		/* overloaded */
526
527	switch (name[0]) {
528
529	case KERN_SECURELVL:
530		level = securelevel;
531		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
532		    newp == NULL)
533			return (error);
534		if (level < securelevel && p->p_pid != 1)
535			return (EPERM);
536		securelevel = level;
537		return (0);
538	case KERN_VNODE:
539		return (sysctl_vnode(oldp, oldlenp));
540	case KERN_PROC:
541		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
542	case KERN_FILE:
543		return (sysctl_file(oldp, oldlenp));
544#ifdef GPROF
545	case KERN_PROF:
546		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
547		    newp, newlen));
548#endif
549	case KERN_NTP_PLL:
550		return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp,
551				   newp, newlen, p));
552	case KERN_DUMPDEV:
553		ndumpdev = dumpdev;
554		error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev,
555				      sizeof ndumpdev);
556		if (!error && ndumpdev != dumpdev) {
557			error = setdumpdev(ndumpdev);
558		}
559		return error;
560	default:
561		return (EOPNOTSUPP);
562	}
563	/* NOTREACHED */
564}
565
566/*
567 * hardware related system variables.
568 */
569int
570hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
571	int *name;
572	u_int namelen;
573	void *oldp;
574	size_t *oldlenp;
575	void *newp;
576	size_t newlen;
577	struct proc *p;
578{
579	/* almost all sysctl names at this level are terminal */
580	if (namelen != 1 && name[0] != HW_DEVCONF)
581		return (ENOTDIR);		/* overloaded */
582
583	switch (name[0]) {
584	case HW_PHYSMEM:
585		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
586	case HW_USERMEM:
587		return (sysctl_rdint(oldp, oldlenp, newp,
588		    ctob(physmem - cnt.v_wire_count)));
589	case HW_DEVCONF:
590		return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp,
591				   newp, newlen, p));
592	default:
593		return (EOPNOTSUPP);
594	}
595	/* NOTREACHED */
596}
597
598#ifdef DEBUG
599/*
600 * Debugging related system variables.
601 */
602struct ctldebug debug0, debug1, debug2, debug3, debug4;
603struct ctldebug debug5, debug6, debug7, debug8, debug9;
604struct ctldebug debug10, debug11, debug12, debug13, debug14;
605struct ctldebug debug15, debug16, debug17, debug18, debug19;
606static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
607	&debug0, &debug1, &debug2, &debug3, &debug4,
608	&debug5, &debug6, &debug7, &debug8, &debug9,
609	&debug10, &debug11, &debug12, &debug13, &debug14,
610	&debug15, &debug16, &debug17, &debug18, &debug19,
611};
612static int
613debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
614	int *name;
615	u_int namelen;
616	void *oldp;
617	size_t *oldlenp;
618	void *newp;
619	size_t newlen;
620	struct proc *p;
621{
622	struct ctldebug *cdp;
623
624	/* all sysctl names at this level are name and field */
625	if (namelen != 2)
626		return (ENOTDIR);		/* overloaded */
627	cdp = debugvars[name[0]];
628	if (cdp->debugname == 0)
629		return (EOPNOTSUPP);
630	switch (name[1]) {
631	case CTL_DEBUG_NAME:
632		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
633	case CTL_DEBUG_VALUE:
634		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
635	default:
636		return (EOPNOTSUPP);
637	}
638	/* NOTREACHED */
639}
640#endif /* DEBUG */
641
642/*
643 * Validate parameters and get old / set new parameters
644 * for an integer-valued sysctl function.
645 */
646int
647sysctl_int(oldp, oldlenp, newp, newlen, valp)
648	void *oldp;
649	size_t *oldlenp;
650	void *newp;
651	size_t newlen;
652	int *valp;
653{
654	int error = 0;
655
656	if (oldp && *oldlenp < sizeof(int))
657		return (ENOMEM);
658	if (newp && newlen != sizeof(int))
659		return (EINVAL);
660	*oldlenp = sizeof(int);
661	if (oldp)
662		error = copyout(valp, oldp, sizeof(int));
663	if (error == 0 && newp)
664		error = copyin(newp, valp, sizeof(int));
665	return (error);
666}
667
668/*
669 * As above, but read-only.
670 */
671int
672sysctl_rdint(oldp, oldlenp, newp, val)
673	void *oldp;
674	size_t *oldlenp;
675	void *newp;
676	int val;
677{
678	int error = 0;
679
680	if (oldp && *oldlenp < sizeof(int))
681		return (ENOMEM);
682	if (newp)
683		return (EPERM);
684	*oldlenp = sizeof(int);
685	if (oldp)
686		error = copyout((caddr_t)&val, oldp, sizeof(int));
687	return (error);
688}
689
690/*
691 * Validate parameters and get old / set new parameters
692 * for a string-valued sysctl function.
693 */
694int
695sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
696	void *oldp;
697	size_t *oldlenp;
698	void *newp;
699	size_t newlen;
700	char *str;
701	int maxlen;
702{
703	int len, error = 0, rval = 0;
704
705	len = strlen(str) + 1;
706	if (oldp && *oldlenp < len) {
707		len = *oldlenp;
708		rval = ENOMEM;
709	}
710	if (newp && newlen >= maxlen)
711		return (EINVAL);
712	if (oldp) {
713		*oldlenp = len;
714		error = copyout(str, oldp, len);
715		if (error)
716			rval = error;
717	}
718	if ((error == 0 || error == ENOMEM) && newp) {
719		error = copyin(newp, str, newlen);
720		if (error)
721			rval = error;
722		str[newlen] = 0;
723	}
724	return (rval);
725}
726
727/*
728 * As above, but read-only.
729 */
730int
731sysctl_rdstring(oldp, oldlenp, newp, str)
732	void *oldp;
733	size_t *oldlenp;
734	void *newp;
735	char *str;
736{
737	int len, error = 0, rval = 0;
738
739	len = strlen(str) + 1;
740	if (oldp && *oldlenp < len) {
741		len = *oldlenp;
742		rval = ENOMEM;
743	}
744	if (newp)
745		return (EPERM);
746	*oldlenp = len;
747	if (oldp)
748		error = copyout(str, oldp, len);
749		if (error)
750			rval = error;
751	return (rval);
752}
753
754/*
755 * Validate parameters and get old / set new parameters
756 * for a structure oriented sysctl function.
757 */
758int
759sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
760	void *oldp;
761	size_t *oldlenp;
762	void *newp;
763	size_t newlen;
764	void *sp;
765	int len;
766{
767	int error = 0;
768
769	if (oldp && *oldlenp < len)
770		return (ENOMEM);
771	if (newp && newlen > len)
772		return (EINVAL);
773	if (oldp) {
774		*oldlenp = len;
775		error = copyout(sp, oldp, len);
776	}
777	if (error == 0 && newp)
778		error = copyin(newp, sp, len);
779	return (error);
780}
781
782/*
783 * Validate parameters and get old parameters
784 * for a structure oriented sysctl function.
785 */
786int
787sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
788	void *oldp;
789	size_t *oldlenp;
790	void *newp, *sp;
791	int len;
792{
793	int error = 0;
794
795	if (oldp && *oldlenp < len)
796		return (ENOMEM);
797	if (newp)
798		return (EPERM);
799	*oldlenp = len;
800	if (oldp)
801		error = copyout(sp, oldp, len);
802	return (error);
803}
804
805/*
806 * Get file structures.
807 */
808int
809sysctl_file(where, sizep)
810	char *where;
811	size_t *sizep;
812{
813	int buflen, error;
814	struct file *fp;
815	char *start = where;
816
817	buflen = *sizep;
818	if (where == NULL) {
819		/*
820		 * overestimate by 10 files
821		 */
822		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
823		return (0);
824	}
825
826	/*
827	 * first copyout filehead
828	 */
829	if (buflen < sizeof(filehead)) {
830		*sizep = 0;
831		return (0);
832	}
833	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
834	if (error)
835		return (error);
836	buflen -= sizeof(filehead);
837	where += sizeof(filehead);
838
839	/*
840	 * followed by an array of file structures
841	 */
842	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
843		if (buflen < sizeof(struct file)) {
844			*sizep = where - start;
845			return (ENOMEM);
846		}
847		error = copyout((caddr_t)fp, where, sizeof (struct file));
848		if (error)
849			return (error);
850		buflen -= sizeof(struct file);
851		where += sizeof(struct file);
852	}
853	*sizep = where - start;
854	return (0);
855}
856
857/*
858 * try over estimating by 5 procs
859 */
860#define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
861
862int
863sysctl_doproc(name, namelen, where, sizep)
864	int *name;
865	u_int namelen;
866	char *where;
867	size_t *sizep;
868{
869	register struct proc *p;
870	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
871	register int needed = 0;
872	int buflen = where != NULL ? *sizep : 0;
873	int doingzomb;
874	struct eproc eproc;
875	int error = 0;
876
877	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
878		return (EINVAL);
879	p = (struct proc *)allproc;
880	doingzomb = 0;
881again:
882	for (; p != NULL; p = p->p_next) {
883		/*
884		 * Skip embryonic processes.
885		 */
886		if (p->p_stat == SIDL)
887			continue;
888		/*
889		 * TODO - make more efficient (see notes below).
890		 * do by session.
891		 */
892		switch (name[0]) {
893
894		case KERN_PROC_PID:
895			/* could do this with just a lookup */
896			if (p->p_pid != (pid_t)name[1])
897				continue;
898			break;
899
900		case KERN_PROC_PGRP:
901			/* could do this by traversing pgrp */
902			if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1])
903				continue;
904			break;
905
906		case KERN_PROC_TTY:
907			if ((p->p_flag & P_CONTROLT) == 0 ||
908			    p->p_session == NULL ||
909			    p->p_session->s_ttyp == NULL ||
910			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
911				continue;
912			break;
913
914		case KERN_PROC_UID:
915			if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1])
916				continue;
917			break;
918
919		case KERN_PROC_RUID:
920			if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1])
921				continue;
922			break;
923		}
924		if (buflen >= sizeof(struct kinfo_proc)) {
925			fill_eproc(p, &eproc);
926			error = copyout((caddr_t)p, &dp->kp_proc,
927			    sizeof(struct proc));
928			if (error)
929				return (error);
930			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
931			    sizeof(eproc));
932			if (error)
933				return (error);
934			dp++;
935			buflen -= sizeof(struct kinfo_proc);
936		}
937		needed += sizeof(struct kinfo_proc);
938	}
939	if (doingzomb == 0) {
940		p = zombproc;
941		doingzomb++;
942		goto again;
943	}
944	if (where != NULL) {
945		*sizep = (caddr_t)dp - where;
946		if (needed > *sizep)
947			return (ENOMEM);
948	} else {
949		needed += KERN_PROCSLOP;
950		*sizep = needed;
951	}
952	return (0);
953}
954
955/*
956 * Fill in an eproc structure for the specified process.
957 */
958void
959fill_eproc(p, ep)
960	register struct proc *p;
961	register struct eproc *ep;
962{
963	register struct tty *tp;
964
965	bzero(ep, sizeof(*ep));
966
967	ep->e_paddr = p;
968	if (p->p_cred) {
969		ep->e_pcred = *p->p_cred;
970		if (p->p_ucred)
971			ep->e_ucred = *p->p_ucred;
972	}
973	if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) {
974		register struct vmspace *vm = p->p_vmspace;
975
976#ifdef pmap_resident_count
977		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
978#else
979		ep->e_vm.vm_rssize = vm->vm_rssize;
980#endif
981		ep->e_vm.vm_tsize = vm->vm_tsize;
982		ep->e_vm.vm_dsize = vm->vm_dsize;
983		ep->e_vm.vm_ssize = vm->vm_ssize;
984#ifndef sparc
985		ep->e_vm.vm_pmap = vm->vm_pmap;
986#endif
987	}
988	if (p->p_pptr)
989		ep->e_ppid = p->p_pptr->p_pid;
990	if (p->p_pgrp) {
991		ep->e_sess = p->p_pgrp->pg_session;
992		ep->e_pgid = p->p_pgrp->pg_id;
993		ep->e_jobc = p->p_pgrp->pg_jobc;
994	}
995	if ((p->p_flag & P_CONTROLT) &&
996	    (ep->e_sess != NULL) &&
997	    ((tp = ep->e_sess->s_ttyp) != NULL)) {
998		ep->e_tdev = tp->t_dev;
999		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
1000		ep->e_tsess = tp->t_session;
1001	} else
1002		ep->e_tdev = NODEV;
1003	if (ep->e_sess && ep->e_sess->s_ttyvp)
1004		ep->e_flag = EPROC_CTTY;
1005	if (SESS_LEADER(p))
1006		ep->e_flag |= EPROC_SLEADER;
1007	if (p->p_wmesg) {
1008		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
1009		ep->e_wmesg[WMESGLEN] = 0;
1010	}
1011}
1012
1013#ifdef COMPAT_43
1014#include <sys/socket.h>
1015#define	KINFO_PROC		(0<<8)
1016#define	KINFO_RT		(1<<8)
1017#define	KINFO_VNODE		(2<<8)
1018#define	KINFO_FILE		(3<<8)
1019#define	KINFO_METER		(4<<8)
1020#define	KINFO_LOADAVG		(5<<8)
1021#define	KINFO_CLOCKRATE		(6<<8)
1022
1023/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1024#define	KINFO_BSDI_SYSINFO	(101<<8)
1025
1026/*
1027 * XXX this is bloat, but I hope it's better here than on the potentially
1028 * limited kernel stack...  -Peter
1029 */
1030
1031struct {
1032	int	bsdi_machine;		/* "i386" on BSD/386 */
1033/*      ^^^ this is an offset to the string, relative to the struct start */
1034	char	*pad0;
1035	long	pad1;
1036	long	pad2;
1037	long	pad3;
1038	u_long	pad4;
1039	u_long	pad5;
1040	u_long	pad6;
1041
1042	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
1043	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
1044	long	pad7;
1045	long	pad8;
1046	char	*pad9;
1047
1048	long	pad10;
1049	long	pad11;
1050	int	pad12;
1051	long	pad13;
1052	quad_t	pad14;
1053	long	pad15;
1054
1055	struct	timeval pad16;
1056	/* we dont set this, because BSDI's uname used gethostname() instead */
1057	int	bsdi_hostname;		/* hostname on BSD/386 */
1058
1059	/* the actual string data is appended here */
1060
1061} bsdi_si;
1062/*
1063 * this data is appended to the end of the bsdi_si structure during copyout.
1064 * The "char *" offsets are relative to the base of the bsdi_si struct.
1065 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1066 * should not exceed the length of the buffer here... (or else!! :-)
1067 */
1068char bsdi_strings[80];	/* It had better be less than this! */
1069
1070struct getkerninfo_args {
1071	int	op;
1072	char	*where;
1073	int	*size;
1074	int	arg;
1075};
1076
1077int
1078ogetkerninfo(p, uap, retval)
1079	struct proc *p;
1080	register struct getkerninfo_args *uap;
1081	int *retval;
1082{
1083	int error, name[5];
1084	u_int size;
1085
1086	if (uap->size &&
1087	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
1088		return (error);
1089
1090	switch (uap->op & 0xff00) {
1091
1092	case KINFO_RT:
1093		name[0] = PF_ROUTE;
1094		name[1] = 0;
1095		name[2] = (uap->op & 0xff0000) >> 16;
1096		name[3] = uap->op & 0xff;
1097		name[4] = uap->arg;
1098		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
1099		break;
1100
1101	case KINFO_VNODE:
1102		name[0] = KERN_VNODE;
1103		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
1104		break;
1105
1106	case KINFO_PROC:
1107		name[0] = KERN_PROC;
1108		name[1] = uap->op & 0xff;
1109		name[2] = uap->arg;
1110		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
1111		break;
1112
1113	case KINFO_FILE:
1114		name[0] = KERN_FILE;
1115		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
1116		break;
1117
1118	case KINFO_METER:
1119		name[0] = VM_METER;
1120		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
1121		break;
1122
1123	case KINFO_LOADAVG:
1124		name[0] = VM_LOADAVG;
1125		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
1126		break;
1127
1128	case KINFO_CLOCKRATE:
1129		name[0] = KERN_CLOCKRATE;
1130		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
1131		break;
1132
1133	case KINFO_BSDI_SYSINFO: {
1134		/*
1135		 * this is pretty crude, but it's just enough for uname()
1136		 * from BSDI's 1.x libc to work.
1137		 *
1138		 * In particular, it doesn't return the same results when
1139		 * the supplied buffer is too small.  BSDI's version apparently
1140		 * will return the amount copied, and set the *size to how
1141		 * much was needed.  The emulation framework here isn't capable
1142		 * of that, so we just set both to the amount copied.
1143		 * BSDI's 2.x product apparently fails with ENOMEM in this
1144		 * scenario.
1145		 */
1146
1147		u_int needed;
1148		u_int left;
1149		char *s;
1150
1151		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1152		bzero(bsdi_strings, sizeof(bsdi_strings));
1153
1154		s = bsdi_strings;
1155
1156		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1157		strcpy(s, ostype);
1158		s += strlen(s) + 1;
1159
1160		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1161		strcpy(s, osrelease);
1162		s += strlen(s) + 1;
1163
1164		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1165		strcpy(s, machine);
1166		s += strlen(s) + 1;
1167
1168		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1169
1170		if (uap->where == NULL) {
1171			/* process is asking how much buffer to supply.. */
1172			size = needed;
1173			error = 0;
1174			break;
1175		}
1176
1177
1178		/* if too much buffer supplied, trim it down */
1179		if (size > needed)
1180			size = needed;
1181
1182		/* how much of the buffer is remaining */
1183		left = size;
1184
1185		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1186			break;
1187
1188		/* is there any point in continuing? */
1189		if (left > sizeof(bsdi_si)) {
1190			left -= sizeof(bsdi_si);
1191			error = copyout(&bsdi_strings,
1192					uap->where + sizeof(bsdi_si), left);
1193		}
1194		break;
1195	}
1196
1197	default:
1198		return (EOPNOTSUPP);
1199	}
1200	if (error)
1201		return (error);
1202	*retval = size;
1203	if (uap->size)
1204		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1205		    sizeof(size));
1206	return (error);
1207}
1208#endif /* COMPAT_43 */
1209