source: rtems/cpukit/libnetworking/kern/kern_sysctl.c @ b2b143f4

4.104.114.84.95
Last change on this file since b2b143f4 was b2b143f4, checked in by Joel Sherrill <joel.sherrill@…>, on 03/05/04 at 17:58:51

2004-03-05 Joel Sherrill <joel@…>

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