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

4.104.114.84.95
Last change on this file since 0739963 was 0739963, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/19/04 at 13:49:10

2004-04-19 Ralf Corsepius <ralf_corsepius@…>

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