xref: /dragonfly/sys/kern/kern_sysctl.c (revision 6e285212)
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  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
9  * project, to make these variables more userfriendly.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
40  * $FreeBSD: src/sys/kern/kern_sysctl.c,v 1.92.2.9 2003/05/01 22:48:09 trhodes Exp $
41  * $DragonFly: src/sys/kern/kern_sysctl.c,v 1.2 2003/06/17 04:28:41 dillon Exp $
42  */
43 
44 #include "opt_compat.h"
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/buf.h>
50 #include <sys/sysctl.h>
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53 #include <sys/sysproto.h>
54 #include <vm/vm.h>
55 #include <vm/vm_extern.h>
56 
57 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
58 static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
59 
60 /*
61  * Locking and stats
62  */
63 static struct sysctl_lock {
64 	int	sl_lock;
65 	int	sl_want;
66 	int	sl_locked;
67 } memlock;
68 
69 static int sysctl_root(SYSCTL_HANDLER_ARGS);
70 
71 struct sysctl_oid_list sysctl__children; /* root list */
72 
73 static struct sysctl_oid *
74 sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
75 {
76 	struct sysctl_oid *oidp;
77 
78 	SLIST_FOREACH(oidp, list, oid_link) {
79 		if (strcmp(oidp->oid_name, name) == 0) {
80 			return (oidp);
81 		}
82 	}
83 	return (NULL);
84 }
85 
86 /*
87  * Initialization of the MIB tree.
88  *
89  * Order by number in each list.
90  */
91 
92 void sysctl_register_oid(struct sysctl_oid *oidp)
93 {
94 	struct sysctl_oid_list *parent = oidp->oid_parent;
95 	struct sysctl_oid *p;
96 	struct sysctl_oid *q;
97 	int n;
98 
99 	/*
100 	 * First check if another oid with the same name already
101 	 * exists in the parent's list.
102 	 */
103 	p = sysctl_find_oidname(oidp->oid_name, parent);
104 	if (p != NULL) {
105 		if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
106 			p->oid_refcnt++;
107 			return;
108 		} else {
109 			printf("can't re-use a leaf (%s)!\n", p->oid_name);
110 			return;
111 		}
112 	}
113 	/*
114 	 * If this oid has a number OID_AUTO, give it a number which
115 	 * is greater than any current oid.  Make sure it is at least
116 	 * 100 to leave space for pre-assigned oid numbers.
117 	 */
118 	if (oidp->oid_number == OID_AUTO) {
119 		/* First, find the highest oid in the parent list >99 */
120 		n = 99;
121 		SLIST_FOREACH(p, parent, oid_link) {
122 			if (p->oid_number > n)
123 				n = p->oid_number;
124 		}
125 		oidp->oid_number = n + 1;
126 	}
127 
128 	/*
129 	 * Insert the oid into the parent's list in order.
130 	 */
131 	q = NULL;
132 	SLIST_FOREACH(p, parent, oid_link) {
133 		if (oidp->oid_number < p->oid_number)
134 			break;
135 		q = p;
136 	}
137 	if (q)
138 		SLIST_INSERT_AFTER(q, oidp, oid_link);
139 	else
140 		SLIST_INSERT_HEAD(parent, oidp, oid_link);
141 }
142 
143 void sysctl_unregister_oid(struct sysctl_oid *oidp)
144 {
145 
146 	SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
147 }
148 
149 /* Initialize a new context to keep track of dynamically added sysctls. */
150 int
151 sysctl_ctx_init(struct sysctl_ctx_list *c)
152 {
153 
154 	if (c == NULL) {
155 		return (EINVAL);
156 	}
157 	TAILQ_INIT(c);
158 	return (0);
159 }
160 
161 /* Free the context, and destroy all dynamic oids registered in this context */
162 int
163 sysctl_ctx_free(struct sysctl_ctx_list *clist)
164 {
165 	struct sysctl_ctx_entry *e, *e1;
166 	int error;
167 
168 	error = 0;
169 	/*
170 	 * First perform a "dry run" to check if it's ok to remove oids.
171 	 * XXX FIXME
172 	 * XXX This algorithm is a hack. But I don't know any
173 	 * XXX better solution for now...
174 	 */
175 	TAILQ_FOREACH(e, clist, link) {
176 		error = sysctl_remove_oid(e->entry, 0, 0);
177 		if (error)
178 			break;
179 	}
180 	/*
181 	 * Restore deregistered entries, either from the end,
182 	 * or from the place where error occured.
183 	 * e contains the entry that was not unregistered
184 	 */
185 	if (error)
186 		e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
187 	else
188 		e1 = TAILQ_LAST(clist, sysctl_ctx_list);
189 	while (e1 != NULL) {
190 		sysctl_register_oid(e1->entry);
191 		e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
192 	}
193 	if (error)
194 		return(EBUSY);
195 	/* Now really delete the entries */
196 	e = TAILQ_FIRST(clist);
197 	while (e != NULL) {
198 		e1 = TAILQ_NEXT(e, link);
199 		error = sysctl_remove_oid(e->entry, 1, 0);
200 		if (error)
201 			panic("sysctl_remove_oid: corrupt tree, entry: %s",
202 			    e->entry->oid_name);
203 		free(e, M_SYSCTLOID);
204 		e = e1;
205 	}
206 	return (error);
207 }
208 
209 /* Add an entry to the context */
210 struct sysctl_ctx_entry *
211 sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
212 {
213 	struct sysctl_ctx_entry *e;
214 
215 	if (clist == NULL || oidp == NULL)
216 		return(NULL);
217 	e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
218 	e->entry = oidp;
219 	TAILQ_INSERT_HEAD(clist, e, link);
220 	return (e);
221 }
222 
223 /* Find an entry in the context */
224 struct sysctl_ctx_entry *
225 sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
226 {
227 	struct sysctl_ctx_entry *e;
228 
229 	if (clist == NULL || oidp == NULL)
230 		return(NULL);
231 	for (e = TAILQ_FIRST(clist); e != NULL; e = TAILQ_NEXT(e, link)) {
232 		if(e->entry == oidp)
233 			return(e);
234 	}
235 	return (e);
236 }
237 
238 /*
239  * Delete an entry from the context.
240  * NOTE: this function doesn't free oidp! You have to remove it
241  * with sysctl_remove_oid().
242  */
243 int
244 sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
245 {
246 	struct sysctl_ctx_entry *e;
247 
248 	if (clist == NULL || oidp == NULL)
249 		return (EINVAL);
250 	e = sysctl_ctx_entry_find(clist, oidp);
251 	if (e != NULL) {
252 		TAILQ_REMOVE(clist, e, link);
253 		free(e, M_SYSCTLOID);
254 		return (0);
255 	} else
256 		return (ENOENT);
257 }
258 
259 /*
260  * Remove dynamically created sysctl trees.
261  * oidp - top of the tree to be removed
262  * del - if 0 - just deregister, otherwise free up entries as well
263  * recurse - if != 0 traverse the subtree to be deleted
264  */
265 int
266 sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
267 {
268 	struct sysctl_oid *p;
269 	int error;
270 
271 	if (oidp == NULL)
272 		return(EINVAL);
273 	if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
274 		printf("can't remove non-dynamic nodes!\n");
275 		return (EINVAL);
276 	}
277 	/*
278 	 * WARNING: normal method to do this should be through
279 	 * sysctl_ctx_free(). Use recursing as the last resort
280 	 * method to purge your sysctl tree of leftovers...
281 	 * However, if some other code still references these nodes,
282 	 * it will panic.
283 	 */
284 	if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
285 		if (oidp->oid_refcnt == 1) {
286 			SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
287 				if (!recurse)
288 					return (ENOTEMPTY);
289 				error = sysctl_remove_oid(p, del, recurse);
290 				if (error)
291 					return (error);
292 			}
293 			if (del)
294 				free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
295 		}
296 	}
297 	if (oidp->oid_refcnt > 1 ) {
298 		oidp->oid_refcnt--;
299 	} else {
300 		if (oidp->oid_refcnt == 0) {
301 			printf("Warning: bad oid_refcnt=%u (%s)!\n",
302 				oidp->oid_refcnt, oidp->oid_name);
303 			return (EINVAL);
304 		}
305 		sysctl_unregister_oid(oidp);
306 		if (del) {
307 			if (oidp->oid_descr)
308 				free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID);
309 			free((void *)(uintptr_t)(const void *)oidp->oid_name,
310 			     M_SYSCTLOID);
311 			free(oidp, M_SYSCTLOID);
312 		}
313 	}
314 	return (0);
315 }
316 
317 /*
318  * Create new sysctls at run time.
319  * clist may point to a valid context initialized with sysctl_ctx_init().
320  */
321 struct sysctl_oid *
322 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
323 	int number, const char *name, int kind, void *arg1, int arg2,
324 	int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
325 {
326 	struct sysctl_oid *oidp;
327 	ssize_t len;
328 	char *newname;
329 
330 	/* You have to hook up somewhere.. */
331 	if (parent == NULL)
332 		return(NULL);
333 	/* Check if the node already exists, otherwise create it */
334 	oidp = sysctl_find_oidname(name, parent);
335 	if (oidp != NULL) {
336 		if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
337 			oidp->oid_refcnt++;
338 			/* Update the context */
339 			if (clist != NULL)
340 				sysctl_ctx_entry_add(clist, oidp);
341 			return (oidp);
342 		} else {
343 			printf("can't re-use a leaf (%s)!\n", name);
344 			return (NULL);
345 		}
346 	}
347 	oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK);
348 	bzero(oidp, sizeof(struct sysctl_oid));
349 	oidp->oid_parent = parent;
350 	SLIST_NEXT(oidp, oid_link) = NULL;
351 	oidp->oid_number = number;
352 	oidp->oid_refcnt = 1;
353 	len = strlen(name);
354 	newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
355 	bcopy(name, newname, len + 1);
356 	newname[len] = '\0';
357 	oidp->oid_name = newname;
358 	oidp->oid_handler = handler;
359 	oidp->oid_kind = CTLFLAG_DYN | kind;
360 	if ((kind & CTLTYPE) == CTLTYPE_NODE) {
361 		/* Allocate space for children */
362 		SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list),
363 		    M_SYSCTLOID, M_WAITOK);
364 		SLIST_INIT(SYSCTL_CHILDREN(oidp));
365 	} else {
366 		oidp->oid_arg1 = arg1;
367 		oidp->oid_arg2 = arg2;
368 	}
369 	oidp->oid_fmt = fmt;
370 	if (descr) {
371 		int len = strlen(descr) + 1;
372 		oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK);
373 		if (oidp->oid_descr)
374 			strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
375 	};
376 	/* Update the context, if used */
377 	if (clist != NULL)
378 		sysctl_ctx_entry_add(clist, oidp);
379 	/* Register this oid */
380 	sysctl_register_oid(oidp);
381 	return (oidp);
382 }
383 
384 /*
385  * Bulk-register all the oids in a linker_set.
386  */
387 void sysctl_register_set(struct linker_set *lsp)
388 {
389 	int count = lsp->ls_length;
390 	int i;
391 	for (i = 0; i < count; i++)
392 		sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
393 }
394 
395 void sysctl_unregister_set(struct linker_set *lsp)
396 {
397 	int count = lsp->ls_length;
398 	int i;
399 	for (i = 0; i < count; i++)
400 		sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
401 }
402 
403 /*
404  * Register the kernel's oids on startup.
405  */
406 extern struct linker_set sysctl_set;
407 
408 static void sysctl_register_all(void *arg)
409 {
410 
411 	sysctl_register_set(&sysctl_set);
412 }
413 
414 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
415 
416 /*
417  * "Staff-functions"
418  *
419  * These functions implement a presently undocumented interface
420  * used by the sysctl program to walk the tree, and get the type
421  * so it can print the value.
422  * This interface is under work and consideration, and should probably
423  * be killed with a big axe by the first person who can find the time.
424  * (be aware though, that the proper interface isn't as obvious as it
425  * may seem, there are various conflicting requirements.
426  *
427  * {0,0}	printf the entire MIB-tree.
428  * {0,1,...}	return the name of the "..." OID.
429  * {0,2,...}	return the next OID.
430  * {0,3}	return the OID of the name in "new"
431  * {0,4,...}	return the kind & format info for the "..." OID.
432  */
433 
434 static void
435 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
436 {
437 	int k;
438 	struct sysctl_oid *oidp;
439 
440 	SLIST_FOREACH(oidp, l, oid_link) {
441 
442 		for (k=0; k<i; k++)
443 			printf(" ");
444 
445 		printf("%d %s ", oidp->oid_number, oidp->oid_name);
446 
447 		printf("%c%c",
448 			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
449 			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
450 
451 		if (oidp->oid_handler)
452 			printf(" *Handler");
453 
454 		switch (oidp->oid_kind & CTLTYPE) {
455 			case CTLTYPE_NODE:
456 				printf(" Node\n");
457 				if (!oidp->oid_handler) {
458 					sysctl_sysctl_debug_dump_node(
459 						oidp->oid_arg1, i+2);
460 				}
461 				break;
462 			case CTLTYPE_INT:    printf(" Int\n"); break;
463 			case CTLTYPE_STRING: printf(" String\n"); break;
464 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
465 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
466 			default:	     printf("\n");
467 		}
468 
469 	}
470 }
471 
472 static int
473 sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
474 {
475 	int error;
476 
477 	error = suser(req->p);
478 	if (error)
479 		return error;
480 	sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
481 	return ENOENT;
482 }
483 
484 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
485 	0, 0, sysctl_sysctl_debug, "-", "");
486 
487 static int
488 sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
489 {
490 	int *name = (int *) arg1;
491 	u_int namelen = arg2;
492 	int error = 0;
493 	struct sysctl_oid *oid;
494 	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
495 	char buf[10];
496 
497 	while (namelen) {
498 		if (!lsp) {
499 			snprintf(buf,sizeof(buf),"%d",*name);
500 			if (req->oldidx)
501 				error = SYSCTL_OUT(req, ".", 1);
502 			if (!error)
503 				error = SYSCTL_OUT(req, buf, strlen(buf));
504 			if (error)
505 				return (error);
506 			namelen--;
507 			name++;
508 			continue;
509 		}
510 		lsp2 = 0;
511 		SLIST_FOREACH(oid, lsp, oid_link) {
512 			if (oid->oid_number != *name)
513 				continue;
514 
515 			if (req->oldidx)
516 				error = SYSCTL_OUT(req, ".", 1);
517 			if (!error)
518 				error = SYSCTL_OUT(req, oid->oid_name,
519 					strlen(oid->oid_name));
520 			if (error)
521 				return (error);
522 
523 			namelen--;
524 			name++;
525 
526 			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
527 				break;
528 
529 			if (oid->oid_handler)
530 				break;
531 
532 			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
533 			break;
534 		}
535 		lsp = lsp2;
536 	}
537 	return (SYSCTL_OUT(req, "", 1));
538 }
539 
540 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
541 
542 static int
543 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
544 	int *next, int *len, int level, struct sysctl_oid **oidpp)
545 {
546 	struct sysctl_oid *oidp;
547 
548 	*len = level;
549 	SLIST_FOREACH(oidp, lsp, oid_link) {
550 		*next = oidp->oid_number;
551 		*oidpp = oidp;
552 
553 		if (!namelen) {
554 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
555 				return 0;
556 			if (oidp->oid_handler)
557 				/* We really should call the handler here...*/
558 				return 0;
559 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
560 			if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
561 				len, level+1, oidpp))
562 				return 0;
563 			goto next;
564 		}
565 
566 		if (oidp->oid_number < *name)
567 			continue;
568 
569 		if (oidp->oid_number > *name) {
570 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
571 				return 0;
572 			if (oidp->oid_handler)
573 				return 0;
574 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
575 			if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
576 				next+1, len, level+1, oidpp))
577 				return (0);
578 			goto next;
579 		}
580 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
581 			continue;
582 
583 		if (oidp->oid_handler)
584 			continue;
585 
586 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
587 		if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
588 			len, level+1, oidpp))
589 			return (0);
590 	next:
591 		namelen = 1;
592 		*len = level;
593 	}
594 	return 1;
595 }
596 
597 static int
598 sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
599 {
600 	int *name = (int *) arg1;
601 	u_int namelen = arg2;
602 	int i, j, error;
603 	struct sysctl_oid *oid;
604 	struct sysctl_oid_list *lsp = &sysctl__children;
605 	int newoid[CTL_MAXNAME];
606 
607 	i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
608 	if (i)
609 		return ENOENT;
610 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
611 	return (error);
612 }
613 
614 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
615 
616 static int
617 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
618 {
619 	int i;
620 	struct sysctl_oid *oidp;
621 	struct sysctl_oid_list *lsp = &sysctl__children;
622 	char *p;
623 
624 	if (!*name)
625 		return ENOENT;
626 
627 	p = name + strlen(name) - 1 ;
628 	if (*p == '.')
629 		*p = '\0';
630 
631 	*len = 0;
632 
633 	for (p = name; *p && *p != '.'; p++)
634 		;
635 	i = *p;
636 	if (i == '.')
637 		*p = '\0';
638 
639 	oidp = SLIST_FIRST(lsp);
640 
641 	while (oidp && *len < CTL_MAXNAME) {
642 		if (strcmp(name, oidp->oid_name)) {
643 			oidp = SLIST_NEXT(oidp, oid_link);
644 			continue;
645 		}
646 		*oid++ = oidp->oid_number;
647 		(*len)++;
648 
649 		if (!i) {
650 			if (oidpp)
651 				*oidpp = oidp;
652 			return (0);
653 		}
654 
655 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
656 			break;
657 
658 		if (oidp->oid_handler)
659 			break;
660 
661 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
662 		oidp = SLIST_FIRST(lsp);
663 		name = p+1;
664 		for (p = name; *p && *p != '.'; p++)
665 				;
666 		i = *p;
667 		if (i == '.')
668 			*p = '\0';
669 	}
670 	return ENOENT;
671 }
672 
673 static int
674 sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
675 {
676 	char *p;
677 	int error, oid[CTL_MAXNAME], len;
678 	struct sysctl_oid *op = 0;
679 
680 	if (!req->newlen)
681 		return ENOENT;
682 	if (req->newlen >= MAXPATHLEN)	/* XXX arbitrary, undocumented */
683 		return (ENAMETOOLONG);
684 
685 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
686 
687 	error = SYSCTL_IN(req, p, req->newlen);
688 	if (error) {
689 		free(p, M_SYSCTL);
690 		return (error);
691 	}
692 
693 	p [req->newlen] = '\0';
694 
695 	error = name2oid(p, oid, &len, &op);
696 
697 	free(p, M_SYSCTL);
698 
699 	if (error)
700 		return (error);
701 
702 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
703 	return (error);
704 }
705 
706 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
707 	sysctl_sysctl_name2oid, "I", "");
708 
709 static int
710 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
711 {
712 	struct sysctl_oid *oid;
713 	int error;
714 
715 	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
716 	if (error)
717 		return (error);
718 
719 	if (!oid->oid_fmt)
720 		return (ENOENT);
721 	error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
722 	if (error)
723 		return (error);
724 	error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
725 	return (error);
726 }
727 
728 
729 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
730 
731 static int
732 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
733 {
734 	struct sysctl_oid *oid;
735 	int error;
736 
737 	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
738 	if (error)
739 		return (error);
740 
741 	if (!oid->oid_descr)
742 		return (ENOENT);
743 	error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
744 	return (error);
745 }
746 
747 SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
748 
749 /*
750  * Default "handler" functions.
751  */
752 
753 /*
754  * Handle an int, signed or unsigned.
755  * Two cases:
756  *     a variable:  point arg1 at it.
757  *     a constant:  pass it in arg2.
758  */
759 
760 int
761 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
762 {
763 	int error = 0;
764 
765 	if (arg1)
766 		error = SYSCTL_OUT(req, arg1, sizeof(int));
767 	else
768 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
769 
770 	if (error || !req->newptr)
771 		return (error);
772 
773 	if (!arg1)
774 		error = EPERM;
775 	else
776 		error = SYSCTL_IN(req, arg1, sizeof(int));
777 	return (error);
778 }
779 
780 /*
781  * Handle a long, signed or unsigned.  arg1 points to it.
782  */
783 
784 int
785 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
786 {
787 	int error = 0;
788 
789 	if (!arg1)
790 		return (EINVAL);
791 	error = SYSCTL_OUT(req, arg1, sizeof(long));
792 
793 	if (error || !req->newptr)
794 		return (error);
795 
796 	error = SYSCTL_IN(req, arg1, sizeof(long));
797 	return (error);
798 }
799 
800 /*
801  * Handle our generic '\0' terminated 'C' string.
802  * Two cases:
803  * 	a variable string:  point arg1 at it, arg2 is max length.
804  * 	a constant string:  point arg1 at it, arg2 is zero.
805  */
806 
807 int
808 sysctl_handle_string(SYSCTL_HANDLER_ARGS)
809 {
810 	int error=0;
811 
812 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
813 
814 	if (error || !req->newptr)
815 		return (error);
816 
817 	if ((req->newlen - req->newidx) >= arg2) {
818 		error = EINVAL;
819 	} else {
820 		arg2 = (req->newlen - req->newidx);
821 		error = SYSCTL_IN(req, arg1, arg2);
822 		((char *)arg1)[arg2] = '\0';
823 	}
824 
825 	return (error);
826 }
827 
828 /*
829  * Handle any kind of opaque data.
830  * arg1 points to it, arg2 is the size.
831  */
832 
833 int
834 sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
835 {
836 	int error;
837 
838 	error = SYSCTL_OUT(req, arg1, arg2);
839 
840 	if (error || !req->newptr)
841 		return (error);
842 
843 	error = SYSCTL_IN(req, arg1, arg2);
844 
845 	return (error);
846 }
847 
848 /*
849  * Transfer functions to/from kernel space.
850  * XXX: rather untested at this point
851  */
852 static int
853 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
854 {
855 	size_t i = 0;
856 
857 	if (req->oldptr) {
858 		i = l;
859 		if (i > req->oldlen - req->oldidx)
860 			i = req->oldlen - req->oldidx;
861 		if (i > 0)
862 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
863 	}
864 	req->oldidx += l;
865 	if (req->oldptr && i != l)
866 		return (ENOMEM);
867 	return (0);
868 }
869 
870 static int
871 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
872 {
873 
874 	if (!req->newptr)
875 		return 0;
876 	if (req->newlen - req->newidx < l)
877 		return (EINVAL);
878 	bcopy((char *)req->newptr + req->newidx, p, l);
879 	req->newidx += l;
880 	return (0);
881 }
882 
883 int
884 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
885 {
886 	int error = 0;
887 	struct sysctl_req req;
888 
889 	bzero(&req, sizeof req);
890 
891 	req.p = p;
892 
893 	if (oldlenp) {
894 		req.oldlen = *oldlenp;
895 	}
896 
897 	if (old) {
898 		req.oldptr= old;
899 	}
900 
901 	if (new != NULL) {
902 		req.newlen = newlen;
903 		req.newptr = new;
904 	}
905 
906 	req.oldfunc = sysctl_old_kernel;
907 	req.newfunc = sysctl_new_kernel;
908 	req.lock = 1;
909 
910 	/* XXX this should probably be done in a general way */
911 	while (memlock.sl_lock) {
912 		memlock.sl_want = 1;
913 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
914 		memlock.sl_locked++;
915 	}
916 	memlock.sl_lock = 1;
917 
918 	error = sysctl_root(0, name, namelen, &req);
919 
920 	if (req.lock == 2)
921 		vsunlock(req.oldptr, req.oldlen);
922 
923 	memlock.sl_lock = 0;
924 
925 	if (memlock.sl_want) {
926 		memlock.sl_want = 0;
927 		wakeup((caddr_t)&memlock);
928 	}
929 
930 	if (error && error != ENOMEM)
931 		return (error);
932 
933 	if (retval) {
934 		if (req.oldptr && req.oldidx > req.oldlen)
935 			*retval = req.oldlen;
936 		else
937 			*retval = req.oldidx;
938 	}
939 	return (error);
940 }
941 
942 int
943 kernel_sysctlbyname(struct proc *p, char *name, void *old, size_t *oldlenp,
944     void *new, size_t newlen, size_t *retval)
945 {
946         int oid[CTL_MAXNAME];
947         size_t oidlen, plen;
948 	int error;
949 
950 	oid[0] = 0;		/* sysctl internal magic */
951 	oid[1] = 3;		/* name2oid */
952 	oidlen = sizeof(oid);
953 
954 	error = kernel_sysctl(p, oid, 2, oid, &oidlen,
955 	    (void *)name, strlen(name), &plen);
956 	if (error)
957 		return (error);
958 
959 	error = kernel_sysctl(p, oid, plen / sizeof(int), old, oldlenp,
960 	    new, newlen, retval);
961 	return (error);
962 }
963 
964 /*
965  * Transfer function to/from user space.
966  */
967 static int
968 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
969 {
970 	int error = 0;
971 	size_t i = 0;
972 
973 	if (req->lock == 1 && req->oldptr) {
974 		vslock(req->oldptr, req->oldlen);
975 		req->lock = 2;
976 	}
977 	if (req->oldptr) {
978 		i = l;
979 		if (i > req->oldlen - req->oldidx)
980 			i = req->oldlen - req->oldidx;
981 		if (i > 0)
982 			error = copyout(p, (char *)req->oldptr + req->oldidx,
983 					i);
984 	}
985 	req->oldidx += l;
986 	if (error)
987 		return (error);
988 	if (req->oldptr && i < l)
989 		return (ENOMEM);
990 	return (0);
991 }
992 
993 static int
994 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
995 {
996 	int error;
997 
998 	if (!req->newptr)
999 		return 0;
1000 	if (req->newlen - req->newidx < l)
1001 		return (EINVAL);
1002 	error = copyin((char *)req->newptr + req->newidx, p, l);
1003 	req->newidx += l;
1004 	return (error);
1005 }
1006 
1007 int
1008 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1009     int *nindx, struct sysctl_req *req)
1010 {
1011 	struct sysctl_oid *oid;
1012 	int indx;
1013 
1014 	oid = SLIST_FIRST(&sysctl__children);
1015 	indx = 0;
1016 	while (oid && indx < CTL_MAXNAME) {
1017 		if (oid->oid_number == name[indx]) {
1018 			indx++;
1019 			if (oid->oid_kind & CTLFLAG_NOLOCK)
1020 				req->lock = 0;
1021 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1022 				if (oid->oid_handler != NULL ||
1023 				    indx == namelen) {
1024 					*noid = oid;
1025 					if (nindx != NULL)
1026 						*nindx = indx;
1027 					return (0);
1028 				}
1029 				oid = SLIST_FIRST(
1030 				    (struct sysctl_oid_list *)oid->oid_arg1);
1031 			} else if (indx == namelen) {
1032 				*noid = oid;
1033 				if (nindx != NULL)
1034 					*nindx = indx;
1035 				return (0);
1036 			} else {
1037 				return (ENOTDIR);
1038 			}
1039 		} else {
1040 			oid = SLIST_NEXT(oid, oid_link);
1041 		}
1042 	}
1043 	return (ENOENT);
1044 }
1045 
1046 /*
1047  * Traverse our tree, and find the right node, execute whatever it points
1048  * to, and return the resulting error code.
1049  */
1050 
1051 int
1052 sysctl_root(SYSCTL_HANDLER_ARGS)
1053 {
1054 	struct sysctl_oid *oid;
1055 	int error, indx;
1056 
1057 	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1058 	if (error)
1059 		return (error);
1060 
1061 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1062 		/*
1063 		 * You can't call a sysctl when it's a node, but has
1064 		 * no handler.  Inform the user that it's a node.
1065 		 * The indx may or may not be the same as namelen.
1066 		 */
1067 		if (oid->oid_handler == NULL)
1068 			return (EISDIR);
1069 	}
1070 
1071 	/* If writing isn't allowed */
1072 	if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
1073 	    ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
1074 		return (EPERM);
1075 
1076 	/* Most likely only root can write */
1077 	if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
1078 	    req->newptr && req->p &&
1079 	    (error = suser_xxx(0, req->p,
1080 	    (oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0)))
1081 		return (error);
1082 
1083 	if (!oid->oid_handler)
1084 		return EINVAL;
1085 
1086 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
1087 		error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
1088 		    req);
1089 	else
1090 		error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
1091 		    req);
1092 	return (error);
1093 }
1094 
1095 #ifndef _SYS_SYSPROTO_H_
1096 struct sysctl_args {
1097 	int	*name;
1098 	u_int	namelen;
1099 	void	*old;
1100 	size_t	*oldlenp;
1101 	void	*new;
1102 	size_t	newlen;
1103 };
1104 #endif
1105 
1106 int
1107 __sysctl(struct proc *p, struct sysctl_args *uap)
1108 {
1109 	int error, i, name[CTL_MAXNAME];
1110 	size_t j;
1111 
1112 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1113 		return (EINVAL);
1114 
1115  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1116  	if (error)
1117 		return (error);
1118 
1119 	error = userland_sysctl(p, name, uap->namelen,
1120 		uap->old, uap->oldlenp, 0,
1121 		uap->new, uap->newlen, &j);
1122 	if (error && error != ENOMEM)
1123 		return (error);
1124 	if (uap->oldlenp) {
1125 		i = copyout(&j, uap->oldlenp, sizeof(j));
1126 		if (i)
1127 			return (i);
1128 	}
1129 	return (error);
1130 }
1131 
1132 /*
1133  * This is used from various compatibility syscalls too.  That's why name
1134  * must be in kernel space.
1135  */
1136 int
1137 userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1138 {
1139 	int error = 0;
1140 	struct sysctl_req req, req2;
1141 
1142 	bzero(&req, sizeof req);
1143 
1144 	req.p = p;
1145 
1146 	if (oldlenp) {
1147 		if (inkernel) {
1148 			req.oldlen = *oldlenp;
1149 		} else {
1150 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1151 			if (error)
1152 				return (error);
1153 		}
1154 	}
1155 
1156 	if (old) {
1157 		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1158 			return (EFAULT);
1159 		req.oldptr= old;
1160 	}
1161 
1162 	if (new != NULL) {
1163 		if (!useracc(new, req.newlen, VM_PROT_READ))
1164 			return (EFAULT);
1165 		req.newlen = newlen;
1166 		req.newptr = new;
1167 	}
1168 
1169 	req.oldfunc = sysctl_old_user;
1170 	req.newfunc = sysctl_new_user;
1171 	req.lock = 1;
1172 
1173 	/* XXX this should probably be done in a general way */
1174 	while (memlock.sl_lock) {
1175 		memlock.sl_want = 1;
1176 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
1177 		memlock.sl_locked++;
1178 	}
1179 	memlock.sl_lock = 1;
1180 
1181 	do {
1182 	    req2 = req;
1183 	    error = sysctl_root(0, name, namelen, &req2);
1184 	} while (error == EAGAIN);
1185 
1186 	req = req2;
1187 	if (req.lock == 2)
1188 		vsunlock(req.oldptr, req.oldlen);
1189 
1190 	memlock.sl_lock = 0;
1191 
1192 	if (memlock.sl_want) {
1193 		memlock.sl_want = 0;
1194 		wakeup((caddr_t)&memlock);
1195 	}
1196 
1197 	if (error && error != ENOMEM)
1198 		return (error);
1199 
1200 	if (retval) {
1201 		if (req.oldptr && req.oldidx > req.oldlen)
1202 			*retval = req.oldlen;
1203 		else
1204 			*retval = req.oldidx;
1205 	}
1206 	return (error);
1207 }
1208 
1209 #ifdef COMPAT_43
1210 #include <sys/socket.h>
1211 #include <vm/vm_param.h>
1212 
1213 #define	KINFO_PROC		(0<<8)
1214 #define	KINFO_RT		(1<<8)
1215 #define	KINFO_VNODE		(2<<8)
1216 #define	KINFO_FILE		(3<<8)
1217 #define	KINFO_METER		(4<<8)
1218 #define	KINFO_LOADAVG		(5<<8)
1219 #define	KINFO_CLOCKRATE		(6<<8)
1220 
1221 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1222 #define	KINFO_BSDI_SYSINFO	(101<<8)
1223 
1224 /*
1225  * XXX this is bloat, but I hope it's better here than on the potentially
1226  * limited kernel stack...  -Peter
1227  */
1228 
1229 static struct {
1230 	int	bsdi_machine;		/* "i386" on BSD/386 */
1231 /*      ^^^ this is an offset to the string, relative to the struct start */
1232 	char	*pad0;
1233 	long	pad1;
1234 	long	pad2;
1235 	long	pad3;
1236 	u_long	pad4;
1237 	u_long	pad5;
1238 	u_long	pad6;
1239 
1240 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
1241 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
1242 	long	pad7;
1243 	long	pad8;
1244 	char	*pad9;
1245 
1246 	long	pad10;
1247 	long	pad11;
1248 	int	pad12;
1249 	long	pad13;
1250 	quad_t	pad14;
1251 	long	pad15;
1252 
1253 	struct	timeval pad16;
1254 	/* we dont set this, because BSDI's uname used gethostname() instead */
1255 	int	bsdi_hostname;		/* hostname on BSD/386 */
1256 
1257 	/* the actual string data is appended here */
1258 
1259 } bsdi_si;
1260 /*
1261  * this data is appended to the end of the bsdi_si structure during copyout.
1262  * The "char *" offsets are relative to the base of the bsdi_si struct.
1263  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1264  * should not exceed the length of the buffer here... (or else!! :-)
1265  */
1266 static char bsdi_strings[80];	/* It had better be less than this! */
1267 
1268 #ifndef _SYS_SYSPROTO_H_
1269 struct getkerninfo_args {
1270 	int	op;
1271 	char	*where;
1272 	size_t	*size;
1273 	int	arg;
1274 };
1275 #endif
1276 
1277 int
1278 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
1279 {
1280 	int error, name[6];
1281 	size_t size;
1282 
1283 	switch (uap->op & 0xff00) {
1284 
1285 	case KINFO_RT:
1286 		name[0] = CTL_NET;
1287 		name[1] = PF_ROUTE;
1288 		name[2] = 0;
1289 		name[3] = (uap->op & 0xff0000) >> 16;
1290 		name[4] = uap->op & 0xff;
1291 		name[5] = uap->arg;
1292 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
1293 			0, 0, 0, &size);
1294 		break;
1295 
1296 	case KINFO_VNODE:
1297 		name[0] = CTL_KERN;
1298 		name[1] = KERN_VNODE;
1299 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1300 			0, 0, 0, &size);
1301 		break;
1302 
1303 	case KINFO_PROC:
1304 		name[0] = CTL_KERN;
1305 		name[1] = KERN_PROC;
1306 		name[2] = uap->op & 0xff;
1307 		name[3] = uap->arg;
1308 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
1309 			0, 0, 0, &size);
1310 		break;
1311 
1312 	case KINFO_FILE:
1313 		name[0] = CTL_KERN;
1314 		name[1] = KERN_FILE;
1315 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1316 			0, 0, 0, &size);
1317 		break;
1318 
1319 	case KINFO_METER:
1320 		name[0] = CTL_VM;
1321 		name[1] = VM_METER;
1322 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1323 			0, 0, 0, &size);
1324 		break;
1325 
1326 	case KINFO_LOADAVG:
1327 		name[0] = CTL_VM;
1328 		name[1] = VM_LOADAVG;
1329 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1330 			0, 0, 0, &size);
1331 		break;
1332 
1333 	case KINFO_CLOCKRATE:
1334 		name[0] = CTL_KERN;
1335 		name[1] = KERN_CLOCKRATE;
1336 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1337 			0, 0, 0, &size);
1338 		break;
1339 
1340 	case KINFO_BSDI_SYSINFO: {
1341 		/*
1342 		 * this is pretty crude, but it's just enough for uname()
1343 		 * from BSDI's 1.x libc to work.
1344 		 *
1345 		 * In particular, it doesn't return the same results when
1346 		 * the supplied buffer is too small.  BSDI's version apparently
1347 		 * will return the amount copied, and set the *size to how
1348 		 * much was needed.  The emulation framework here isn't capable
1349 		 * of that, so we just set both to the amount copied.
1350 		 * BSDI's 2.x product apparently fails with ENOMEM in this
1351 		 * scenario.
1352 		 */
1353 
1354 		u_int needed;
1355 		u_int left;
1356 		char *s;
1357 
1358 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1359 		bzero(bsdi_strings, sizeof(bsdi_strings));
1360 
1361 		s = bsdi_strings;
1362 
1363 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1364 		strcpy(s, ostype);
1365 		s += strlen(s) + 1;
1366 
1367 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1368 		strcpy(s, osrelease);
1369 		s += strlen(s) + 1;
1370 
1371 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1372 		strcpy(s, machine);
1373 		s += strlen(s) + 1;
1374 
1375 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1376 
1377 		if (uap->where == NULL) {
1378 			/* process is asking how much buffer to supply.. */
1379 			size = needed;
1380 			error = 0;
1381 			break;
1382 		}
1383 
1384 
1385 		/* if too much buffer supplied, trim it down */
1386 		if (size > needed)
1387 			size = needed;
1388 
1389 		/* how much of the buffer is remaining */
1390 		left = size;
1391 
1392 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1393 			break;
1394 
1395 		/* is there any point in continuing? */
1396 		if (left > sizeof(bsdi_si)) {
1397 			left -= sizeof(bsdi_si);
1398 			error = copyout(&bsdi_strings,
1399 					uap->where + sizeof(bsdi_si), left);
1400 		}
1401 		break;
1402 	}
1403 
1404 	default:
1405 		return (EOPNOTSUPP);
1406 	}
1407 	if (error)
1408 		return (error);
1409 	p->p_retval[0] = size;
1410 	if (uap->size)
1411 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1412 		    sizeof(size));
1413 	return (error);
1414 }
1415 #endif /* COMPAT_43 */
1416