xref: /freebsd/sys/kern/kern_sysctl.c (revision 48991a368427cadb9cdac39581d1676c29619c52)
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.51 1995/11/16 18:59:49 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/vnode.h>
49 #include <sys/unistd.h>
50 #include <sys/conf.h>
51 #include <sys/sysctl.h>
52 
53 /*
54  * Locking and stats
55  */
56 static struct sysctl_lock {
57 	int	sl_lock;
58 	int	sl_want;
59 	int	sl_locked;
60 } memlock;
61 
62 static int sysctl_root SYSCTL_HANDLER_ARGS;
63 
64 extern struct linker_set sysctl_;
65 
66 /* BEGIN_MIB */
67 SYSCTL_NODE(, 0,	  sysctl, CTLFLAG_RW, 0,
68 	"Sysctl internal magic");
69 SYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW, 0,
70 	"High kernel, proc, limits &c");
71 SYSCTL_NODE(, CTL_VM,	  vm,     CTLFLAG_RW, 0,
72 	"Virtual memory");
73 SYSCTL_NODE(, CTL_FS,	  fs,     CTLFLAG_RW, 0,
74 	"File system");
75 SYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
76 	"Network, (see socket.h)");
77 SYSCTL_NODE(, CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
78 	"Debugging");
79 SYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
80 	"hardware");
81 SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
82 	"machine dependent");
83 SYSCTL_NODE(, CTL_USER,	  user,   CTLFLAG_RW, 0,
84 	"user-level");
85 
86 SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, "");
87 
88 SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, "");
89 
90 SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, "");
91 
92 SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "");
93 
94 extern int osreldate;
95 SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "");
96 
97 SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, "");
98 
99 SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, "");
100 
101 SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid,
102 	CTLFLAG_RD, &maxprocperuid, 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 #ifdef _POSIX_SAVED_IDS
113 SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, "");
114 #else
115 SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, "");
116 #endif
117 
118 char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
119 
120 SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile,
121 	CTLFLAG_RW, kernelname, sizeof kernelname, "");
122 
123 SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime,
124 	CTLFLAG_RW, &boottime, timeval, "");
125 
126 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
127 
128 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
129 
130 SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, "");
131 
132 SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, "");
133 
134 SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, "");
135 
136 /* END_MIB */
137 
138 extern int vfs_update_wakeup;
139 extern int vfs_update_interval;
140 static int
141 sysctl_kern_updateinterval SYSCTL_HANDLER_ARGS
142 {
143 	int error = sysctl_handle_int(oidp,
144 		oidp->oid_arg1, oidp->oid_arg2, req);
145 	if (!error)
146 		wakeup(&vfs_update_wakeup);
147 	return error;
148 }
149 
150 SYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW,
151 	&vfs_update_interval, 0, sysctl_kern_updateinterval, "");
152 
153 
154 char hostname[MAXHOSTNAMELEN];
155 
156 SYSCTL_STRING(_kern, KERN_HOSTNAME, hostname, CTLFLAG_RW,
157 	hostname, sizeof(hostname), "");
158 
159 int securelevel = -1;
160 
161 static int
162 sysctl_kern_securelvl SYSCTL_HANDLER_ARGS
163 {
164 		int error, level;
165 
166 		level = securelevel;
167 		error = sysctl_handle_int(oidp, &level, 0, req);
168 		if (error || !req->newptr)
169 			return (error);
170 		if (level < securelevel && req->p->p_pid != 1)
171 			return (EPERM);
172 		securelevel = level;
173 		return (error);
174 }
175 
176 SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW,
177 	0, 0, sysctl_kern_securelvl, "");
178 
179 static int
180 sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
181 {
182 	int error;
183 	dev_t ndumpdev;
184 
185 	ndumpdev = dumpdev;
186 	error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
187 	if (!error && ndumpdev != dumpdev) {
188 		error = setdumpdev(ndumpdev);
189 	}
190 	return (error);
191 }
192 
193 SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
194 	0, sizeof dumpdev, sysctl_kern_dumpdev, "");
195 
196 static int
197 sysctl_hw_physmem SYSCTL_HANDLER_ARGS
198 {
199 	int error = sysctl_handle_int(oidp, 0, ctob(physmem), req);
200 	return (error);
201 }
202 
203 SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD,
204 	0, 0, sysctl_hw_physmem, "");
205 
206 static int
207 sysctl_hw_usermem SYSCTL_HANDLER_ARGS
208 {
209 	int error = sysctl_handle_int(oidp, 0,
210 		ctob(physmem - cnt.v_wire_count), req);
211 	return (error);
212 }
213 
214 SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD,
215 	0, 0, sysctl_hw_usermem, "");
216 
217 /* END_MIB */
218 
219 static int
220 sysctl_order_cmp(const void *a, const void *b)
221 {
222 	const struct sysctl_oid **pa, **pb;
223 
224 	pa = (const struct sysctl_oid **)a;
225 	pb = (const struct sysctl_oid **)b;
226 	if (*pa == NULL)
227 		return (1);
228 	if (*pb == NULL)
229 		return (-1);
230 	return ((*pa)->oid_number - (*pb)->oid_number);
231 }
232 
233 static void
234 sysctl_order(void *arg)
235 {
236 	int j;
237 	struct linker_set *l = (struct linker_set *) arg;
238 	struct sysctl_oid **oidpp;
239 
240 	j = l->ls_length;
241 	oidpp = (struct sysctl_oid **) l->ls_items;
242 	for (; j--; oidpp++) {
243 		if (!*oidpp)
244 			continue;
245 		if ((*oidpp)->oid_arg1 == arg) {
246 			*oidpp = 0;
247 			continue;
248 		}
249 		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
250 			if (!(*oidpp)->oid_handler)
251 				sysctl_order((*oidpp)->oid_arg1);
252 	}
253 	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
254 		sysctl_order_cmp);
255 }
256 
257 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
258 
259 static void
260 sysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
261 {
262 	int j, k;
263 	struct sysctl_oid **oidpp;
264 
265 	j = l->ls_length;
266 	oidpp = (struct sysctl_oid **) l->ls_items;
267 	for (; j--; oidpp++) {
268 
269 		if (!*oidpp)
270 			continue;
271 
272 		for (k=0; k<i; k++)
273 			printf(" ");
274 
275 		if ((*oidpp)->oid_number > 100) {
276 			printf("Junk! %p  # %d  %s  k %x  a1 %p  a2 %x  h %p\n",
277 				*oidpp,
278 		 		(*oidpp)->oid_number, (*oidpp)->oid_name,
279 		 		(*oidpp)->oid_kind, (*oidpp)->oid_arg1,
280 		 		(*oidpp)->oid_arg2, (*oidpp)->oid_handler);
281 			continue;
282 		}
283 		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
284 
285 		printf("%c%c",
286 			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
287 			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
288 
289 		switch ((*oidpp)->oid_kind & CTLTYPE) {
290 			case CTLTYPE_NODE:
291 				if ((*oidpp)->oid_handler) {
292 					printf(" Node(proc)\n");
293 				} else {
294 					printf(" Node\n");
295 					sysctl_sysctl_debug_dump_node(
296 						(*oidpp)->oid_arg1, i+2);
297 				}
298 				break;
299 			case CTLTYPE_INT:    printf(" Int\n"); break;
300 			case CTLTYPE_STRING: printf(" String\n"); break;
301 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
302 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
303 			default:	     printf("\n");
304 		}
305 
306 	}
307 }
308 
309 
310 static int
311 sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
312 {
313 	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
314 	return ENOENT;
315 }
316 
317 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
318 	0, 0, sysctl_sysctl_debug, "");
319 
320 char domainname[MAXHOSTNAMELEN];
321 SYSCTL_STRING(_kern, KERN_DOMAINNAME, domainname, CTLFLAG_RW,
322 	&domainname, sizeof(domainname), "");
323 
324 long hostid;
325 /* Some trouble here, if sizeof (int) != sizeof (long) */
326 SYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "");
327 
328 /*
329  * Handle an integer, signed or unsigned.
330  * Two cases:
331  *     a variable:  point arg1 at it.
332  *     a constant:  pass it in arg2.
333  */
334 
335 int
336 sysctl_handle_int SYSCTL_HANDLER_ARGS
337 {
338 	int error = 0;
339 
340 	if (arg1)
341 		error = SYSCTL_OUT(req, arg1, sizeof(int));
342 	else if (arg2)
343 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
344 
345 	if (error || !req->newptr)
346 		return (error);
347 
348 	if (!arg1)
349 		error = EPERM;
350 	else
351 		error = SYSCTL_IN(req, arg1, sizeof(int));
352 	return (error);
353 }
354 
355 /*
356  * Handle our generic '\0' terminated 'C' string.
357  * Two cases:
358  * 	a variable string:  point arg1 at it, arg2 is max length.
359  * 	a constant string:  point arg1 at it, arg2 is zero.
360  */
361 
362 int
363 sysctl_handle_string SYSCTL_HANDLER_ARGS
364 {
365 	int error=0;
366 
367 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
368 
369 	if (error || !req->newptr || !arg2)
370 		return (error);
371 
372 	if ((req->newlen - req->newidx) > arg2) {
373 		error = E2BIG;
374 	} else {
375 		arg2 = (req->newlen - req->newidx);
376 		error = SYSCTL_IN(req, arg1, arg2);
377 		((char *)arg1)[arg2] = '\0';
378 	}
379 
380 	return (error);
381 }
382 
383 /*
384  * Handle any kind of opaque data.
385  * arg1 points to it, arg2 is the size.
386  */
387 
388 int
389 sysctl_handle_opaque SYSCTL_HANDLER_ARGS
390 {
391 	int error;
392 
393 	error = SYSCTL_OUT(req, arg1, arg2);
394 
395 	if (error || !req->newptr)
396 		return (error);
397 
398 	error = SYSCTL_IN(req, arg1, arg2);
399 
400 	return (error);
401 }
402 
403 /*
404  * Transfer functions to/from kernel space.
405  * XXX: rather untested at this point
406  */
407 static int
408 sysctl_old_kernel(struct sysctl_req *req, void *p, int l)
409 {
410 	int i = 0;
411 
412 	if (req->oldptr) {
413 		i = min(req->oldlen - req->oldidx, l);
414 		if (i > 0)
415 			bcopy(p, req->oldptr + req->oldidx, i);
416 	}
417 	req->oldidx += l;
418 	if (i != l)
419 		return (ENOMEM);
420 	return (0);
421 
422 }
423 
424 static int
425 sysctl_new_kernel(struct sysctl_req *req, void *p, int l)
426 {
427 	if (!req->newptr)
428 		return 0;
429 	if (req->newlen - req->newidx < l)
430 		return (EINVAL);
431 	bcopy(req->newptr + req->newidx, p, l);
432 	req->newidx += l;
433 	return (0);
434 }
435 
436 /*
437  * Transfer function to/from user space.
438  */
439 static int
440 sysctl_old_user(struct sysctl_req *req, void *p, int l)
441 {
442 	int error = 0, i = 0;
443 
444 	if (req->lock == 1 && req->oldptr) {
445 		vslock(req->oldptr, req->oldlen);
446 		req->lock = 2;
447 	}
448 	if (req->oldptr) {
449 		i = min(req->oldlen - req->oldidx, l);
450 		if (i > 0)
451 			error  = copyout(p, req->oldptr + req->oldidx, i);
452 	}
453 	req->oldidx += l;
454 	if (error)
455 		return (error);
456 	if (req->oldptr && i < l)
457 		return (ENOMEM);
458 	return (0);
459 }
460 
461 static int
462 sysctl_new_user(struct sysctl_req *req, void *p, int l)
463 {
464 	int error;
465 
466 	if (!req->newptr)
467 		return 0;
468 	if (req->newlen - req->newidx < l)
469 		return (EINVAL);
470 	error = copyin(req->newptr + req->newidx, p, l);
471 	req->newidx += l;
472 	return (error);
473 }
474 
475 /*
476  * Traverse our tree, and find the right node, execute whatever it points
477  * at, and return the resulting error code.
478  */
479 
480 int
481 sysctl_root SYSCTL_HANDLER_ARGS
482 {
483 	int *name = (int *) arg1;
484 	int namelen = arg2;
485 	int indx, i, j;
486 	struct sysctl_oid **oidpp;
487 	struct linker_set *lsp = &sysctl_;
488 
489 	j = lsp->ls_length;
490 	oidpp = (struct sysctl_oid **) lsp->ls_items;
491 
492 	indx = 0;
493 	while (j-- && indx < CTL_MAXNAME) {
494 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
495 			indx++;
496 			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
497 				req->lock = 0;
498 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
499 				if ((*oidpp)->oid_handler)
500 					goto found;
501 				if (indx == namelen)
502 					return ENOENT;
503 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
504 				j = lsp->ls_length;
505 				oidpp = (struct sysctl_oid **)lsp->ls_items;
506 			} else {
507 				if (indx != namelen)
508 					return EISDIR;
509 				goto found;
510 			}
511 		} else {
512 			oidpp++;
513 		}
514 	}
515 	return ENOENT;
516 found:
517 
518 	/* If writing isn't allowed */
519 	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
520 		return (EPERM);
521 
522 	if (!(*oidpp)->oid_handler)
523 		return EINVAL;
524 
525 	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
526 		i = ((*oidpp)->oid_handler) (*oidpp,
527 					name + indx, namelen - indx,
528 					req);
529 	} else {
530 		i = ((*oidpp)->oid_handler) (*oidpp,
531 					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
532 					req);
533 	}
534 	return (i);
535 }
536 
537 #ifndef _SYS_SYSPROTO_H_
538 struct sysctl_args {
539 	int	*name;
540 	u_int	namelen;
541 	void	*old;
542 	size_t	*oldlenp;
543 	void	*new;
544 	size_t	newlen;
545 };
546 #endif
547 
548 int
549 __sysctl(struct proc *p, struct sysctl_args *uap, int *retval)
550 {
551 	int error, i, j, name[CTL_MAXNAME];
552 
553 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
554 		return (EINVAL);
555 
556  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
557  	if (error)
558 		return (error);
559 
560 	error = userland_sysctl(p, name, uap->namelen,
561 		uap->old, uap->oldlenp, 0,
562 		uap->new, uap->newlen, &j);
563 	if (error && error != ENOMEM)
564 		return (error);
565 	if (uap->oldlenp) {
566 		i = copyout(&j, uap->oldlenp, sizeof(j));
567 		if (i)
568 			return (i);
569 	}
570 	return (error);
571 }
572 
573 /*
574  * This is used from various compatibility syscalls too.  That's why name
575  * must be in kernel space.
576  */
577 int
578 userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval)
579 {
580 	int error = 0;
581 	struct sysctl_req req;
582 
583 	bzero(&req, sizeof req);
584 
585 	req.p = p;
586 
587 	if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
588 		return (error);
589 
590 	if (oldlenp) {
591 		if (inkernel) {
592 			req.oldlen = *oldlenp;
593 		} else {
594 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
595 			if (error)
596 				return (error);
597 		}
598 	}
599 
600 	if (old) {
601 		if (!useracc(old, req.oldlen, B_WRITE))
602 			return (EFAULT);
603 		req.oldptr= old;
604 	}
605 
606 	if (newlen) {
607 		if (!useracc(new, req.newlen, B_READ))
608 			return (EFAULT);
609 		req.newlen = newlen;
610 		req.newptr = new;
611 	}
612 
613 	req.oldfunc = sysctl_old_user;
614 	req.newfunc = sysctl_new_user;
615 	req.lock = 1;
616 
617 	/* XXX this should probably be done in a general way */
618 	while (memlock.sl_lock) {
619 		memlock.sl_want = 1;
620 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
621 		memlock.sl_locked++;
622 	}
623 	memlock.sl_lock = 1;
624 
625 	error = sysctl_root(0, name, namelen, &req);
626 
627 	if (req.lock == 2)
628 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
629 
630 	memlock.sl_lock = 0;
631 
632 	if (memlock.sl_want) {
633 		memlock.sl_want = 0;
634 		wakeup((caddr_t)&memlock);
635 	}
636 
637 	if (error && error != ENOMEM)
638 		return (error);
639 
640 	if (retval) {
641 		if (req.oldptr && req.oldidx > req.oldlen)
642 			*retval = req.oldlen;
643 		else
644 			*retval = req.oldidx;
645 	}
646 	return (error);
647 }
648 
649 #ifdef COMPAT_43
650 #include <sys/socket.h>
651 #define	KINFO_PROC		(0<<8)
652 #define	KINFO_RT		(1<<8)
653 #define	KINFO_VNODE		(2<<8)
654 #define	KINFO_FILE		(3<<8)
655 #define	KINFO_METER		(4<<8)
656 #define	KINFO_LOADAVG		(5<<8)
657 #define	KINFO_CLOCKRATE		(6<<8)
658 
659 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
660 #define	KINFO_BSDI_SYSINFO	(101<<8)
661 
662 /*
663  * XXX this is bloat, but I hope it's better here than on the potentially
664  * limited kernel stack...  -Peter
665  */
666 
667 struct {
668 	int	bsdi_machine;		/* "i386" on BSD/386 */
669 /*      ^^^ this is an offset to the string, relative to the struct start */
670 	char	*pad0;
671 	long	pad1;
672 	long	pad2;
673 	long	pad3;
674 	u_long	pad4;
675 	u_long	pad5;
676 	u_long	pad6;
677 
678 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
679 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
680 	long	pad7;
681 	long	pad8;
682 	char	*pad9;
683 
684 	long	pad10;
685 	long	pad11;
686 	int	pad12;
687 	long	pad13;
688 	quad_t	pad14;
689 	long	pad15;
690 
691 	struct	timeval pad16;
692 	/* we dont set this, because BSDI's uname used gethostname() instead */
693 	int	bsdi_hostname;		/* hostname on BSD/386 */
694 
695 	/* the actual string data is appended here */
696 
697 } bsdi_si;
698 /*
699  * this data is appended to the end of the bsdi_si structure during copyout.
700  * The "char *" offsets are relative to the base of the bsdi_si struct.
701  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
702  * should not exceed the length of the buffer here... (or else!! :-)
703  */
704 char bsdi_strings[80];	/* It had better be less than this! */
705 
706 #ifndef _SYS_SYSPROTO_H_
707 struct getkerninfo_args {
708 	int	op;
709 	char	*where;
710 	int	*size;
711 	int	arg;
712 };
713 #endif
714 
715 int
716 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap, int *retval)
717 {
718 	int error, name[6];
719 	u_int size;
720 
721 	switch (uap->op & 0xff00) {
722 
723 	case KINFO_RT:
724 		name[0] = CTL_NET;
725 		name[1] = PF_ROUTE;
726 		name[2] = 0;
727 		name[3] = (uap->op & 0xff0000) >> 16;
728 		name[4] = uap->op & 0xff;
729 		name[5] = uap->arg;
730 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
731 			0, 0, 0, &size);
732 		break;
733 
734 	case KINFO_VNODE:
735 		name[0] = CTL_KERN;
736 		name[1] = KERN_VNODE;
737 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
738 			0, 0, 0, &size);
739 		break;
740 
741 	case KINFO_PROC:
742 		name[0] = CTL_KERN;
743 		name[1] = KERN_PROC;
744 		name[2] = uap->op & 0xff;
745 		name[3] = uap->arg;
746 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
747 			0, 0, 0, &size);
748 		break;
749 
750 	case KINFO_FILE:
751 		name[0] = CTL_KERN;
752 		name[1] = KERN_FILE;
753 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
754 			0, 0, 0, &size);
755 		break;
756 
757 	case KINFO_METER:
758 		name[0] = CTL_VM;
759 		name[1] = VM_METER;
760 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
761 			0, 0, 0, &size);
762 		break;
763 
764 	case KINFO_LOADAVG:
765 		name[0] = CTL_VM;
766 		name[1] = VM_LOADAVG;
767 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
768 			0, 0, 0, &size);
769 		break;
770 
771 	case KINFO_CLOCKRATE:
772 		name[0] = CTL_KERN;
773 		name[1] = KERN_CLOCKRATE;
774 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
775 			0, 0, 0, &size);
776 		break;
777 
778 	case KINFO_BSDI_SYSINFO: {
779 		/*
780 		 * this is pretty crude, but it's just enough for uname()
781 		 * from BSDI's 1.x libc to work.
782 		 *
783 		 * In particular, it doesn't return the same results when
784 		 * the supplied buffer is too small.  BSDI's version apparently
785 		 * will return the amount copied, and set the *size to how
786 		 * much was needed.  The emulation framework here isn't capable
787 		 * of that, so we just set both to the amount copied.
788 		 * BSDI's 2.x product apparently fails with ENOMEM in this
789 		 * scenario.
790 		 */
791 
792 		u_int needed;
793 		u_int left;
794 		char *s;
795 
796 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
797 		bzero(bsdi_strings, sizeof(bsdi_strings));
798 
799 		s = bsdi_strings;
800 
801 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
802 		strcpy(s, ostype);
803 		s += strlen(s) + 1;
804 
805 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
806 		strcpy(s, osrelease);
807 		s += strlen(s) + 1;
808 
809 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
810 		strcpy(s, machine);
811 		s += strlen(s) + 1;
812 
813 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
814 
815 		if (uap->where == NULL) {
816 			/* process is asking how much buffer to supply.. */
817 			size = needed;
818 			error = 0;
819 			break;
820 		}
821 
822 
823 		/* if too much buffer supplied, trim it down */
824 		if (size > needed)
825 			size = needed;
826 
827 		/* how much of the buffer is remaining */
828 		left = size;
829 
830 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
831 			break;
832 
833 		/* is there any point in continuing? */
834 		if (left > sizeof(bsdi_si)) {
835 			left -= sizeof(bsdi_si);
836 			error = copyout(&bsdi_strings,
837 					uap->where + sizeof(bsdi_si), left);
838 		}
839 		break;
840 	}
841 
842 	default:
843 		return (EOPNOTSUPP);
844 	}
845 	if (error)
846 		return (error);
847 	*retval = size;
848 	if (uap->size)
849 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
850 		    sizeof(size));
851 	return (error);
852 }
853 #endif /* COMPAT_43 */
854