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

4.104.114.84.95
Last change on this file since e980b219 was ca66d01, checked in by Joel Sherrill <joel.sherrill@…>, on 04/30/04 at 16:20:36

2004-04-30 Joel Sherrill <joel@…>

  • libnetworking/kern/kern_sysctl.c: sysctl_register_all cannot be static with RTEMS.
  • Property mode set to 100644
File size: 33.8 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 lock")
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
426#if defined(__rtems__)
427void
428#else
429static void
430#endif
431sysctl_register_all(void *arg)
432{
433        struct sysctl_oid **oidp;
434
435        SYSCTL_INIT();
436        SET_FOREACH(oidp, sysctl_set)
437                sysctl_register_oid(*oidp);
438}
439SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
440
441/*
442 * "Staff-functions"
443 *
444 * These functions implement a presently undocumented interface
445 * used by the sysctl program to walk the tree, and get the type
446 * so it can print the value.
447 * This interface is under work and consideration, and should probably
448 * be killed with a big axe by the first person who can find the time.
449 * (be aware though, that the proper interface isn't as obvious as it
450 * may seem, there are various conflicting requirements.
451 *
452 * {0,0}        printf the entire MIB-tree.
453 * {0,1,...}    return the name of the "..." OID.
454 * {0,2,...}    return the next OID.
455 * {0,3}        return the OID of the name in "new"
456 * {0,4,...}    return the kind & format info for the "..." OID.
457 * {0,5,...}    return the description the "..." OID.
458 */
459
460static void
461sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
462{
463        int k;
464        struct sysctl_oid *oidp;
465
466        SLIST_FOREACH(oidp, l, oid_link) {
467
468                for (k=0; k<i; k++)
469                        printf(" ");
470
471                printf("%d %s ", oidp->oid_number, oidp->oid_name);
472
473                printf("%c%c",
474                        oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
475                        oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
476
477                if (oidp->oid_handler)
478                        printf(" *Handler");
479
480                switch (oidp->oid_kind & CTLTYPE) {
481                        case CTLTYPE_NODE:
482                                printf(" Node\n");
483                                if (!oidp->oid_handler) {
484                                        sysctl_sysctl_debug_dump_node(
485                                                oidp->oid_arg1, i+2);
486                                }
487                                break;
488                        case CTLTYPE_INT:    printf(" Int\n"); break;
489                        case CTLTYPE_STRING: printf(" String\n"); break;
490                        case CTLTYPE_QUAD:   printf(" Quad\n"); break;
491                        case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
492                        default:             printf("\n");
493                }
494
495        }
496}
497
498static int
499sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
500{
501#ifndef __rtems__
502        int error;
503
504        error = suser(req->td);
505        if (error)
506                return error;
507#endif
508        sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
509        return ENOENT;
510}
511
512SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
513        0, 0, sysctl_sysctl_debug, "-", "");
514
515static int
516sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
517{
518        int *name = (int *) arg1;
519        u_int namelen = arg2;
520        int error = 0;
521        struct sysctl_oid *oid;
522        struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
523        char buf[10];
524
525        while (namelen) {
526                if (!lsp) {
527                        snprintf(buf,sizeof(buf),"%d",*name);
528                        if (req->oldidx)
529                                error = SYSCTL_OUT(req, ".", 1);
530                        if (!error)
531                                error = SYSCTL_OUT(req, buf, strlen(buf));
532                        if (error)
533                                return (error);
534                        namelen--;
535                        name++;
536                        continue;
537                }
538                lsp2 = 0;
539                SLIST_FOREACH(oid, lsp, oid_link) {
540                        if (oid->oid_number != *name)
541                                continue;
542
543                        if (req->oldidx)
544                                error = SYSCTL_OUT(req, ".", 1);
545                        if (!error)
546                                error = SYSCTL_OUT(req, oid->oid_name,
547                                        strlen(oid->oid_name));
548                        if (error)
549                                return (error);
550
551                        namelen--;
552                        name++;
553
554                        if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
555                                break;
556
557                        if (oid->oid_handler)
558                                break;
559
560                        lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
561                        break;
562                }
563                lsp = lsp2;
564        }
565        return (SYSCTL_OUT(req, "", 1));
566}
567
568SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
569
570static int
571sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
572        int *next, int *len, int level, struct sysctl_oid **oidpp)
573{
574        struct sysctl_oid *oidp;
575
576        *len = level;
577        SLIST_FOREACH(oidp, lsp, oid_link) {
578                *next = oidp->oid_number;
579                *oidpp = oidp;
580
581                if (oidp->oid_kind & CTLFLAG_SKIP)
582                        continue;
583
584                if (!namelen) {
585                        if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
586                                return 0;
587                        if (oidp->oid_handler)
588                                /* We really should call the handler here...*/
589                                return 0;
590                        lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
591                        if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
592                                len, level+1, oidpp))
593                                return 0;
594                        goto emptynode;
595                }
596
597                if (oidp->oid_number < *name)
598                        continue;
599
600                if (oidp->oid_number > *name) {
601                        if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
602                                return 0;
603                        if (oidp->oid_handler)
604                                return 0;
605                        lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
606                        if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
607                                next+1, len, level+1, oidpp))
608                                return (0);
609                        goto next;
610                }
611                if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
612                        continue;
613
614                if (oidp->oid_handler)
615                        continue;
616
617                lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
618                if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
619                        len, level+1, oidpp))
620                        return (0);
621        next:
622                namelen = 1;
623        emptynode:
624                *len = level;
625        }
626        return 1;
627}
628
629static int
630sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
631{
632        int *name = (int *) arg1;
633        u_int namelen = arg2;
634        int i, j, error;
635        struct sysctl_oid *oid;
636        struct sysctl_oid_list *lsp = &sysctl__children;
637        int newoid[CTL_MAXNAME];
638
639        i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
640        if (i)
641                return ENOENT;
642        error = SYSCTL_OUT(req, newoid, j * sizeof (int));
643        return (error);
644}
645
646SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
647
648static int
649name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
650{
651        int i;
652        struct sysctl_oid *oidp;
653        struct sysctl_oid_list *lsp = &sysctl__children;
654        char *p;
655
656        if (!*name)
657                return ENOENT;
658
659        p = name + strlen(name) - 1 ;
660        if (*p == '.')
661                *p = '\0';
662
663        *len = 0;
664
665        for (p = name; *p && *p != '.'; p++)
666                ;
667        i = *p;
668        if (i == '.')
669                *p = '\0';
670
671        oidp = SLIST_FIRST(lsp);
672
673        while (oidp && *len < CTL_MAXNAME) {
674                if (strcmp(name, oidp->oid_name)) {
675                        oidp = SLIST_NEXT(oidp, oid_link);
676                        continue;
677                }
678                *oid++ = oidp->oid_number;
679                (*len)++;
680
681                if (!i) {
682                        if (oidpp)
683                                *oidpp = oidp;
684                        return (0);
685                }
686
687                if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
688                        break;
689
690                if (oidp->oid_handler)
691                        break;
692
693                lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
694                oidp = SLIST_FIRST(lsp);
695                name = p+1;
696                for (p = name; *p && *p != '.'; p++)
697                                ;
698                i = *p;
699                if (i == '.')
700                        *p = '\0';
701        }
702        return ENOENT;
703}
704
705static int
706sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
707{
708        char *p;
709        int error, oid[CTL_MAXNAME], len;
710        struct sysctl_oid *op = 0;
711
712        if (!req->newlen)
713                return ENOENT;
714        if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
715                return (ENAMETOOLONG);
716
717        p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
718
719        error = SYSCTL_IN(req, p, req->newlen);
720        if (error) {
721                free(p, M_SYSCTL);
722                return (error);
723        }
724
725        p [req->newlen] = '\0';
726
727        error = name2oid(p, oid, &len, &op);
728
729        free(p, M_SYSCTL);
730
731        if (error)
732                return (error);
733
734        error = SYSCTL_OUT(req, oid, len * sizeof *oid);
735        return (error);
736}
737
738SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
739        sysctl_sysctl_name2oid, "I", "");
740
741static int
742sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
743{
744        struct sysctl_oid *oid;
745        int error;
746
747        error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
748        if (error)
749                return (error);
750
751        if (!oid->oid_fmt)
752                return (ENOENT);
753        error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
754        if (error)
755                return (error);
756        error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
757        return (error);
758}
759
760
761SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
762
763static int
764sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
765{
766        struct sysctl_oid *oid;
767        int error;
768
769        error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
770        if (error)
771                return (error);
772
773        if (!oid->descr)
774                return (ENOENT);
775        error = SYSCTL_OUT(req, oid->descr, strlen(oid->descr) + 1);
776        return (error);
777}
778
779SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
780
781/*
782 * Default "handler" functions.
783 */
784
785/*
786 * Handle an int, signed or unsigned.
787 * Two cases:
788 *     a variable:  point arg1 at it.
789 *     a constant:  pass it in arg2.
790 */
791
792int
793sysctl_handle_int(SYSCTL_HANDLER_ARGS)
794{
795        int tmpout, error = 0;
796
797        /*
798         * Attempt to get a coherent snapshot by making a copy of the data.
799         */
800        if (arg1)
801                tmpout = *(int *)arg1;
802        else
803                tmpout = arg2;
804        error = SYSCTL_OUT(req, &tmpout, sizeof(int));
805
806        if (error || !req->newptr)
807                return (error);
808
809        if (!arg1)
810                error = EPERM;
811        else
812                error = SYSCTL_IN(req, arg1, sizeof(int));
813        return (error);
814}
815
816/*
817 * Handle a long, signed or unsigned.  arg1 points to it.
818 */
819
820int
821sysctl_handle_long(SYSCTL_HANDLER_ARGS)
822{
823        int error = 0;
824        long tmpout;
825
826        /*
827         * Attempt to get a coherent snapshot by making a copy of the data.
828         */
829        if (!arg1)
830                return (EINVAL);
831        tmpout = *(long *)arg1;
832        error = SYSCTL_OUT(req, &tmpout, sizeof(long));
833
834        if (error || !req->newptr)
835                return (error);
836
837        error = SYSCTL_IN(req, arg1, sizeof(long));
838        return (error);
839}
840
841/*
842 * Handle our generic '\0' terminated 'C' string.
843 * Two cases:
844 *      a variable string:  point arg1 at it, arg2 is max length.
845 *      a constant string:  point arg1 at it, arg2 is zero.
846 */
847
848int
849sysctl_handle_string(SYSCTL_HANDLER_ARGS)
850{
851        int error=0;
852        char *tmparg;
853        size_t outlen;
854
855        /*
856         * Attempt to get a coherent snapshot by copying to a
857         * temporary kernel buffer.
858         */
859retry:
860        outlen = strlen((char *)arg1)+1;
861        tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK);
862
863        if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) {
864                free(tmparg, M_SYSCTLTMP);
865                goto retry;
866        }
867
868        error = SYSCTL_OUT(req, tmparg, outlen);
869        free(tmparg, M_SYSCTLTMP);
870
871        if (error || !req->newptr)
872                return (error);
873
874        if ((req->newlen - req->newidx) >= arg2) {
875                error = EINVAL;
876        } else {
877                arg2 = (req->newlen - req->newidx);
878                error = SYSCTL_IN(req, arg1, arg2);
879                ((char *)arg1)[arg2] = '\0';
880        }
881
882        return (error);
883}
884
885/*
886 * Handle any kind of opaque data.
887 * arg1 points to it, arg2 is the size.
888 */
889
890int
891sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
892{
893        int error;
894        void *tmparg;
895
896        /*
897         * Attempt to get a coherent snapshot, either by wiring the
898         * user space buffer or copying to a temporary kernel buffer
899         * depending on the size of the data.
900         */
901        if (arg2 > PAGE_SIZE) {
902                sysctl_wire_old_buffer(req, arg2);
903                error = SYSCTL_OUT(req, arg1, arg2);
904        } else {
905                tmparg = malloc(arg2, M_SYSCTLTMP, M_WAITOK);
906                bcopy(arg1, tmparg, arg2);
907                error = SYSCTL_OUT(req, tmparg, arg2);
908                free(tmparg, M_SYSCTLTMP);
909        }
910
911        if (error || !req->newptr)
912                return (error);
913
914        error = SYSCTL_IN(req, arg1, arg2);
915
916        return (error);
917}
918
919/*
920 * Transfer functions to/from kernel space.
921 * XXX: rather untested at this point
922 */
923static int
924sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
925{
926        size_t i = 0;
927
928        if (req->oldptr) {
929                i = l;
930                if (req->oldlen <= req->oldidx)
931                        i = 0;
932                else
933                        if (i > req->oldlen - req->oldidx)
934                                i = req->oldlen - req->oldidx;
935                if (i > 0)
936                        bcopy(p, (char *)req->oldptr + req->oldidx, i);
937        }
938        req->oldidx += l;
939        if (req->oldptr && i != l)
940                return (ENOMEM);
941        return (0);
942}
943
944static int
945sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
946{
947        if (!req->newptr)
948                return 0;
949        if (req->newlen - req->newidx < l)
950                return (EINVAL);
951        bcopy((char *)req->newptr + req->newidx, p, l);
952        req->newidx += l;
953        return (0);
954}
955
956int
957kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
958    size_t *oldlenp, void *new, size_t newlen, size_t *retval)
959{
960        int error = 0;
961        struct sysctl_req req;
962
963        bzero(&req, sizeof req);
964
965        req.td = td;
966
967        if (oldlenp) {
968                req.oldlen = *oldlenp;
969        }
970
971        if (old) {
972                req.oldptr= old;
973        }
974
975        if (new != NULL) {
976                req.newlen = newlen;
977                req.newptr = new;
978        }
979
980        req.oldfunc = sysctl_old_kernel;
981        req.newfunc = sysctl_new_kernel;
982        req.lock = REQ_LOCKED;
983
984        SYSCTL_LOCK();
985
986        error = sysctl_root(0, name, namelen, &req);
987
988        if (req.lock == REQ_WIRED)
989#ifdef __rtems__
990    printf ("kern_sysctl: vsunlock needs to be called!\n");
991#else
992                vsunlock(req.oldptr, req.oldlen);
993#endif
994
995        SYSCTL_UNLOCK();
996
997        if (error && error != ENOMEM)
998                return (error);
999
1000        if (retval) {
1001                if (req.oldptr && req.oldidx > req.oldlen)
1002                        *retval = req.oldlen;
1003                else
1004                        *retval = req.oldidx;
1005        }
1006        return (error);
1007}
1008
1009int
1010kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
1011    void *new, size_t newlen, size_t *retval)
1012{
1013        int oid[CTL_MAXNAME];
1014        size_t oidlen, plen;
1015        int error;
1016
1017        oid[0] = 0;             /* sysctl internal magic */
1018        oid[1] = 3;             /* name2oid */
1019        oidlen = sizeof(oid);
1020
1021        error = kernel_sysctl(td, oid, 2, oid, &oidlen,
1022            (void *)name, strlen(name), &plen);
1023        if (error)
1024                return (error);
1025
1026        error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
1027            new, newlen, retval);
1028        return (error);
1029}
1030
1031/*
1032 * Transfer function to/from user space.
1033 */
1034static int
1035sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1036{
1037        int error = 0;
1038        size_t i = 0;
1039
1040#ifndef __rtems__
1041        if (req->lock == 1 && req->oldptr)
1042                WITNESS_SLEEP(1, NULL);
1043#endif
1044        if (req->oldptr) {
1045                i = l;
1046                if (req->oldlen <= req->oldidx)
1047                        i = 0;
1048                else
1049                        if (i > req->oldlen - req->oldidx)
1050                                i = req->oldlen - req->oldidx;
1051                if (i > 0)
1052                        error = copyout(p, (char *)req->oldptr + req->oldidx,
1053                                        i);
1054        }
1055        req->oldidx += l;
1056        if (error)
1057                return (error);
1058        if (req->oldptr && i < l)
1059                return (ENOMEM);
1060        return (0);
1061}
1062
1063static int
1064sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1065{
1066        int error;
1067
1068        if (!req->newptr)
1069                return 0;
1070        if (req->newlen - req->newidx < l)
1071                return (EINVAL);
1072        error = copyin((char *)req->newptr + req->newidx, p, l);
1073        req->newidx += l;
1074        return (error);
1075}
1076
1077/*
1078 * Wire the user space destination buffer.  If set to a value greater than
1079 * zero, the len parameter limits the maximum amount of wired memory.
1080 *
1081 * XXX - The len parameter is currently ignored due to the lack of
1082 * a place to save it in the sysctl_req structure so that the matching
1083 * amount of memory can be unwired in the sysctl exit code.
1084 */
1085int
1086sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
1087{
1088        if (req->lock == REQ_LOCKED && req->oldptr &&
1089            req->oldfunc == sysctl_old_user) {
1090#ifndef __rtems__
1091                vslock(req->oldptr, req->oldlen);
1092#endif
1093                req->lock = REQ_WIRED;
1094        }
1095        return (0);
1096}
1097
1098int
1099sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1100    int *nindx, struct sysctl_req *req)
1101{
1102        struct sysctl_oid *oid;
1103        int indx;
1104
1105        oid = SLIST_FIRST(&sysctl__children);
1106        indx = 0;
1107        while (oid && indx < CTL_MAXNAME) {
1108                if (oid->oid_number == name[indx]) {
1109                        indx++;
1110                        if (oid->oid_kind & CTLFLAG_NOLOCK)
1111                                req->lock = REQ_UNLOCKED;
1112                        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1113                                if (oid->oid_handler != NULL ||
1114                                    indx == namelen) {
1115                                        *noid = oid;
1116                                        if (nindx != NULL)
1117                                                *nindx = indx;
1118                                        return (0);
1119                                }
1120                                oid = SLIST_FIRST(
1121                                    (struct sysctl_oid_list *)oid->oid_arg1);
1122                        } else if (indx == namelen) {
1123                                *noid = oid;
1124                                if (nindx != NULL)
1125                                        *nindx = indx;
1126                                return (0);
1127                        } else {
1128                                return (ENOTDIR);
1129                        }
1130                } else {
1131                        oid = SLIST_NEXT(oid, oid_link);
1132                }
1133        }
1134        return (ENOENT);
1135}
1136
1137/*
1138 * Traverse our tree, and find the right node, execute whatever it points
1139 * to, and return the resulting error code.
1140 */
1141
1142static int
1143sysctl_root(SYSCTL_HANDLER_ARGS)
1144{
1145        struct sysctl_oid *oid;
1146        int error, indx;
1147
1148        error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1149        if (error)
1150                return (error);
1151
1152        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1153                /*
1154                 * You can't call a sysctl when it's a node, but has
1155                 * no handler.  Inform the user that it's a node.
1156                 * The indx may or may not be the same as namelen.
1157                 */
1158                if (oid->oid_handler == NULL)
1159                        return (EISDIR);
1160        }
1161
1162        /* Is this sysctl writable? */
1163        if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
1164                return (EPERM);
1165
1166#ifndef __rtems__
1167        KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
1168
1169        /* Is this sysctl sensitive to securelevels? */
1170        if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
1171                error = securelevel_gt(req->td->td_ucred, 0);
1172                if (error)
1173                        return (error);
1174        }
1175
1176        /* Is this sysctl writable by only privileged users? */
1177        if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
1178                int flags;
1179
1180                if (oid->oid_kind & CTLFLAG_PRISON)
1181                        flags = PRISON_ROOT;
1182                else
1183                        flags = 0;
1184                error = suser_cred(req->td->td_ucred, flags);
1185                if (error)
1186                        return (error);
1187        }
1188#endif
1189
1190        if (!oid->oid_handler)
1191                return EINVAL;
1192
1193        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
1194                error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
1195                    req);
1196        else
1197                error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
1198                    req);
1199        return (error);
1200}
1201
1202#ifndef _SYS_SYSPROTO_H_
1203struct sysctl_args {
1204        int     *name;
1205        u_int   namelen;
1206        void    *old;
1207        size_t  *oldlenp;
1208        void    *new;
1209        size_t  newlen;
1210};
1211#endif
1212
1213/*
1214 * MPSAFE
1215 */
1216int
1217__sysctl(struct thread *td, struct sysctl_args *uap)
1218{
1219        int error, name[CTL_MAXNAME];
1220        size_t j;
1221
1222        if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1223                return (EINVAL);
1224
1225        error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1226        if (error)
1227                return (error);
1228
1229        mtx_lock(&Giant);
1230
1231        error = userland_sysctl(td, name, uap->namelen,
1232                uap->old, uap->oldlenp, 0,
1233                uap->new, uap->newlen, &j);
1234        if (error && error != ENOMEM)
1235                goto done2;
1236        if (uap->oldlenp) {
1237                int i = copyout(&j, uap->oldlenp, sizeof(j));
1238                if (i)
1239                        error = i;
1240        }
1241done2:
1242        mtx_unlock(&Giant);
1243        return (error);
1244}
1245
1246/*
1247 * This is used from various compatibility syscalls too.  That's why name
1248 * must be in kernel space.
1249 */
1250int
1251userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1252    size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1253{
1254        int error = 0;
1255        struct sysctl_req req, req2;
1256
1257        bzero(&req, sizeof req);
1258
1259        req.td = td;
1260
1261        if (oldlenp) {
1262                if (inkernel) {
1263                        req.oldlen = *oldlenp;
1264                } else {
1265                        error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1266                        if (error)
1267                                return (error);
1268                }
1269        }
1270
1271        if (old) {
1272#ifndef __rtems__
1273                if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1274                        return (EFAULT);
1275#endif
1276                req.oldptr= old;
1277        }
1278
1279        if (new != NULL) {
1280#ifndef __rtems__
1281                if (!useracc(new, req.newlen, VM_PROT_READ))
1282                        return (EFAULT);
1283#endif
1284                req.newlen = newlen;
1285                req.newptr = new;
1286        }
1287
1288        req.oldfunc = sysctl_old_user;
1289        req.newfunc = sysctl_new_user;
1290        req.lock = REQ_LOCKED;
1291
1292        SYSCTL_LOCK();
1293
1294#ifdef MAC
1295        error = mac_check_system_sysctl(td->td_ucred, name, namelen, old,
1296            oldlenp, inkernel, new, newlen);
1297        if (error) {
1298                SYSCTL_UNLOCK();
1299                return (error);
1300        }
1301#endif
1302
1303        do {
1304            req2 = req;
1305            error = sysctl_root(0, name, namelen, &req2);
1306        } while (error == EAGAIN);
1307
1308        req = req2;
1309#ifndef __rtems__
1310        if (req.lock == REQ_WIRED)
1311                vsunlock(req.oldptr, req.oldlen);
1312#endif
1313
1314        SYSCTL_UNLOCK();
1315
1316        if (error && error != ENOMEM)
1317                return (error);
1318
1319        if (retval) {
1320                if (req.oldptr && req.oldidx > req.oldlen)
1321                        *retval = req.oldlen;
1322                else
1323                        *retval = req.oldidx;
1324        }
1325        return (error);
1326}
1327
1328#ifdef COMPAT_43
1329#include <sys/socket.h>
1330#include <vm/vm_param.h>
1331
1332#define KINFO_PROC              (0<<8)
1333#define KINFO_RT                (1<<8)
1334#define KINFO_VNODE             (2<<8)
1335#define KINFO_FILE              (3<<8)
1336#define KINFO_METER             (4<<8)
1337#define KINFO_LOADAVG           (5<<8)
1338#define KINFO_CLOCKRATE         (6<<8)
1339
1340/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1341#define KINFO_BSDI_SYSINFO      (101<<8)
1342
1343/*
1344 * XXX this is bloat, but I hope it's better here than on the potentially
1345 * limited kernel stack...  -Peter
1346 */
1347
1348static struct {
1349        int     bsdi_machine;           /* "i386" on BSD/386 */
1350/*      ^^^ this is an offset to the string, relative to the struct start */
1351        char    *pad0;
1352        long    pad1;
1353        long    pad2;
1354        long    pad3;
1355        u_long  pad4;
1356        u_long  pad5;
1357        u_long  pad6;
1358
1359        int     bsdi_ostype;            /* "BSD/386" on BSD/386 */
1360        int     bsdi_osrelease;         /* "1.1" on BSD/386 */
1361        long    pad7;
1362        long    pad8;
1363        char    *pad9;
1364
1365        long    pad10;
1366        long    pad11;
1367        int     pad12;
1368        long    pad13;
1369        quad_t  pad14;
1370        long    pad15;
1371
1372        struct  timeval pad16;
1373        /* we dont set this, because BSDI's uname used gethostname() instead */
1374        int     bsdi_hostname;          /* hostname on BSD/386 */
1375
1376        /* the actual string data is appended here */
1377
1378} bsdi_si;
1379/*
1380 * this data is appended to the end of the bsdi_si structure during copyout.
1381 * The "char *" offsets are relative to the base of the bsdi_si struct.
1382 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1383 * should not exceed the length of the buffer here... (or else!! :-)
1384 */
1385static char bsdi_strings[80];   /* It had better be less than this! */
1386
1387#ifndef _SYS_SYSPROTO_H_
1388struct getkerninfo_args {
1389        int     op;
1390        char    *where;
1391        size_t  *size;
1392        int     arg;
1393};
1394#endif
1395
1396/*
1397 * MPSAFE
1398 */
1399int
1400ogetkerninfo(struct thread *td, struct getkerninfo_args *uap)
1401{
1402        int error, name[6];
1403        size_t size;
1404        u_int needed = 0;
1405
1406        mtx_lock(&Giant);
1407
1408        switch (uap->op & 0xff00) {
1409
1410        case KINFO_RT:
1411                name[0] = CTL_NET;
1412                name[1] = PF_ROUTE;
1413                name[2] = 0;
1414                name[3] = (uap->op & 0xff0000) >> 16;
1415                name[4] = uap->op & 0xff;
1416                name[5] = uap->arg;
1417                error = userland_sysctl(td, name, 6, uap->where, uap->size,
1418                        0, 0, 0, &size);
1419                break;
1420
1421        case KINFO_VNODE:
1422                name[0] = CTL_KERN;
1423                name[1] = KERN_VNODE;
1424                error = userland_sysctl(td, name, 2, uap->where, uap->size,
1425                        0, 0, 0, &size);
1426                break;
1427
1428        case KINFO_PROC:
1429                name[0] = CTL_KERN;
1430                name[1] = KERN_PROC;
1431                name[2] = uap->op & 0xff;
1432                name[3] = uap->arg;
1433                error = userland_sysctl(td, name, 4, uap->where, uap->size,
1434                        0, 0, 0, &size);
1435                break;
1436
1437        case KINFO_FILE:
1438                name[0] = CTL_KERN;
1439                name[1] = KERN_FILE;
1440                error = userland_sysctl(td, name, 2, uap->where, uap->size,
1441                        0, 0, 0, &size);
1442                break;
1443
1444        case KINFO_METER:
1445                name[0] = CTL_VM;
1446                name[1] = VM_TOTAL;
1447                error = userland_sysctl(td, name, 2, uap->where, uap->size,
1448                        0, 0, 0, &size);
1449                break;
1450
1451        case KINFO_LOADAVG:
1452                name[0] = CTL_VM;
1453                name[1] = VM_LOADAVG;
1454                error = userland_sysctl(td, name, 2, uap->where, uap->size,
1455                        0, 0, 0, &size);
1456                break;
1457
1458        case KINFO_CLOCKRATE:
1459                name[0] = CTL_KERN;
1460                name[1] = KERN_CLOCKRATE;
1461                error = userland_sysctl(td, name, 2, uap->where, uap->size,
1462                        0, 0, 0, &size);
1463                break;
1464
1465        case KINFO_BSDI_SYSINFO: {
1466                /*
1467                 * this is pretty crude, but it's just enough for uname()
1468                 * from BSDI's 1.x libc to work.
1469                 *
1470                 * *size gives the size of the buffer before the call, and
1471                 * the amount of data copied after a successful call.
1472                 * If successful, the return value is the amount of data
1473                 * available, which can be larger than *size.
1474                 *
1475                 * BSDI's 2.x product apparently fails with ENOMEM if *size
1476                 * is too small.
1477                 */
1478
1479                u_int left;
1480                char *s;
1481
1482                bzero((char *)&bsdi_si, sizeof(bsdi_si));
1483                bzero(bsdi_strings, sizeof(bsdi_strings));
1484
1485                s = bsdi_strings;
1486
1487                bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1488                strcpy(s, ostype);
1489                s += strlen(s) + 1;
1490
1491                bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1492                strcpy(s, osrelease);
1493                s += strlen(s) + 1;
1494
1495                bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1496                strcpy(s, machine);
1497                s += strlen(s) + 1;
1498
1499                needed = sizeof(bsdi_si) + (s - bsdi_strings);
1500
1501                if ((uap->where == NULL) || (uap->size == NULL)) {
1502                        /* process is asking how much buffer to supply.. */
1503                        size = needed;
1504                        error = 0;
1505                        break;
1506                }
1507
1508                if ((error = copyin(uap->size, &size, sizeof(size))) != 0)
1509                        break;
1510
1511                /* if too much buffer supplied, trim it down */
1512                if (size > needed)
1513                        size = needed;
1514
1515                /* how much of the buffer is remaining */
1516                left = size;
1517
1518                if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1519                        break;
1520
1521                /* is there any point in continuing? */
1522                if (left > sizeof(bsdi_si)) {
1523                        left -= sizeof(bsdi_si);
1524                        error = copyout(&bsdi_strings,
1525                                        uap->where + sizeof(bsdi_si), left);
1526                }
1527                break;
1528        }
1529
1530        default:
1531                error = EOPNOTSUPP;
1532                break;
1533        }
1534        if (error == 0) {
1535                td->td_retval[0] = needed ? needed : size;
1536                if (uap->size) {
1537                        error = copyout(&size, uap->size, sizeof(size));
1538                }
1539        }
1540        mtx_unlock(&Giant);
1541        return (error);
1542}
1543#endif /* COMPAT_43 */
Note: See TracBrowser for help on using the repository browser.