source: rtems-libbsd/freebsd/sys/kern/kern_sysctl.c @ c99816e

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since c99816e was c99816e, checked in by Sebastian Huber <sebastian.huber@…>, on 10/30/13 at 14:24:00

Implement sysctl_handle_opaque()

FIXME: The snapshots are not reliable.

  • Property mode set to 100644
File size: 35.2 KB
Line 
1#include <machine/rtems-bsd-config.h>
2
3/*-
4 * Copyright (c) 1982, 1986, 1989, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Mike Karels at Berkeley Software Design, Inc.
9 *
10 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
11 * project, to make these variables more userfriendly.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *      @(#)kern_sysctl.c       8.4 (Berkeley) 4/14/94
38 */
39
40#ifdef __rtems__
41/* FIXME */
42#undef sysctl
43#endif /* __rtems__ */
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD$");
46
47#include <rtems/bsd/local/opt_compat.h>
48#include <rtems/bsd/local/opt_ktrace.h>
49
50#include <rtems/bsd/sys/param.h>
51#include <sys/systm.h>
52#include <sys/kernel.h>
53#include <sys/sysctl.h>
54#include <sys/malloc.h>
55#include <sys/priv.h>
56#include <sys/proc.h>
57#include <sys/jail.h>
58#include <rtems/bsd/sys/lock.h>
59#include <sys/mutex.h>
60#include <sys/sx.h>
61#include <sys/sysproto.h>
62#include <sys/uio.h>
63#ifdef KTRACE
64#include <sys/ktrace.h>
65#endif
66
67#include <net/vnet.h>
68
69#include <security/mac/mac_framework.h>
70#include <vm/vm.h>
71#include <vm/vm_extern.h>
72
73#ifdef __rtems__
74/* From FreeBSD file 'sys/kern/kern_mib.c' */
75SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, "Sysctl internal magic");
76SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, "High kernel, proc, limits &c");
77SYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, "Debugging");
78SYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, "hardware");
79#endif /* __rtems__ */
80static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
81static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
82static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
83
84/*
85 * The sysctllock protects the MIB tree.  It also protects sysctl
86 * contexts used with dynamic sysctls.  The sysctl_register_oid() and
87 * sysctl_unregister_oid() routines require the sysctllock to already
88 * be held, so the sysctl_lock() and sysctl_unlock() routines are
89 * provided for the few places in the kernel which need to use that
90 * API rather than using the dynamic API.  Use of the dynamic API is
91 * strongly encouraged for most code.
92 *
93 * The sysctlmemlock is used to limit the amount of user memory wired for
94 * sysctl requests.  This is implemented by serializing any userland
95 * sysctl requests larger than a single page via an exclusive lock.
96 */
97static struct sx sysctllock;
98static struct sx sysctlmemlock;
99
100#define SYSCTL_SLOCK()          sx_slock(&sysctllock)
101#define SYSCTL_SUNLOCK()        sx_sunlock(&sysctllock)
102#define SYSCTL_XLOCK()          sx_xlock(&sysctllock)
103#define SYSCTL_XUNLOCK()        sx_xunlock(&sysctllock)
104#define SYSCTL_ASSERT_XLOCKED() sx_assert(&sysctllock, SA_XLOCKED)
105#define SYSCTL_ASSERT_LOCKED()  sx_assert(&sysctllock, SA_LOCKED)
106#define SYSCTL_INIT()           sx_init(&sysctllock, "sysctl lock")
107
108static int sysctl_root(SYSCTL_HANDLER_ARGS);
109
110struct sysctl_oid_list sysctl__children; /* root list */
111
112static int      sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
113                    int recurse);
114
115static struct sysctl_oid *
116sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
117{
118        struct sysctl_oid *oidp;
119
120        SYSCTL_ASSERT_LOCKED();
121        SLIST_FOREACH(oidp, list, oid_link) {
122                if (strcmp(oidp->oid_name, name) == 0) {
123                        return (oidp);
124                }
125        }
126        return (NULL);
127}
128
129/*
130 * Initialization of the MIB tree.
131 *
132 * Order by number in each list.
133 */
134void
135sysctl_lock(void)
136{
137
138        SYSCTL_XLOCK();
139}
140
141void
142sysctl_unlock(void)
143{
144
145        SYSCTL_XUNLOCK();
146}
147
148void
149sysctl_register_oid(struct sysctl_oid *oidp)
150{
151        struct sysctl_oid_list *parent = oidp->oid_parent;
152        struct sysctl_oid *p;
153        struct sysctl_oid *q;
154
155        /*
156         * First check if another oid with the same name already
157         * exists in the parent's list.
158         */
159        SYSCTL_ASSERT_XLOCKED();
160        p = sysctl_find_oidname(oidp->oid_name, parent);
161        if (p != NULL) {
162                if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
163                        p->oid_refcnt++;
164                        return;
165                } else {
166                        printf("can't re-use a leaf (%s)!\n", p->oid_name);
167                        return;
168                }
169        }
170        /*
171         * If this oid has a number OID_AUTO, give it a number which
172         * is greater than any current oid.
173         * NOTE: DO NOT change the starting value here, change it in
174         * <sys/sysctl.h>, and make sure it is at least 256 to
175         * accomodate e.g. net.inet.raw as a static sysctl node.
176         */
177        if (oidp->oid_number == OID_AUTO) {
178                static int newoid = CTL_AUTO_START;
179
180                oidp->oid_number = newoid++;
181                if (newoid == 0x7fffffff)
182                        panic("out of oids");
183        }
184#if 0
185        else if (oidp->oid_number >= CTL_AUTO_START) {
186                /* do not panic; this happens when unregistering sysctl sets */
187                printf("static sysctl oid too high: %d", oidp->oid_number);
188        }
189#endif
190
191        /*
192         * Insert the oid into the parent's list in order.
193         */
194        q = NULL;
195        SLIST_FOREACH(p, parent, oid_link) {
196                if (oidp->oid_number < p->oid_number)
197                        break;
198                q = p;
199        }
200        if (q)
201                SLIST_INSERT_AFTER(q, oidp, oid_link);
202        else
203                SLIST_INSERT_HEAD(parent, oidp, oid_link);
204}
205
206void
207sysctl_unregister_oid(struct sysctl_oid *oidp)
208{
209        struct sysctl_oid *p;
210        int error;
211
212        SYSCTL_ASSERT_XLOCKED();
213        error = ENOENT;
214        if (oidp->oid_number == OID_AUTO) {
215                error = EINVAL;
216        } else {
217                SLIST_FOREACH(p, oidp->oid_parent, oid_link) {
218                        if (p == oidp) {
219                                SLIST_REMOVE(oidp->oid_parent, oidp,
220                                    sysctl_oid, oid_link);
221                                error = 0;
222                                break;
223                        }
224                }
225        }
226
227        /*
228         * This can happen when a module fails to register and is
229         * being unloaded afterwards.  It should not be a panic()
230         * for normal use.
231         */
232        if (error)
233                printf("%s: failed to unregister sysctl\n", __func__);
234}
235
236/* Initialize a new context to keep track of dynamically added sysctls. */
237int
238sysctl_ctx_init(struct sysctl_ctx_list *c)
239{
240
241        if (c == NULL) {
242                return (EINVAL);
243        }
244
245        /*
246         * No locking here, the caller is responsible for not adding
247         * new nodes to a context until after this function has
248         * returned.
249         */
250        TAILQ_INIT(c);
251        return (0);
252}
253
254/* Free the context, and destroy all dynamic oids registered in this context */
255int
256sysctl_ctx_free(struct sysctl_ctx_list *clist)
257{
258        struct sysctl_ctx_entry *e, *e1;
259        int error;
260
261        error = 0;
262        /*
263         * First perform a "dry run" to check if it's ok to remove oids.
264         * XXX FIXME
265         * XXX This algorithm is a hack. But I don't know any
266         * XXX better solution for now...
267         */
268        SYSCTL_XLOCK();
269        TAILQ_FOREACH(e, clist, link) {
270                error = sysctl_remove_oid_locked(e->entry, 0, 0);
271                if (error)
272                        break;
273        }
274        /*
275         * Restore deregistered entries, either from the end,
276         * or from the place where error occured.
277         * e contains the entry that was not unregistered
278         */
279        if (error)
280                e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
281        else
282                e1 = TAILQ_LAST(clist, sysctl_ctx_list);
283        while (e1 != NULL) {
284                sysctl_register_oid(e1->entry);
285                e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
286        }
287        if (error) {
288                SYSCTL_XUNLOCK();
289                return(EBUSY);
290        }
291        /* Now really delete the entries */
292        e = TAILQ_FIRST(clist);
293        while (e != NULL) {
294                e1 = TAILQ_NEXT(e, link);
295                error = sysctl_remove_oid_locked(e->entry, 1, 0);
296                if (error)
297                        panic("sysctl_remove_oid: corrupt tree, entry: %s",
298                            e->entry->oid_name);
299                free(e, M_SYSCTLOID);
300                e = e1;
301        }
302        SYSCTL_XUNLOCK();
303        return (error);
304}
305
306/* Add an entry to the context */
307struct sysctl_ctx_entry *
308sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
309{
310        struct sysctl_ctx_entry *e;
311
312        SYSCTL_ASSERT_XLOCKED();
313        if (clist == NULL || oidp == NULL)
314                return(NULL);
315        e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
316        e->entry = oidp;
317        TAILQ_INSERT_HEAD(clist, e, link);
318        return (e);
319}
320
321/* Find an entry in the context */
322struct sysctl_ctx_entry *
323sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
324{
325        struct sysctl_ctx_entry *e;
326
327        SYSCTL_ASSERT_LOCKED();
328        if (clist == NULL || oidp == NULL)
329                return(NULL);
330        TAILQ_FOREACH(e, clist, link) {
331                if(e->entry == oidp)
332                        return(e);
333        }
334        return (e);
335}
336
337/*
338 * Delete an entry from the context.
339 * NOTE: this function doesn't free oidp! You have to remove it
340 * with sysctl_remove_oid().
341 */
342int
343sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
344{
345        struct sysctl_ctx_entry *e;
346
347        if (clist == NULL || oidp == NULL)
348                return (EINVAL);
349        SYSCTL_XLOCK();
350        e = sysctl_ctx_entry_find(clist, oidp);
351        if (e != NULL) {
352                TAILQ_REMOVE(clist, e, link);
353                SYSCTL_XUNLOCK();
354                free(e, M_SYSCTLOID);
355                return (0);
356        } else {
357                SYSCTL_XUNLOCK();
358                return (ENOENT);
359        }
360}
361
362/*
363 * Remove dynamically created sysctl trees.
364 * oidp - top of the tree to be removed
365 * del - if 0 - just deregister, otherwise free up entries as well
366 * recurse - if != 0 traverse the subtree to be deleted
367 */
368int
369sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
370{
371        int error;
372
373        SYSCTL_XLOCK();
374        error = sysctl_remove_oid_locked(oidp, del, recurse);
375        SYSCTL_XUNLOCK();
376        return (error);
377}
378
379static int
380sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
381{
382        struct sysctl_oid *p;
383        int error;
384
385        SYSCTL_ASSERT_XLOCKED();
386        if (oidp == NULL)
387                return(EINVAL);
388        if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
389                printf("can't remove non-dynamic nodes!\n");
390                return (EINVAL);
391        }
392        /*
393         * WARNING: normal method to do this should be through
394         * sysctl_ctx_free(). Use recursing as the last resort
395         * method to purge your sysctl tree of leftovers...
396         * However, if some other code still references these nodes,
397         * it will panic.
398         */
399        if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
400                if (oidp->oid_refcnt == 1) {
401                        SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
402                                if (!recurse)
403                                        return (ENOTEMPTY);
404                                error = sysctl_remove_oid_locked(p, del,
405                                    recurse);
406                                if (error)
407                                        return (error);
408                        }
409                        if (del)
410                                free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
411                }
412        }
413        if (oidp->oid_refcnt > 1 ) {
414                oidp->oid_refcnt--;
415        } else {
416                if (oidp->oid_refcnt == 0) {
417                        printf("Warning: bad oid_refcnt=%u (%s)!\n",
418                                oidp->oid_refcnt, oidp->oid_name);
419                        return (EINVAL);
420                }
421                sysctl_unregister_oid(oidp);
422                if (del) {
423                        if (oidp->oid_descr)
424                                free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID);
425                        free((void *)(uintptr_t)(const void *)oidp->oid_name,
426                             M_SYSCTLOID);
427                        free(oidp, M_SYSCTLOID);
428                }
429        }
430        return (0);
431}
432
433/*
434 * Create new sysctls at run time.
435 * clist may point to a valid context initialized with sysctl_ctx_init().
436 */
437struct sysctl_oid *
438sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
439        int number, const char *name, int kind, void *arg1, int arg2,
440        int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
441{
442        struct sysctl_oid *oidp;
443        ssize_t len;
444        char *newname;
445
446        /* You have to hook up somewhere.. */
447        if (parent == NULL)
448                return(NULL);
449        /* Check if the node already exists, otherwise create it */
450        SYSCTL_XLOCK();
451        oidp = sysctl_find_oidname(name, parent);
452        if (oidp != NULL) {
453                if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
454                        oidp->oid_refcnt++;
455                        /* Update the context */
456                        if (clist != NULL)
457                                sysctl_ctx_entry_add(clist, oidp);
458                        SYSCTL_XUNLOCK();
459                        return (oidp);
460                } else {
461                        SYSCTL_XUNLOCK();
462                        printf("can't re-use a leaf (%s)!\n", name);
463                        return (NULL);
464                }
465        }
466        oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
467        oidp->oid_parent = parent;
468        SLIST_NEXT(oidp, oid_link) = NULL;
469        oidp->oid_number = number;
470        oidp->oid_refcnt = 1;
471        len = strlen(name);
472        newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
473        bcopy(name, newname, len + 1);
474        newname[len] = '\0';
475        oidp->oid_name = newname;
476        oidp->oid_handler = handler;
477        oidp->oid_kind = CTLFLAG_DYN | kind;
478        if ((kind & CTLTYPE) == CTLTYPE_NODE) {
479                /* Allocate space for children */
480                SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list),
481                    M_SYSCTLOID, M_WAITOK));
482                SLIST_INIT(SYSCTL_CHILDREN(oidp));
483        } else {
484                oidp->oid_arg1 = arg1;
485                oidp->oid_arg2 = arg2;
486        }
487        oidp->oid_fmt = fmt;
488        if (descr) {
489                int len = strlen(descr) + 1;
490                oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK);
491                if (oidp->oid_descr)
492                        strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
493        }
494        /* Update the context, if used */
495        if (clist != NULL)
496                sysctl_ctx_entry_add(clist, oidp);
497        /* Register this oid */
498        sysctl_register_oid(oidp);
499        SYSCTL_XUNLOCK();
500        return (oidp);
501}
502
503/*
504 * Rename an existing oid.
505 */
506void
507sysctl_rename_oid(struct sysctl_oid *oidp, const char *name)
508{
509        ssize_t len;
510        char *newname;
511        void *oldname;
512
513        len = strlen(name);
514        newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
515        bcopy(name, newname, len + 1);
516        newname[len] = '\0';
517        SYSCTL_XLOCK();
518        oldname = (void *)(uintptr_t)(const void *)oidp->oid_name;
519        oidp->oid_name = newname;
520        SYSCTL_XUNLOCK();
521        free(oldname, M_SYSCTLOID);
522}
523
524/*
525 * Reparent an existing oid.
526 */
527int
528sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
529{
530        struct sysctl_oid *oidp;
531
532        SYSCTL_XLOCK();
533        if (oid->oid_parent == parent) {
534                SYSCTL_XUNLOCK();
535                return (0);
536        }
537        oidp = sysctl_find_oidname(oid->oid_name, parent);
538        if (oidp != NULL) {
539                SYSCTL_XUNLOCK();
540                return (EEXIST);
541        }
542        sysctl_unregister_oid(oid);
543        oid->oid_parent = parent;
544        oid->oid_number = OID_AUTO;
545        sysctl_register_oid(oid);
546        SYSCTL_XUNLOCK();
547        return (0);
548}
549
550/*
551 * Register the kernel's oids on startup.
552 */
553SET_DECLARE(sysctl_set, struct sysctl_oid);
554
555static void
556sysctl_register_all(void *arg)
557{
558        struct sysctl_oid **oidp;
559
560        sx_init(&sysctlmemlock, "sysctl mem");
561        SYSCTL_INIT();
562        SYSCTL_XLOCK();
563        SET_FOREACH(oidp, sysctl_set)
564                sysctl_register_oid(*oidp);
565        SYSCTL_XUNLOCK();
566}
567SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
568
569/*
570 * "Staff-functions"
571 *
572 * These functions implement a presently undocumented interface
573 * used by the sysctl program to walk the tree, and get the type
574 * so it can print the value.
575 * This interface is under work and consideration, and should probably
576 * be killed with a big axe by the first person who can find the time.
577 * (be aware though, that the proper interface isn't as obvious as it
578 * may seem, there are various conflicting requirements.
579 *
580 * {0,0}        printf the entire MIB-tree.
581 * {0,1,...}    return the name of the "..." OID.
582 * {0,2,...}    return the next OID.
583 * {0,3}        return the OID of the name in "new"
584 * {0,4,...}    return the kind & format info for the "..." OID.
585 * {0,5,...}    return the description the "..." OID.
586 */
587
588#ifdef SYSCTL_DEBUG
589static void
590sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
591{
592        int k;
593        struct sysctl_oid *oidp;
594
595        SYSCTL_ASSERT_LOCKED();
596        SLIST_FOREACH(oidp, l, oid_link) {
597
598                for (k=0; k<i; k++)
599                        printf(" ");
600
601                printf("%d %s ", oidp->oid_number, oidp->oid_name);
602
603                printf("%c%c",
604                        oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
605                        oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
606
607                if (oidp->oid_handler)
608                        printf(" *Handler");
609
610                switch (oidp->oid_kind & CTLTYPE) {
611                        case CTLTYPE_NODE:
612                                printf(" Node\n");
613                                if (!oidp->oid_handler) {
614                                        sysctl_sysctl_debug_dump_node(
615                                                oidp->oid_arg1, i+2);
616                                }
617                                break;
618                        case CTLTYPE_INT:    printf(" Int\n"); break;
619                        case CTLTYPE_STRING: printf(" String\n"); break;
620                        case CTLTYPE_QUAD:   printf(" Quad\n"); break;
621                        case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
622                        default:             printf("\n");
623                }
624
625        }
626}
627
628static int
629sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
630{
631        int error;
632
633        error = priv_check(req->td, PRIV_SYSCTL_DEBUG);
634        if (error)
635                return (error);
636        sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
637        return (ENOENT);
638}
639
640SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
641        0, 0, sysctl_sysctl_debug, "-", "");
642#endif
643
644static int
645sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
646{
647        int *name = (int *) arg1;
648        u_int namelen = arg2;
649        int error = 0;
650        struct sysctl_oid *oid;
651        struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
652        char buf[10];
653
654        SYSCTL_ASSERT_LOCKED();
655        while (namelen) {
656                if (!lsp) {
657                        snprintf(buf,sizeof(buf),"%d",*name);
658                        if (req->oldidx)
659                                error = SYSCTL_OUT(req, ".", 1);
660                        if (!error)
661                                error = SYSCTL_OUT(req, buf, strlen(buf));
662                        if (error)
663                                return (error);
664                        namelen--;
665                        name++;
666                        continue;
667                }
668                lsp2 = 0;
669                SLIST_FOREACH(oid, lsp, oid_link) {
670                        if (oid->oid_number != *name)
671                                continue;
672
673                        if (req->oldidx)
674                                error = SYSCTL_OUT(req, ".", 1);
675                        if (!error)
676                                error = SYSCTL_OUT(req, oid->oid_name,
677                                        strlen(oid->oid_name));
678                        if (error)
679                                return (error);
680
681                        namelen--;
682                        name++;
683
684                        if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
685                                break;
686
687                        if (oid->oid_handler)
688                                break;
689
690                        lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
691                        break;
692                }
693                lsp = lsp2;
694        }
695        return (SYSCTL_OUT(req, "", 1));
696}
697
698static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
699
700static int
701sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
702        int *next, int *len, int level, struct sysctl_oid **oidpp)
703{
704        struct sysctl_oid *oidp;
705
706        SYSCTL_ASSERT_LOCKED();
707        *len = level;
708        SLIST_FOREACH(oidp, lsp, oid_link) {
709                *next = oidp->oid_number;
710                *oidpp = oidp;
711
712                if (oidp->oid_kind & CTLFLAG_SKIP)
713                        continue;
714
715                if (!namelen) {
716                        if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
717                                return (0);
718                        if (oidp->oid_handler)
719                                /* We really should call the handler here...*/
720                                return (0);
721                        lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
722                        if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
723                                len, level+1, oidpp))
724                                return (0);
725                        goto emptynode;
726                }
727
728                if (oidp->oid_number < *name)
729                        continue;
730
731                if (oidp->oid_number > *name) {
732                        if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
733                                return (0);
734                        if (oidp->oid_handler)
735                                return (0);
736                        lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
737                        if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
738                                next+1, len, level+1, oidpp))
739                                return (0);
740                        goto next;
741                }
742                if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
743                        continue;
744
745                if (oidp->oid_handler)
746                        continue;
747
748                lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
749                if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
750                        len, level+1, oidpp))
751                        return (0);
752        next:
753                namelen = 1;
754        emptynode:
755                *len = level;
756        }
757        return (1);
758}
759
760static int
761sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
762{
763        int *name = (int *) arg1;
764        u_int namelen = arg2;
765        int i, j, error;
766        struct sysctl_oid *oid;
767        struct sysctl_oid_list *lsp = &sysctl__children;
768        int newoid[CTL_MAXNAME];
769
770        i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
771        if (i)
772                return (ENOENT);
773        error = SYSCTL_OUT(req, newoid, j * sizeof (int));
774        return (error);
775}
776
777static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
778
779static int
780name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp)
781{
782        int i;
783        struct sysctl_oid *oidp;
784        struct sysctl_oid_list *lsp = &sysctl__children;
785        char *p;
786
787        SYSCTL_ASSERT_LOCKED();
788
789        if (!*name)
790                return (ENOENT);
791
792        p = name + strlen(name) - 1 ;
793        if (*p == '.')
794                *p = '\0';
795
796        *len = 0;
797
798        for (p = name; *p && *p != '.'; p++)
799                ;
800        i = *p;
801        if (i == '.')
802                *p = '\0';
803
804        oidp = SLIST_FIRST(lsp);
805
806        while (oidp && *len < CTL_MAXNAME) {
807                if (strcmp(name, oidp->oid_name)) {
808                        oidp = SLIST_NEXT(oidp, oid_link);
809                        continue;
810                }
811                *oid++ = oidp->oid_number;
812                (*len)++;
813
814                if (!i) {
815                        if (oidpp)
816                                *oidpp = oidp;
817                        return (0);
818                }
819
820                if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
821                        break;
822
823                if (oidp->oid_handler)
824                        break;
825
826                lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
827                oidp = SLIST_FIRST(lsp);
828                name = p+1;
829                for (p = name; *p && *p != '.'; p++)
830                                ;
831                i = *p;
832                if (i == '.')
833                        *p = '\0';
834        }
835        return (ENOENT);
836}
837
838static int
839sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
840{
841        char *p;
842        int error, oid[CTL_MAXNAME], len;
843        struct sysctl_oid *op = 0;
844
845        SYSCTL_ASSERT_LOCKED();
846
847        if (!req->newlen)
848                return (ENOENT);
849        if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
850                return (ENAMETOOLONG);
851
852        p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
853
854        error = SYSCTL_IN(req, p, req->newlen);
855        if (error) {
856                free(p, M_SYSCTL);
857                return (error);
858        }
859
860        p [req->newlen] = '\0';
861
862        error = name2oid(p, oid, &len, &op);
863
864        free(p, M_SYSCTL);
865
866        if (error)
867                return (error);
868
869        error = SYSCTL_OUT(req, oid, len * sizeof *oid);
870        return (error);
871}
872
873SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY|CTLFLAG_MPSAFE,
874    0, 0, sysctl_sysctl_name2oid, "I", "");
875
876static int
877sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
878{
879        struct sysctl_oid *oid;
880        int error;
881
882        error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
883        if (error)
884                return (error);
885
886        if (!oid->oid_fmt)
887                return (ENOENT);
888        error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
889        if (error)
890                return (error);
891        error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
892        return (error);
893}
894
895
896static SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD|CTLFLAG_MPSAFE,
897    sysctl_sysctl_oidfmt, "");
898
899static int
900sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
901{
902        struct sysctl_oid *oid;
903        int error;
904
905        error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
906        if (error)
907                return (error);
908
909        if (!oid->oid_descr)
910                return (ENOENT);
911        error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
912        return (error);
913}
914
915static SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
916
917/*
918 * Default "handler" functions.
919 */
920
921/*
922 * Handle an int, signed or unsigned.
923 * Two cases:
924 *     a variable:  point arg1 at it.
925 *     a constant:  pass it in arg2.
926 */
927
928int
929sysctl_handle_int(SYSCTL_HANDLER_ARGS)
930{
931        int tmpout, error = 0;
932
933        /*
934         * Attempt to get a coherent snapshot by making a copy of the data.
935         */
936        if (arg1)
937                tmpout = *(int *)arg1;
938        else
939                tmpout = arg2;
940        error = SYSCTL_OUT(req, &tmpout, sizeof(int));
941
942        if (error || !req->newptr)
943                return (error);
944
945        if (!arg1)
946                error = EPERM;
947        else
948                error = SYSCTL_IN(req, arg1, sizeof(int));
949        return (error);
950}
951
952/*
953 * Based on on sysctl_handle_int() convert milliseconds into ticks.
954 * Note: this is used by TCP.
955 */
956
957int
958sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS)
959{
960        int error, s, tt;
961
962        tt = *(int *)arg1;
963        s = (int)((int64_t)tt * 1000 / hz);
964
965        error = sysctl_handle_int(oidp, &s, 0, req);
966        if (error || !req->newptr)
967                return (error);
968
969        tt = (int)((int64_t)s * hz / 1000);
970        if (tt < 1)
971                return (EINVAL);
972
973        *(int *)arg1 = tt;
974        return (0);
975}
976
977
978/*
979 * Handle a long, signed or unsigned.  arg1 points to it.
980 */
981
982int
983sysctl_handle_long(SYSCTL_HANDLER_ARGS)
984{
985        int error = 0;
986        long tmplong;
987#ifdef SCTL_MASK32
988        int tmpint;
989#endif
990
991        /*
992         * Attempt to get a coherent snapshot by making a copy of the data.
993         */
994        if (!arg1)
995                return (EINVAL);
996        tmplong = *(long *)arg1;
997#ifdef SCTL_MASK32
998        if (req->flags & SCTL_MASK32) {
999                tmpint = tmplong;
1000                error = SYSCTL_OUT(req, &tmpint, sizeof(int));
1001        } else
1002#endif
1003                error = SYSCTL_OUT(req, &tmplong, sizeof(long));
1004
1005        if (error || !req->newptr)
1006                return (error);
1007
1008#ifdef SCTL_MASK32
1009        if (req->flags & SCTL_MASK32) {
1010                error = SYSCTL_IN(req, &tmpint, sizeof(int));
1011                *(long *)arg1 = (long)tmpint;
1012        } else
1013#endif
1014                error = SYSCTL_IN(req, arg1, sizeof(long));
1015        return (error);
1016}
1017
1018/*
1019 * Handle a 64 bit int, signed or unsigned.  arg1 points to it.
1020 */
1021
1022int
1023sysctl_handle_quad(SYSCTL_HANDLER_ARGS)
1024{
1025        int error = 0;
1026        uint64_t tmpout;
1027
1028        /*
1029         * Attempt to get a coherent snapshot by making a copy of the data.
1030         */
1031        if (!arg1)
1032                return (EINVAL);
1033        tmpout = *(uint64_t *)arg1;
1034        error = SYSCTL_OUT(req, &tmpout, sizeof(uint64_t));
1035
1036        if (error || !req->newptr)
1037                return (error);
1038
1039        error = SYSCTL_IN(req, arg1, sizeof(uint64_t));
1040        return (error);
1041}
1042
1043/*
1044 * Handle our generic '\0' terminated 'C' string.
1045 * Two cases:
1046 *      a variable string:  point arg1 at it, arg2 is max length.
1047 *      a constant string:  point arg1 at it, arg2 is zero.
1048 */
1049
1050int
1051sysctl_handle_string(SYSCTL_HANDLER_ARGS)
1052{
1053        int error=0;
1054        char *tmparg;
1055        size_t outlen;
1056
1057        /*
1058         * Attempt to get a coherent snapshot by copying to a
1059         * temporary kernel buffer.
1060         */
1061retry:
1062        outlen = strlen((char *)arg1)+1;
1063        tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK);
1064
1065        if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) {
1066                free(tmparg, M_SYSCTLTMP);
1067                goto retry;
1068        }
1069
1070        error = SYSCTL_OUT(req, tmparg, outlen);
1071        free(tmparg, M_SYSCTLTMP);
1072
1073        if (error || !req->newptr)
1074                return (error);
1075
1076        if ((req->newlen - req->newidx) >= arg2) {
1077                error = EINVAL;
1078        } else {
1079                arg2 = (req->newlen - req->newidx);
1080                error = SYSCTL_IN(req, arg1, arg2);
1081                ((char *)arg1)[arg2] = '\0';
1082        }
1083
1084        return (error);
1085}
1086
1087/*
1088 * Handle any kind of opaque data.
1089 * arg1 points to it, arg2 is the size.
1090 */
1091
1092int
1093sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
1094{
1095#ifndef __rtems__
1096        int error, tries;
1097        u_int generation;
1098        struct sysctl_req req2;
1099
1100        /*
1101         * Attempt to get a coherent snapshot, by using the thread
1102         * pre-emption counter updated from within mi_switch() to
1103         * determine if we were pre-empted during a bcopy() or
1104         * copyout(). Make 3 attempts at doing this before giving up.
1105         * If we encounter an error, stop immediately.
1106         */
1107        tries = 0;
1108        req2 = *req;
1109retry:
1110        generation = curthread->td_generation;
1111#else /* __rtems__ */
1112        int error;
1113#endif /* __rtems__ */
1114        error = SYSCTL_OUT(req, arg1, arg2);
1115        if (error)
1116                return (error);
1117#ifndef __rtems__
1118        tries++;
1119        if (generation != curthread->td_generation && tries < 3) {
1120                *req = req2;
1121                goto retry;
1122        }
1123#endif /* __rtems__ */
1124
1125        error = SYSCTL_IN(req, arg1, arg2);
1126
1127        return (error);
1128}
1129
1130/*
1131 * Transfer functions to/from kernel space.
1132 * XXX: rather untested at this point
1133 */
1134static int
1135sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
1136{
1137        size_t i = 0;
1138
1139        if (req->oldptr) {
1140                i = l;
1141                if (req->oldlen <= req->oldidx)
1142                        i = 0;
1143                else
1144                        if (i > req->oldlen - req->oldidx)
1145                                i = req->oldlen - req->oldidx;
1146                if (i > 0)
1147                        bcopy(p, (char *)req->oldptr + req->oldidx, i);
1148        }
1149        req->oldidx += l;
1150        if (req->oldptr && i != l)
1151                return (ENOMEM);
1152        return (0);
1153}
1154
1155static int
1156sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
1157{
1158        if (!req->newptr)
1159                return (0);
1160        if (req->newlen - req->newidx < l)
1161                return (EINVAL);
1162        bcopy((char *)req->newptr + req->newidx, p, l);
1163        req->newidx += l;
1164        return (0);
1165}
1166
1167int
1168kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1169#ifndef __rtems__
1170    size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags)
1171#else /* __rtems__ */
1172    size_t *oldlenp, const void *new, size_t newlen, size_t *retval, int flags)
1173#endif /* __rtems__ */
1174{
1175        int error = 0;
1176        struct sysctl_req req;
1177
1178        bzero(&req, sizeof req);
1179
1180#ifndef __rtems__
1181        req.td = td;
1182#else /* __rtems__ */
1183        req.td = curthread;
1184#endif /* __rtems__ */
1185        req.flags = flags;
1186
1187        if (oldlenp) {
1188                req.oldlen = *oldlenp;
1189        }
1190        req.validlen = req.oldlen;
1191
1192        if (old) {
1193                req.oldptr= old;
1194        }
1195
1196        if (new != NULL) {
1197                req.newlen = newlen;
1198                req.newptr = new;
1199        }
1200
1201        req.oldfunc = sysctl_old_kernel;
1202        req.newfunc = sysctl_new_kernel;
1203        req.lock = REQ_LOCKED;
1204
1205        SYSCTL_SLOCK();
1206        error = sysctl_root(0, name, namelen, &req);
1207        SYSCTL_SUNLOCK();
1208
1209        if (req.lock == REQ_WIRED && req.validlen > 0)
1210                vsunlock(req.oldptr, req.validlen);
1211
1212        if (error && error != ENOMEM)
1213                return (error);
1214
1215        if (retval) {
1216                if (req.oldptr && req.oldidx > req.validlen)
1217                        *retval = req.validlen;
1218                else
1219                        *retval = req.oldidx;
1220        }
1221        return (error);
1222}
1223
1224#ifndef __rtems__
1225int
1226kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
1227    void *new, size_t newlen, size_t *retval, int flags)
1228{
1229        int oid[CTL_MAXNAME];
1230        size_t oidlen, plen;
1231        int error;
1232
1233        oid[0] = 0;             /* sysctl internal magic */
1234        oid[1] = 3;             /* name2oid */
1235        oidlen = sizeof(oid);
1236
1237        error = kernel_sysctl(td, oid, 2, oid, &oidlen,
1238            (void *)name, strlen(name), &plen, flags);
1239        if (error)
1240                return (error);
1241
1242        error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
1243            new, newlen, retval, flags);
1244        return (error);
1245}
1246#endif /* __rtems__ */
1247
1248/*
1249 * Transfer function to/from user space.
1250 */
1251static int
1252sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1253{
1254        int error = 0;
1255        size_t i, len, origidx;
1256
1257        origidx = req->oldidx;
1258        req->oldidx += l;
1259        if (req->oldptr == NULL)
1260                return (0);
1261        /*
1262         * If we have not wired the user supplied buffer and we are currently
1263         * holding locks, drop a witness warning, as it's possible that
1264         * write operations to the user page can sleep.
1265         */
1266        if (req->lock != REQ_WIRED)
1267                WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1268                    "sysctl_old_user()");
1269        i = l;
1270        len = req->validlen;
1271        if (len <= origidx)
1272                i = 0;
1273        else {
1274                if (i > len - origidx)
1275                        i = len - origidx;
1276                error = copyout(p, (char *)req->oldptr + origidx, i);
1277        }
1278        if (error)
1279                return (error);
1280        if (i < l)
1281                return (ENOMEM);
1282        return (0);
1283}
1284
1285#ifndef __rtems__
1286static int
1287sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1288{
1289        int error;
1290
1291        if (!req->newptr)
1292                return (0);
1293        if (req->newlen - req->newidx < l)
1294                return (EINVAL);
1295        WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1296            "sysctl_new_user()");
1297        error = copyin((char *)req->newptr + req->newidx, p, l);
1298        req->newidx += l;
1299        return (error);
1300}
1301#endif /* __rtems__ */
1302
1303/*
1304 * Wire the user space destination buffer.  If set to a value greater than
1305 * zero, the len parameter limits the maximum amount of wired memory.
1306 */
1307int
1308sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
1309{
1310        int ret;
1311        size_t wiredlen;
1312
1313        wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen;
1314        ret = 0;
1315        if (req->lock == REQ_LOCKED && req->oldptr &&
1316            req->oldfunc == sysctl_old_user) {
1317                if (wiredlen != 0) {
1318                        ret = vslock(req->oldptr, wiredlen);
1319                        if (ret != 0) {
1320                                if (ret != ENOMEM)
1321                                        return (ret);
1322                                wiredlen = 0;
1323                        }
1324                }
1325                req->lock = REQ_WIRED;
1326                req->validlen = wiredlen;
1327        }
1328        return (0);
1329}
1330
1331int
1332sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1333    int *nindx, struct sysctl_req *req)
1334{
1335        struct sysctl_oid *oid;
1336        int indx;
1337
1338        SYSCTL_ASSERT_LOCKED();
1339        oid = SLIST_FIRST(&sysctl__children);
1340        indx = 0;
1341        while (oid && indx < CTL_MAXNAME) {
1342                if (oid->oid_number == name[indx]) {
1343                        indx++;
1344                        if (oid->oid_kind & CTLFLAG_NOLOCK)
1345                                req->lock = REQ_UNLOCKED;
1346                        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1347                                if (oid->oid_handler != NULL ||
1348                                    indx == namelen) {
1349                                        *noid = oid;
1350                                        if (nindx != NULL)
1351                                                *nindx = indx;
1352                                        return (0);
1353                                }
1354                                oid = SLIST_FIRST(
1355                                    (struct sysctl_oid_list *)oid->oid_arg1);
1356                        } else if (indx == namelen) {
1357                                *noid = oid;
1358                                if (nindx != NULL)
1359                                        *nindx = indx;
1360                                return (0);
1361                        } else {
1362                                return (ENOTDIR);
1363                        }
1364                } else {
1365                        oid = SLIST_NEXT(oid, oid_link);
1366                }
1367        }
1368        return (ENOENT);
1369}
1370
1371/*
1372 * Traverse our tree, and find the right node, execute whatever it points
1373 * to, and return the resulting error code.
1374 */
1375
1376static int
1377sysctl_root(SYSCTL_HANDLER_ARGS)
1378{
1379        struct sysctl_oid *oid;
1380        int error, indx, lvl;
1381
1382        SYSCTL_ASSERT_LOCKED();
1383
1384        error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1385        if (error)
1386                return (error);
1387
1388        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1389                /*
1390                 * You can't call a sysctl when it's a node, but has
1391                 * no handler.  Inform the user that it's a node.
1392                 * The indx may or may not be the same as namelen.
1393                 */
1394                if (oid->oid_handler == NULL)
1395                        return (EISDIR);
1396        }
1397
1398        /* Is this sysctl writable? */
1399        if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
1400                return (EPERM);
1401
1402#ifndef __rtems__
1403        KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
1404
1405        /* Is this sysctl sensitive to securelevels? */
1406        if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
1407                lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
1408                error = securelevel_gt(req->td->td_ucred, lvl);
1409                if (error)
1410                        return (error);
1411        }
1412
1413        /* Is this sysctl writable by only privileged users? */
1414        if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
1415                int priv;
1416
1417                if (oid->oid_kind & CTLFLAG_PRISON)
1418                        priv = PRIV_SYSCTL_WRITEJAIL;
1419#ifdef VIMAGE
1420                else if ((oid->oid_kind & CTLFLAG_VNET) &&
1421                     prison_owns_vnet(req->td->td_ucred))
1422                        priv = PRIV_SYSCTL_WRITEJAIL;
1423#endif
1424                else
1425                        priv = PRIV_SYSCTL_WRITE;
1426                error = priv_check(req->td, priv);
1427                if (error)
1428                        return (error);
1429        }
1430#else /* __rtems__ */
1431        (void) lvl;
1432#endif /* __rtems__ */
1433
1434        if (!oid->oid_handler)
1435                return (EINVAL);
1436
1437        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1438                arg1 = (int *)arg1 + indx;
1439                arg2 -= indx;
1440        } else {
1441                arg1 = oid->oid_arg1;
1442                arg2 = oid->oid_arg2;
1443        }
1444#ifdef MAC
1445        error = mac_system_check_sysctl(req->td->td_ucred, oid, arg1, arg2,
1446            req);
1447        if (error != 0)
1448                return (error);
1449#endif
1450        if (!(oid->oid_kind & CTLFLAG_MPSAFE))
1451                mtx_lock(&Giant);
1452        error = oid->oid_handler(oid, arg1, arg2, req);
1453        if (!(oid->oid_kind & CTLFLAG_MPSAFE))
1454                mtx_unlock(&Giant);
1455
1456        return (error);
1457}
1458
1459#ifndef __rtems__
1460#ifndef _SYS_SYSPROTO_H_
1461struct sysctl_args {
1462        int     *name;
1463        u_int   namelen;
1464        void    *old;
1465        size_t  *oldlenp;
1466        void    *new;
1467        size_t  newlen;
1468};
1469#endif
1470int
1471__sysctl(struct thread *td, struct sysctl_args *uap)
1472{
1473        int error, i, name[CTL_MAXNAME];
1474        size_t j;
1475
1476        if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1477                return (EINVAL);
1478
1479        error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1480        if (error)
1481                return (error);
1482
1483        error = userland_sysctl(td, name, uap->namelen,
1484                uap->old, uap->oldlenp, 0,
1485                uap->new, uap->newlen, &j, 0);
1486        if (error && error != ENOMEM)
1487                return (error);
1488        if (uap->oldlenp) {
1489                i = copyout(&j, uap->oldlenp, sizeof(j));
1490                if (i)
1491                        return (i);
1492        }
1493        return (error);
1494}
1495
1496/*
1497 * This is used from various compatibility syscalls too.  That's why name
1498 * must be in kernel space.
1499 */
1500int
1501userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1502    size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval,
1503    int flags)
1504{
1505        int error = 0, memlocked;
1506        struct sysctl_req req;
1507
1508        bzero(&req, sizeof req);
1509
1510        req.td = td;
1511        req.flags = flags;
1512
1513        if (oldlenp) {
1514                if (inkernel) {
1515                        req.oldlen = *oldlenp;
1516                } else {
1517                        error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1518                        if (error)
1519                                return (error);
1520                }
1521        }
1522        req.validlen = req.oldlen;
1523
1524        if (old) {
1525                if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1526                        return (EFAULT);
1527                req.oldptr= old;
1528        }
1529
1530        if (new != NULL) {
1531                if (!useracc(new, newlen, VM_PROT_READ))
1532                        return (EFAULT);
1533                req.newlen = newlen;
1534                req.newptr = new;
1535        }
1536
1537        req.oldfunc = sysctl_old_user;
1538        req.newfunc = sysctl_new_user;
1539        req.lock = REQ_LOCKED;
1540
1541#ifdef KTRACE
1542        if (KTRPOINT(curthread, KTR_SYSCTL))
1543                ktrsysctl(name, namelen);
1544#endif
1545
1546        if (req.oldlen > PAGE_SIZE) {
1547                memlocked = 1;
1548                sx_xlock(&sysctlmemlock);
1549        } else
1550                memlocked = 0;
1551        CURVNET_SET(TD_TO_VNET(td));
1552
1553        for (;;) {
1554                req.oldidx = 0;
1555                req.newidx = 0;
1556                SYSCTL_SLOCK();
1557                error = sysctl_root(0, name, namelen, &req);
1558                SYSCTL_SUNLOCK();
1559                if (error != EAGAIN)
1560                        break;
1561                uio_yield();
1562        }
1563
1564        CURVNET_RESTORE();
1565
1566        if (req.lock == REQ_WIRED && req.validlen > 0)
1567                vsunlock(req.oldptr, req.validlen);
1568        if (memlocked)
1569                sx_xunlock(&sysctlmemlock);
1570
1571        if (error && error != ENOMEM)
1572                return (error);
1573
1574        if (retval) {
1575                if (req.oldptr && req.oldidx > req.validlen)
1576                        *retval = req.validlen;
1577                else
1578                        *retval = req.oldidx;
1579        }
1580        return (error);
1581}
1582#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.