|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*-
23: * Copyright (c) 1982, 1986, 1989, 1993
24: * The Regents of the University of California. All rights reserved.
25: *
26: * This code is derived from software contributed to Berkeley by
27: * Mike Karels at Berkeley Software Design, Inc.
28: *
29: * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
30: * project, to make these variables more userfriendly.
31: *
32: * Redistribution and use in source and binary forms, with or without
33: * modification, are permitted provided that the following conditions
34: * are met:
35: * 1. Redistributions of source code must retain the above copyright
36: * notice, this list of conditions and the following disclaimer.
37: * 2. Redistributions in binary form must reproduce the above copyright
38: * notice, this list of conditions and the following disclaimer in the
39: * documentation and/or other materials provided with the distribution.
40: * 3. All advertising materials mentioning features or use of this software
41: * must display the following acknowledgement:
42: * This product includes software developed by the University of
43: * California, Berkeley and its contributors.
44: * 4. Neither the name of the University nor the names of its contributors
45: * may be used to endorse or promote products derived from this software
46: * without specific prior written permission.
47: *
48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58: * SUCH DAMAGE.
59: *
60: * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
61: */
62:
63:
64: #include <sys/param.h>
65: #include <sys/buf.h>
66: #include <sys/kernel.h>
67: #include <sys/sysctl.h>
68: #include <sys/malloc.h>
69: #include <sys/proc.h>
70: #include <sys/systm.h>
71:
72: /*
73: struct sysctl_oid_list sysctl__debug_children;
74: struct sysctl_oid_list sysctl__kern_children;
75: struct sysctl_oid_list sysctl__net_children;
76: struct sysctl_oid_list sysctl__sysctl_children;
77: */
78:
79: extern struct sysctl_oid *newsysctl_list[];
80:
81:
82: static void
83: sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
84:
85:
86:
87: /*
88: * Locking and stats
89: */
90: static struct sysctl_lock {
91: int sl_lock;
92: int sl_want;
93: int sl_locked;
94: } memlock;
95:
96: static int sysctl_root SYSCTL_HANDLER_ARGS;
97:
98: struct sysctl_oid_list sysctl__children; /* root list */
99:
100: /*
101: * Initialization of the MIB tree.
102: *
103: * Order by number in each list.
104: */
105:
106: void sysctl_register_oid(struct sysctl_oid *oidp)
107: {
108: struct sysctl_oid_list *parent = oidp->oid_parent;
109: struct sysctl_oid *p;
110: struct sysctl_oid *q;
111: int n;
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: /* sysctl_sysctl_debug_dump_node(parent, 3); */
119: if (oidp->oid_number == OID_AUTO) {
120: /* First, find the highest oid in the parent list >99 */
121: n = 99;
122: SLIST_FOREACH(p, parent, oid_link) {
123: if (p->oid_number > n)
124: n = p->oid_number;
125: }
126: oidp->oid_number = n + 1;
127: }
128:
129: /*
130: * Insert the oid into the parent's list in order.
131: */
132: q = NULL;
133: SLIST_FOREACH(p, parent, oid_link) {
134: if (oidp->oid_number < p->oid_number)
135: break;
136: q = p;
137: }
138: if (q)
139: SLIST_INSERT_AFTER(q, oidp, oid_link);
140: else
141: SLIST_INSERT_HEAD(parent, oidp, oid_link);
142: }
143:
144: void sysctl_unregister_oid(struct sysctl_oid *oidp)
145: {
146: SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
147: }
148:
149: /*
150: * Bulk-register all the oids in a linker_set.
151: */
152: void sysctl_register_set(struct linker_set *lsp)
153: {
154: int count = lsp->ls_length;
155: int i;
156: for (i = 0; i < count; i++)
157: sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
158: }
159:
160: void sysctl_unregister_set(struct linker_set *lsp)
161: {
162: int count = lsp->ls_length;
163: int i;
164: for (i = 0; i < count; i++)
165: sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
166: }
167:
168:
169: /*
170: * Register OID's from fixed list
171: */
172:
173: void sysctl_register_fixed()
174: {
175: int i = 0;
176:
177:
178: while (newsysctl_list[i]) {
179: /* printf("Registering %d\n", i); */
180: sysctl_register_oid(newsysctl_list[i++]);
181: }
182: }
183:
184: /*
185: * Register the kernel's oids on startup.
186: */
187: struct linker_set sysctl_set;
188:
189: void sysctl_register_all(void *arg)
190: {
191: sysctl_register_set(&sysctl_set);
192: }
193:
194: SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
195:
196: /*
197: * "Staff-functions"
198: *
199: * These functions implement a presently undocumented interface
200: * used by the sysctl program to walk the tree, and get the type
201: * so it can print the value.
202: * This interface is under work and consideration, and should probably
203: * be killed with a big axe by the first person who can find the time.
204: * (be aware though, that the proper interface isn't as obvious as it
205: * may seem, there are various conflicting requirements.
206: *
207: * {0,0} printf the entire MIB-tree.
208: * {0,1,...} return the name of the "..." OID.
209: * {0,2,...} return the next OID.
210: * {0,3} return the OID of the name in "new"
211: * {0,4,...} return the kind & format info for the "..." OID.
212: */
213:
214: static void
215: sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
216: {
217: int k;
218: struct sysctl_oid *oidp;
219:
220: SLIST_FOREACH(oidp, l, oid_link) {
221:
222: for (k=0; k<i; k++)
223: printf(" ");
224:
225: printf("%d %s ", oidp->oid_number, oidp->oid_name);
226:
227: printf("%c%c",
228: oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
229: oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
230:
231: if (oidp->oid_handler)
232: printf(" *Handler");
233:
234: switch (oidp->oid_kind & CTLTYPE) {
235: case CTLTYPE_NODE:
236: printf(" Node\n");
237: if (!oidp->oid_handler) {
238: sysctl_sysctl_debug_dump_node(
239: oidp->oid_arg1, i+2);
240: }
241: break;
242: case CTLTYPE_INT: printf(" Int\n"); break;
243: case CTLTYPE_STRING: printf(" String\n"); break;
244: case CTLTYPE_QUAD: printf(" Quad\n"); break;
245: case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
246: default: printf("\n");
247: }
248:
249: }
250: }
251:
252: static int
253: sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
254: {
255: sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
256: return ENOENT;
257: }
258:
259: SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
260: 0, 0, sysctl_sysctl_debug, "-", "");
261:
262: static int
263: sysctl_sysctl_name SYSCTL_HANDLER_ARGS
264: {
265: int *name = (int *) arg1;
266: u_int namelen = arg2;
267: int error = 0;
268: struct sysctl_oid *oid;
269: struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
270: char buf[10];
271:
272: while (namelen) {
273: if (!lsp) {
274: snprintf(buf,sizeof(buf),"%d",*name);
275: if (req->oldidx)
276: error = SYSCTL_OUT(req, ".", 1);
277: if (!error)
278: error = SYSCTL_OUT(req, buf, strlen(buf));
279: if (error)
280: return (error);
281: namelen--;
282: name++;
283: continue;
284: }
285: lsp2 = 0;
286: SLIST_FOREACH(oid, lsp, oid_link) {
287: if (oid->oid_number != *name)
288: continue;
289:
290: if (req->oldidx)
291: error = SYSCTL_OUT(req, ".", 1);
292: if (!error)
293: error = SYSCTL_OUT(req, oid->oid_name,
294: strlen(oid->oid_name));
295: if (error)
296: return (error);
297:
298: namelen--;
299: name++;
300:
301: if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
302: break;
303:
304: if (oid->oid_handler)
305: break;
306:
307: lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
308: break;
309: }
310: lsp = lsp2;
311: }
312: return (SYSCTL_OUT(req, "", 1));
313: }
314:
315: SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
316:
317: static int
318: sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen,
319: int *next, int *len, int level, struct sysctl_oid **oidpp)
320: {
321: struct sysctl_oid *oidp;
322:
323: *len = level;
324: SLIST_FOREACH(oidp, lsp, oid_link) {
325: *next = oidp->oid_number;
326: *oidpp = oidp;
327:
328: if (!namelen) {
329: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
330: return 0;
331: if (oidp->oid_handler)
332: /* We really should call the handler here...*/
333: return 0;
334: lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
335: if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
336: len, level+1, oidpp))
337: return 0;
338: goto next;
339: }
340:
341: if (oidp->oid_number < *name)
342: continue;
343:
344: if (oidp->oid_number > *name) {
345: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
346: return 0;
347: if (oidp->oid_handler)
348: return 0;
349: lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
350: if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
351: next+1, len, level+1, oidpp))
352: return (0);
353: goto next;
354: }
355: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
356: continue;
357:
358: if (oidp->oid_handler)
359: continue;
360:
361: lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
362: if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
363: len, level+1, oidpp))
364: return (0);
365: next:
366: namelen = 1;
367: *len = level;
368: }
369: return 1;
370: }
371:
372: static int
373: sysctl_sysctl_next SYSCTL_HANDLER_ARGS
374: {
375: int *name = (int *) arg1;
376: u_int namelen = arg2;
377: int i, j, error;
378: struct sysctl_oid *oid;
379: struct sysctl_oid_list *lsp = &sysctl__children;
380: int newoid[CTL_MAXNAME];
381:
382: i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
383: if (i)
384: return ENOENT;
385: error = SYSCTL_OUT(req, newoid, j * sizeof (int));
386: return (error);
387: }
388:
389: SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
390:
391: static int
392: name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
393: {
394: int i;
395: struct sysctl_oid *oidp;
396: struct sysctl_oid_list *lsp = &sysctl__children;
397: char *p;
398:
399: if (!*name)
400: return ENOENT;
401:
402: p = name + strlen(name) - 1 ;
403: if (*p == '.')
404: *p = '\0';
405:
406: *len = 0;
407:
408: for (p = name; *p && *p != '.'; p++)
409: ;
410: i = *p;
411: if (i == '.')
412: *p = '\0';
413:
414: oidp = SLIST_FIRST(lsp);
415:
416: while (oidp && *len < CTL_MAXNAME) {
417: if (strcmp(name, oidp->oid_name)) {
418: oidp = SLIST_NEXT(oidp, oid_link);
419: continue;
420: }
421: *oid++ = oidp->oid_number;
422: (*len)++;
423:
424: if (!i) {
425: if (oidpp)
426: *oidpp = oidp;
427: return (0);
428: }
429:
430: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
431: break;
432:
433: if (oidp->oid_handler)
434: break;
435:
436: lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
437: oidp = SLIST_FIRST(lsp);
438: name = p+1;
439: for (p = name; *p && *p != '.'; p++)
440: ;
441: i = *p;
442: if (i == '.')
443: *p = '\0';
444: }
445: return ENOENT;
446: }
447:
448: static int
449: sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
450: {
451: char *p;
452: int error, oid[CTL_MAXNAME], len;
453: struct sysctl_oid *op = 0;
454:
455: if (!req->newlen)
456: return ENOENT;
457: if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
458: return (ENAMETOOLONG);
459:
460: p = _MALLOC(req->newlen+1, M_TEMP, M_WAITOK);
461:
462: if (!p)
463: return ENOMEM;
464:
465: error = SYSCTL_IN(req, p, req->newlen);
466: if (error) {
467: FREE(p, M_TEMP);
468: return (error);
469: }
470:
471: p [req->newlen] = '\0';
472:
473: error = name2oid(p, oid, &len, &op);
474:
475: FREE(p, M_TEMP);
476:
477: if (error)
478: return (error);
479:
480: error = SYSCTL_OUT(req, oid, len * sizeof *oid);
481: return (error);
482: }
483:
484: SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
485: sysctl_sysctl_name2oid, "I", "");
486:
487: static int
488: sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
489: {
490: int *name = (int *) arg1, error;
491: u_int namelen = arg2;
492: int indx;
493: struct sysctl_oid *oid;
494: struct sysctl_oid_list *lsp = &sysctl__children;
495:
496: oid = SLIST_FIRST(lsp);
497:
498: indx = 0;
499: while (oid && indx < CTL_MAXNAME) {
500: if (oid->oid_number == name[indx]) {
501: indx++;
502: if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
503: if (oid->oid_handler)
504: goto found;
505: if (indx == namelen)
506: goto found;
507: lsp = (struct sysctl_oid_list *)oid->oid_arg1;
508: oid = SLIST_FIRST(lsp);
509: } else {
510: if (indx != namelen)
511: return EISDIR;
512: goto found;
513: }
514: } else {
515: oid = SLIST_NEXT(oid, oid_link);
516: }
517: }
518: return ENOENT;
519: found:
520: if (!oid->oid_fmt)
521: return ENOENT;
522: error = SYSCTL_OUT(req,
523: &oid->oid_kind, sizeof(oid->oid_kind));
524: if (!error)
525: error = SYSCTL_OUT(req, oid->oid_fmt,
526: strlen(oid->oid_fmt)+1);
527: return (error);
528: }
529:
530:
531: SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
532:
533: /*
534: * Default "handler" functions.
535: */
536:
537: /*
538: * Handle an int, signed or unsigned.
539: * Two cases:
540: * a variable: point arg1 at it.
541: * a constant: pass it in arg2.
542: */
543:
544: int
545: sysctl_handle_int SYSCTL_HANDLER_ARGS
546: {
547: int error = 0;
548:
549: if (arg1)
550: error = SYSCTL_OUT(req, arg1, sizeof(int));
551: else
552: error = SYSCTL_OUT(req, &arg2, sizeof(int));
553:
554: if (error || !req->newptr)
555: return (error);
556:
557: if (!arg1)
558: error = EPERM;
559: else
560: error = SYSCTL_IN(req, arg1, sizeof(int));
561: return (error);
562: }
563:
564: /*
565: * Handle a long, signed or unsigned. arg1 points to it.
566: */
567:
568: int
569: sysctl_handle_long SYSCTL_HANDLER_ARGS
570: {
571: int error = 0;
572:
573: if (!arg1)
574: return (EINVAL);
575: error = SYSCTL_OUT(req, arg1, sizeof(long));
576:
577: if (error || !req->newptr)
578: return (error);
579:
580: error = SYSCTL_IN(req, arg1, sizeof(long));
581: return (error);
582: }
583:
584: /*
585: * Handle our generic '\0' terminated 'C' string.
586: * Two cases:
587: * a variable string: point arg1 at it, arg2 is max length.
588: * a constant string: point arg1 at it, arg2 is zero.
589: */
590:
591: int
592: sysctl_handle_string SYSCTL_HANDLER_ARGS
593: {
594: int error=0;
595:
596: error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
597:
598: if (error || !req->newptr)
599: return (error);
600:
601: if ((req->newlen - req->newidx) >= arg2) {
602: error = EINVAL;
603: } else {
604: arg2 = (req->newlen - req->newidx);
605: error = SYSCTL_IN(req, arg1, arg2);
606: ((char *)arg1)[arg2] = '\0';
607: }
608:
609: return (error);
610: }
611:
612: /*
613: * Handle any kind of opaque data.
614: * arg1 points to it, arg2 is the size.
615: */
616:
617: int
618: sysctl_handle_opaque SYSCTL_HANDLER_ARGS
619: {
620: int error;
621:
622: error = SYSCTL_OUT(req, arg1, arg2);
623:
624: if (error || !req->newptr)
625: return (error);
626:
627: error = SYSCTL_IN(req, arg1, arg2);
628:
629: return (error);
630: }
631:
632: /*
633: * Transfer functions to/from kernel space.
634: * XXX: rather untested at this point
635: */
636: static int
637: sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
638: {
639: size_t i = 0;
640: int error = 0;
641:
642: if (req->oldptr) {
643: i = l;
644: if (i > req->oldlen - req->oldidx)
645: i = req->oldlen - req->oldidx;
646: if (i > 0) {
647: error = copyout(p, (char *)req->oldptr + req->oldidx, i);
648: if (error)
649: return error;
650: }
651: }
652: req->oldidx += l;
653: if (req->oldptr && i != l)
654: return (ENOMEM);
655: return (0);
656: }
657:
658: static int
659: sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
660: {
661: if (!req->newptr)
662: return 0;
663: if (req->newlen - req->newidx < l)
664: return (EINVAL);
665: copyin((char *)req->newptr + req->newidx, p, l);
666: req->newidx += l;
667: return (0);
668: }
669:
670: int
671: kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
672: {
673: int error = 0;
674: struct sysctl_req req;
675:
676: bzero(&req, sizeof req);
677:
678: req.p = p;
679:
680: if (oldlenp) {
681: req.oldlen = *oldlenp;
682: }
683:
684: if (old) {
685: req.oldptr= old;
686: }
687:
688: if (newlen) {
689: req.newlen = newlen;
690: req.newptr = new;
691: }
692:
693: req.oldfunc = sysctl_old_kernel;
694: req.newfunc = sysctl_new_kernel;
695: req.lock = 1;
696:
697: /* XXX this should probably be done in a general way */
698: while (memlock.sl_lock) {
699: memlock.sl_want = 1;
700: (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
701: memlock.sl_locked++;
702: }
703: memlock.sl_lock = 1;
704:
705: error = sysctl_root(0, name, namelen, &req);
706:
707: if (req.lock == 2)
708: vsunlock(req.oldptr, req.oldlen, B_WRITE);
709:
710: memlock.sl_lock = 0;
711:
712: if (memlock.sl_want) {
713: memlock.sl_want = 0;
714: wakeup((caddr_t)&memlock);
715: }
716:
717: if (error && error != ENOMEM)
718: return (error);
719:
720: if (retval) {
721: if (req.oldptr && req.oldidx > req.oldlen)
722: *retval = req.oldlen;
723: else
724: *retval = req.oldidx;
725: }
726: return (error);
727: }
728:
729: /*
730: * Transfer function to/from user space.
731: */
732: static int
733: sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
734: {
735: int error = 0;
736: size_t i = 0;
737:
738: if (req->oldptr) {
739: i = l;
740: if (i > req->oldlen - req->oldidx)
741: i = req->oldlen - req->oldidx;
742: if (i > 0)
743: error = copyout(p, (char *)req->oldptr + req->oldidx,
744: i);
745: }
746: req->oldidx += l;
747: if (error)
748: return (error);
749: if (req->oldptr && i < l)
750: return (ENOMEM);
751: return (0);
752: }
753:
754: static int
755: sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
756: {
757: int error;
758:
759: if (!req->newptr)
760: return 0;
761: if (req->newlen - req->newidx < l)
762: return (EINVAL);
763: error = copyin((char *)req->newptr + req->newidx, p, l);
764: req->newidx += l;
765: return (error);
766: }
767:
768: /*
769: * Traverse our tree, and find the right node, execute whatever it points
770: * at, and return the resulting error code.
771: */
772:
773: int
774: sysctl_root SYSCTL_HANDLER_ARGS
775: {
776: int *name = (int *) arg1;
777: u_int namelen = arg2;
778: int indx, i;
779: struct sysctl_oid *oid;
780: struct sysctl_oid_list *lsp = &sysctl__children;
781:
782: oid = SLIST_FIRST(lsp);
783:
784: indx = 0;
785: while (oid && indx < CTL_MAXNAME) {
786: if (oid->oid_number == name[indx]) {
787: indx++;
788: if (oid->oid_kind & CTLFLAG_NOLOCK)
789: req->lock = 0;
790: if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
791: if (oid->oid_handler)
792: goto found;
793: if (indx == namelen)
794: return ENOENT;
795: lsp = (struct sysctl_oid_list *)oid->oid_arg1;
796: oid = SLIST_FIRST(lsp);
797: } else {
798: if (indx != namelen)
799: return EISDIR;
800: goto found;
801: }
802: } else {
803: oid = SLIST_NEXT(oid, oid_link);
804: }
805: }
806: return ENOENT;
807: found:
808: /* If writing isn't allowed */
809: if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
810: ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
811: return (EPERM);
812: }
813:
814:
815: if (!oid->oid_handler) {
816: return EINVAL;
817: }
818:
819: if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
820: i = (oid->oid_handler) (oid,
821: name + indx, namelen - indx,
822: req);
823: } else {
824: i = (oid->oid_handler) (oid,
825: oid->oid_arg1, oid->oid_arg2,
826: req);
827: }
828: return (i);
829: }
830:
831: #ifndef _SYS_SYSPROTO_H_
832: struct sysctl_args {
833: int *name;
834: u_int namelen;
835: void *old;
836: size_t *oldlenp;
837: void *new;
838: size_t newlen;
839: };
840: #endif
841:
842: int
843: /* __sysctl(struct proc *p, struct sysctl_args *uap) */
844: new_sysctl(struct proc *p, struct sysctl_args *uap)
845: {
846: int error, i, name[CTL_MAXNAME];
847: size_t j;
848:
849: if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
850: return (EINVAL);
851:
852: error = copyin(uap->name, &name, uap->namelen * sizeof(int));
853: if (error)
854: return (error);
855:
856: error = userland_sysctl(p, name, uap->namelen,
857: uap->old, uap->oldlenp, 0,
858: uap->new, uap->newlen, &j);
859: if (error && error != ENOMEM)
860: return (error);
861: if (uap->oldlenp) {
862: i = copyout(&j, uap->oldlenp, sizeof(j));
863: if (i)
864: return (i);
865: }
866: return (error);
867: }
868:
869: /*
870: * This is used from various compatibility syscalls too. That's why name
871: * must be in kernel space.
872: */
873: int
874: 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)
875: {
876: int error = 0;
877: struct sysctl_req req, req2;
878:
879: bzero(&req, sizeof req);
880:
881: req.p = p;
882:
883: if (oldlenp) {
884: if (inkernel) {
885: req.oldlen = *oldlenp;
886: } else {
887: error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
888: if (error)
889: return (error);
890: }
891: }
892:
893: if (old) {
894: req.oldptr= old;
895: }
896:
897: if (newlen) {
898: req.newlen = newlen;
899: req.newptr = new;
900: }
901:
902: req.oldfunc = sysctl_old_user;
903: req.newfunc = sysctl_new_user;
904: req.lock = 1;
905:
906: do {
907: req2 = req;
908: error = sysctl_root(0, name, namelen, &req2);
909: } while (error == EAGAIN);
910:
911: req = req2;
912:
913: if (error && error != ENOMEM)
914: return (error);
915:
916: if (retval) {
917: if (req.oldptr && req.oldidx > req.oldlen)
918: *retval = req.oldlen;
919: else
920: *retval = req.oldidx;
921: }
922: return (error);
923: }
924: #if 0
925:
926: #if COMPAT_43
927: #include <sys/socket.h>
928: #include <vm/vm_param.h>
929:
930: #define KINFO_PROC (0<<8)
931: #define KINFO_RT (1<<8)
932: #define KINFO_VNODE (2<<8)
933: #define KINFO_FILE (3<<8)
934: #define KINFO_METER (4<<8)
935: #define KINFO_LOADAVG (5<<8)
936: #define KINFO_CLOCKRATE (6<<8)
937:
938: /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
939: #define KINFO_BSDI_SYSINFO (101<<8)
940:
941: /*
942: * XXX this is bloat, but I hope it's better here than on the potentially
943: * limited kernel stack... -Peter
944: */
945:
946: static struct {
947: int bsdi_machine; /* "i386" on BSD/386 */
948: /* ^^^ this is an offset to the string, relative to the struct start */
949: char *pad0;
950: long pad1;
951: long pad2;
952: long pad3;
953: u_long pad4;
954: u_long pad5;
955: u_long pad6;
956:
957: int bsdi_ostype; /* "BSD/386" on BSD/386 */
958: int bsdi_osrelease; /* "1.1" on BSD/386 */
959: long pad7;
960: long pad8;
961: char *pad9;
962:
963: long pad10;
964: long pad11;
965: int pad12;
966: long pad13;
967: quad_t pad14;
968: long pad15;
969:
970: struct timeval pad16;
971: /* we dont set this, because BSDI's uname used gethostname() instead */
972: int bsdi_hostname; /* hostname on BSD/386 */
973:
974: /* the actual string data is appended here */
975:
976: } bsdi_si;
977: /*
978: * this data is appended to the end of the bsdi_si structure during copyout.
979: * The "char *" offsets are relative to the base of the bsdi_si struct.
980: * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
981: * should not exceed the length of the buffer here... (or else!! :-)
982: */
983: static char bsdi_strings[80]; /* It had better be less than this! */
984:
985: #ifndef _SYS_SYSPROTO_H_
986: struct getkerninfo_args {
987: int op;
988: char *where;
989: size_t *size;
990: int arg;
991: };
992: #endif
993:
994: int
995: ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
996: {
997: int error, name[6];
998: size_t size;
999:
1000: switch (uap->op & 0xff00) {
1001:
1002: case KINFO_RT:
1003: name[0] = CTL_NET;
1004: name[1] = PF_ROUTE;
1005: name[2] = 0;
1006: name[3] = (uap->op & 0xff0000) >> 16;
1007: name[4] = uap->op & 0xff;
1008: name[5] = uap->arg;
1009: error = userland_sysctl(p, name, 6, uap->where, uap->size,
1010: 0, 0, 0, &size);
1011: break;
1012:
1013: case KINFO_VNODE:
1014: name[0] = CTL_KERN;
1015: name[1] = KERN_VNODE;
1016: error = userland_sysctl(p, name, 2, uap->where, uap->size,
1017: 0, 0, 0, &size);
1018: break;
1019:
1020: case KINFO_PROC:
1021: name[0] = CTL_KERN;
1022: name[1] = KERN_PROC;
1023: name[2] = uap->op & 0xff;
1024: name[3] = uap->arg;
1025: error = userland_sysctl(p, name, 4, uap->where, uap->size,
1026: 0, 0, 0, &size);
1027: break;
1028:
1029: case KINFO_FILE:
1030: name[0] = CTL_KERN;
1031: name[1] = KERN_FILE;
1032: error = userland_sysctl(p, name, 2, uap->where, uap->size,
1033: 0, 0, 0, &size);
1034: break;
1035:
1036: case KINFO_METER:
1037: name[0] = CTL_VM;
1038: name[1] = VM_METER;
1039: error = userland_sysctl(p, name, 2, uap->where, uap->size,
1040: 0, 0, 0, &size);
1041: break;
1042:
1043: case KINFO_LOADAVG:
1044: name[0] = CTL_VM;
1045: name[1] = VM_LOADAVG;
1046: error = userland_sysctl(p, name, 2, uap->where, uap->size,
1047: 0, 0, 0, &size);
1048: break;
1049:
1050: case KINFO_CLOCKRATE:
1051: name[0] = CTL_KERN;
1052: name[1] = KERN_CLOCKRATE;
1053: error = userland_sysctl(p, name, 2, uap->where, uap->size,
1054: 0, 0, 0, &size);
1055: break;
1056:
1057: case KINFO_BSDI_SYSINFO: {
1058: /*
1059: * this is pretty crude, but it's just enough for uname()
1060: * from BSDI's 1.x libc to work.
1061: *
1062: * In particular, it doesn't return the same results when
1063: * the supplied buffer is too small. BSDI's version apparently
1064: * will return the amount copied, and set the *size to how
1065: * much was needed. The emulation framework here isn't capable
1066: * of that, so we just set both to the amount copied.
1067: * BSDI's 2.x product apparently fails with ENOMEM in this
1068: * scenario.
1069: */
1070:
1071: u_int needed;
1072: u_int left;
1073: char *s;
1074:
1075: bzero((char *)&bsdi_si, sizeof(bsdi_si));
1076: bzero(bsdi_strings, sizeof(bsdi_strings));
1077:
1078: s = bsdi_strings;
1079:
1080: bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1081: strcpy(s, ostype);
1082: s += strlen(s) + 1;
1083:
1084: bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1085: strcpy(s, osrelease);
1086: s += strlen(s) + 1;
1087:
1088: bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1089: strcpy(s, machine);
1090: s += strlen(s) + 1;
1091:
1092: needed = sizeof(bsdi_si) + (s - bsdi_strings);
1093:
1094: if (uap->where == NULL) {
1095: /* process is asking how much buffer to supply.. */
1096: size = needed;
1097: error = 0;
1098: break;
1099: }
1100:
1101:
1102: /* if too much buffer supplied, trim it down */
1103: if (size > needed)
1104: size = needed;
1105:
1106: /* how much of the buffer is remaining */
1107: left = size;
1108:
1109: if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1110: break;
1111:
1112: /* is there any point in continuing? */
1113: if (left > sizeof(bsdi_si)) {
1114: left -= sizeof(bsdi_si);
1115: error = copyout(&bsdi_strings,
1116: uap->where + sizeof(bsdi_si), left);
1117: }
1118: break;
1119: }
1120:
1121: default:
1122: return (EOPNOTSUPP);
1123: }
1124: if (error)
1125: return (error);
1126: p->p_retval[0] = size;
1127: if (uap->size)
1128: error = copyout((caddr_t)&size, (caddr_t)uap->size,
1129: sizeof(size));
1130: return (error);
1131: }
1132: #endif /* COMPAT_43 */
1133:
1134: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.