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