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