OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [kern/] [kern_sysctl.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      src/sys/kern/kerm_sysctl.c
4
//
5
//==========================================================================
6
// ####BSDCOPYRIGHTBEGIN####                                    
7
// -------------------------------------------                  
8
// This file is part of eCos, the Embedded Configurable Operating System.
9
//
10
// Portions of this software may have been derived from FreeBSD 
11
// or other sources, and if so are covered by the appropriate copyright
12
// and license included herein.                                 
13
//
14
// Portions created by the Free Software Foundation are         
15
// Copyright (C) 2002 Free Software Foundation, Inc.            
16
// -------------------------------------------                  
17
// ####BSDCOPYRIGHTEND####                                      
18
//==========================================================================
19
 
20
/*-
21
 * Copyright (c) 1982, 1986, 1989, 1993
22
 *      The Regents of the University of California.  All rights reserved.
23
 *
24
 * This code is derived from software contributed to Berkeley by
25
 * Mike Karels at Berkeley Software Design, Inc.
26
 *
27
 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
28
 * project, to make these variables more userfriendly.
29
 *
30
 * Redistribution and use in source and binary forms, with or without
31
 * modification, are permitted provided that the following conditions
32
 * are met:
33
 * 1. Redistributions of source code must retain the above copyright
34
 *    notice, this list of conditions and the following disclaimer.
35
 * 2. Redistributions in binary form must reproduce the above copyright
36
 *    notice, this list of conditions and the following disclaimer in the
37
 *    documentation and/or other materials provided with the distribution.
38
 * 3. All advertising materials mentioning features or use of this software
39
 *    must display the following acknowledgement:
40
 *      This product includes software developed by the University of
41
 *      California, Berkeley and its contributors.
42
 * 4. Neither the name of the University nor the names of its contributors
43
 *    may be used to endorse or promote products derived from this software
44
 *    without specific prior written permission.
45
 *
46
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56
 * SUCH DAMAGE.
57
 *
58
 *      @(#)kern_sysctl.c       8.4 (Berkeley) 4/14/94
59
 * $FreeBSD: src/sys/kern/kern_sysctl.c,v 1.92.2.5 2001/06/18 23:48:13 dd Exp $
60
 */
61
 
62
//#include "opt_compat.h"
63
 
64
#include <sys/param.h>
65
//#include <sys/systm.h>
66
//#include <sys/kernel.h>
67
//#include <sys/buf.h>
68
#include <sys/sysctl.h>
69
#include <sys/malloc.h>
70
//#include <sys/proc.h>
71
//#include <sys/sysproto.h>
72
//#include <vm/vm.h>
73
//#include <vm/vm_extern.h>
74
 
75
#include <cyg/kernel/kapi.h>
76
#include <cyg/hal/hal_tables.h>
77
 
78
/*
79
 * Locking and stats
80
 */
81
 
82
static cyg_mutex_t mutex;
83
static int mutex_init = 0;
84
 
85
static int sysctl_root(SYSCTL_HANDLER_ARGS);
86
 
87
struct sysctl_oid_list sysctl__children; /* root list */
88
SYSCTL_NODE( , CTL_NET, net , CTLFLAG_RW, NULL, "Network root");
89
SYSCTL_NODE( , CTL_DEBUG, sysctl , CTLFLAG_RW, NULL, "Debug root");
90
 
91
struct sysctl_oid_list sysctl__net_children;
92
  struct sysctl_oid_list sysctl__sysctl_children;
93
 
94
static struct sysctl_oid *
95
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
96
{
97
        struct sysctl_oid *oidp;
98
 
99
        SLIST_FOREACH(oidp, list, oid_link) {
100
                if (strcmp(oidp->oid_name, name) == 0) {
101
                        return (oidp);
102
                }
103
        }
104
        return (NULL);
105
}
106
 
107
/*
108
 * Initialization of the MIB tree.
109
 *
110
 * Order by number in each list.
111
 */
112
 
113
void sysctl_register_oid(struct sysctl_oid *oidp)
114
{
115
        struct sysctl_oid_list *parent = oidp->oid_parent;
116
        struct sysctl_oid *p;
117
        struct sysctl_oid *q;
118
        int n;
119
 
120
        /*
121
         * First check if another oid with the same name already
122
         * exists in the parent's list.
123
         */
124
        p = sysctl_find_oidname(oidp->oid_name, parent);
125
        if (p != NULL) {
126
                if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
127
                        p->oid_refcnt++;
128
                        return;
129
                } else {
130
                        printf("can't re-use a leaf (%s)!\n", p->oid_name);
131
                        return;
132
                }
133
        }
134
        /*
135
         * If this oid has a number OID_AUTO, give it a number which
136
         * is greater than any current oid.  Make sure it is at least
137
         * 100 to leave space for pre-assigned oid numbers.
138
         */
139
        if (oidp->oid_number == OID_AUTO) {
140
                /* First, find the highest oid in the parent list >99 */
141
                n = 99;
142
                SLIST_FOREACH(p, parent, oid_link) {
143
                        if (p->oid_number > n)
144
                                n = p->oid_number;
145
                }
146
                oidp->oid_number = n + 1;
147
        }
148
 
149
        /*
150
         * Insert the oid into the parent's list in order.
151
         */
152
        q = NULL;
153
        SLIST_FOREACH(p, parent, oid_link) {
154
                if (oidp->oid_number < p->oid_number)
155
                        break;
156
                q = p;
157
        }
158
        if (q)
159
                SLIST_INSERT_AFTER(q, oidp, oid_link);
160
        else
161
                SLIST_INSERT_HEAD(parent, oidp, oid_link);
162
}
163
 
164
void sysctl_unregister_oid(struct sysctl_oid *oidp)
165
{
166
        SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
167
}
168
 
169
/* Initialize a new context to keep track of dynamically added sysctls. */
170
int
171
sysctl_ctx_init(struct sysctl_ctx_list *c)
172
{
173
 
174
        if (c == NULL) {
175
                return (EINVAL);
176
        }
177
        TAILQ_INIT(c);
178
        return (0);
179
}
180
 
181
/* Free the context, and destroy all dynamic oids registered in this context */
182
int
183
sysctl_ctx_free(struct sysctl_ctx_list *clist)
184
{
185
        struct sysctl_ctx_entry *e, *e1;
186
        int error;
187
 
188
        error = 0;
189
        /*
190
         * First perform a "dry run" to check if it's ok to remove oids.
191
         * XXX FIXME
192
         * XXX This algorithm is a hack. But I don't know any
193
         * XXX better solution for now...
194
         */
195
        TAILQ_FOREACH(e, clist, link) {
196
                error = sysctl_remove_oid(e->entry, 0, 0);
197
                if (error)
198
                        break;
199
        }
200
        /*
201
         * Restore deregistered entries, either from the end,
202
         * or from the place where error occured.
203
         * e contains the entry that was not unregistered
204
         */
205
        if (error)
206
                e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
207
        else
208
                e1 = TAILQ_LAST(clist, sysctl_ctx_list);
209
        while (e1 != NULL) {
210
                sysctl_register_oid(e1->entry);
211
                e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
212
        }
213
        if (error)
214
                return(EBUSY);
215
        /* Now really delete the entries */
216
        e = TAILQ_FIRST(clist);
217
        while (e != NULL) {
218
                e1 = TAILQ_NEXT(e, link);
219
                error = sysctl_remove_oid(e->entry, 1, 0);
220
                if (error)
221
                        panic("sysctl_remove_oid: corrupt tree, entry: %s",
222
                            e->entry->oid_name);
223
                free(e, M_SYSCTLOID);
224
                e = e1;
225
        }
226
        return (error);
227
}
228
 
229
/* Add an entry to the context */
230
struct sysctl_ctx_entry *
231
sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
232
{
233
        struct sysctl_ctx_entry *e;
234
 
235
        if (clist == NULL || oidp == NULL)
236
                return(NULL);
237
        e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
238
        e->entry = oidp;
239
        TAILQ_INSERT_HEAD(clist, e, link);
240
        return (e);
241
}
242
 
243
/* Find an entry in the context */
244
struct sysctl_ctx_entry *
245
sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
246
{
247
        struct sysctl_ctx_entry *e;
248
 
249
        if (clist == NULL || oidp == NULL)
250
                return(NULL);
251
        for (e = TAILQ_FIRST(clist); e != NULL; e = TAILQ_NEXT(e, link)) {
252
                if(e->entry == oidp)
253
                        return(e);
254
        }
255
        return (e);
256
}
257
 
258
/*
259
 * Delete an entry from the context.
260
 * NOTE: this function doesn't free oidp! You have to remove it
261
 * with sysctl_remove_oid().
262
 */
263
int
264
sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
265
{
266
        struct sysctl_ctx_entry *e;
267
 
268
        if (clist == NULL || oidp == NULL)
269
                return (EINVAL);
270
        e = sysctl_ctx_entry_find(clist, oidp);
271
        if (e != NULL) {
272
                TAILQ_REMOVE(clist, e, link);
273
                free(e, M_SYSCTLOID);
274
                return (0);
275
        } else
276
                return (ENOENT);
277
}
278
 
279
/*
280
 * Remove dynamically created sysctl trees.
281
 * oidp - top of the tree to be removed
282
 * del - if 0 - just deregister, otherwise free up entries as well
283
 * recurse - if != 0 traverse the subtree to be deleted
284
 */
285
int
286
sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
287
{
288
        struct sysctl_oid *p;
289
        int error;
290
 
291
        if (oidp == NULL)
292
                return(EINVAL);
293
        if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
294
                printf("can't remove non-dynamic nodes!\n");
295
                return (EINVAL);
296
        }
297
        /*
298
         * WARNING: normal method to do this should be through
299
         * sysctl_ctx_free(). Use recursing as the last resort
300
         * method to purge your sysctl tree of leftovers...
301
         * However, if some other code still references these nodes,
302
         * it will panic.
303
         */
304
        if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
305
                if (oidp->oid_refcnt == 1) {
306
                        SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
307
                                if (!recurse)
308
                                        return (ENOTEMPTY);
309
                                error = sysctl_remove_oid(p, del, recurse);
310
                                if (error)
311
                                        return (error);
312
                        }
313
                        if (del)
314
                                free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
315
                }
316
        }
317
        if (oidp->oid_refcnt > 1 ) {
318
                oidp->oid_refcnt--;
319
        } else {
320
                if (oidp->oid_refcnt == 0) {
321
                        printf("Warning: bad oid_refcnt=%u (%s)!\n",
322
                                oidp->oid_refcnt, oidp->oid_name);
323
                        return (EINVAL);
324
                }
325
                sysctl_unregister_oid(oidp);
326
                if (del) {
327
                        free((void *)oidp->oid_name,
328
                             M_SYSCTLOID);
329
                        free(oidp, M_SYSCTLOID);
330
                }
331
        }
332
        return (0);
333
}
334
 
335
/*
336
 * Create new sysctls at run time.
337
 * clist may point to a valid context initialized with sysctl_ctx_init().
338
 */
339
struct sysctl_oid *
340
sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
341
        int number, const char *name, int kind, void *arg1, int arg2,
342
        int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
343
{
344
        struct sysctl_oid *oidp;
345
        ssize_t len;
346
        char *newname;
347
 
348
        /* You have to hook up somewhere.. */
349
        if (parent == NULL)
350
                return(NULL);
351
        /* Check if the node already exists, otherwise create it */
352
        oidp = sysctl_find_oidname(name, parent);
353
        if (oidp != NULL) {
354
                if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
355
                        oidp->oid_refcnt++;
356
                        /* Update the context */
357
                        if (clist != NULL)
358
                                sysctl_ctx_entry_add(clist, oidp);
359
                        return (oidp);
360
                } else {
361
                        printf("can't re-use a leaf (%s)!\n", name);
362
                        return (NULL);
363
                }
364
        }
365
        oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK);
366
        bzero(oidp, sizeof(struct sysctl_oid));
367
        oidp->oid_parent = parent;
368
        SLIST_NEXT(oidp, oid_link) = NULL;
369
        oidp->oid_number = number;
370
        oidp->oid_refcnt = 1;
371
        len = strlen(name);
372
        newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
373
        bcopy(name, newname, len + 1);
374
        newname[len] = '\0';
375
        oidp->oid_name = newname;
376
        oidp->oid_handler = handler;
377
        oidp->oid_kind = CTLFLAG_DYN | kind;
378
        if ((kind & CTLTYPE) == CTLTYPE_NODE) {
379
                /* Allocate space for children */
380
                 oidp->oid_arg1 = (struct sysctl_oid_list *) malloc(sizeof(struct sysctl_oid_list),
381
                    M_SYSCTLOID, M_WAITOK);
382
                SLIST_INIT(SYSCTL_CHILDREN(oidp));
383
        } else {
384
                oidp->oid_arg1 = arg1;
385
                oidp->oid_arg2 = arg2;
386
        }
387
        oidp->oid_fmt = fmt;
388
        /* Update the context, if used */
389
        if (clist != NULL)
390
                sysctl_ctx_entry_add(clist, oidp);
391
        /* Register this oid */
392
        sysctl_register_oid(oidp);
393
        return (oidp);
394
}
395
 
396
/*
397
 * Bulk-register all the oids in the table.
398
 */
399
CYG_HAL_TABLE_BEGIN(__sysctl_tab__, sysctl_set);
400
CYG_HAL_TABLE_END(__sysctl_tab_end__, sysctl_set);
401
extern struct sysctl_oid  __sysctl_tab__[];
402
extern struct sysctl_oid  __sysctl_tab_end__;
403
 
404
static void sysctl_register_all(void *arg)
405
{
406
  struct sysctl_oid * oidp;
407
 
408
  for (oidp = __sysctl_tab__ ; oidp != &__sysctl_tab_end__; oidp++) {
409
    sysctl_register_oid(oidp);
410
  }
411
}
412
 
413
SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
414
 
415
/*
416
 * "Staff-functions"
417
 *
418
 * These functions implement a presently undocumented interface
419
 * used by the sysctl program to walk the tree, and get the type
420
 * so it can print the value.
421
 * This interface is under work and consideration, and should probably
422
 * be killed with a big axe by the first person who can find the time.
423
 * (be aware though, that the proper interface isn't as obvious as it
424
 * may seem, there are various conflicting requirements.
425
 *
426
 * {0,0}        printf the entire MIB-tree.
427
 * {0,1,...}    return the name of the "..." OID.
428
 * {0,2,...}    return the next OID.
429
 * {0,3}        return the OID of the name in "new"
430
 * {0,4,...}    return the kind & format info for the "..." OID.
431
 */
432
 
433
static void
434
sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
435
{
436
        int k;
437
        struct sysctl_oid *oidp;
438
 
439
        SLIST_FOREACH(oidp, l, oid_link) {
440
 
441
                for (k=0; k<i; k++)
442
                        printf(" ");
443
 
444
                printf("%d %s ", oidp->oid_number, oidp->oid_name);
445
 
446
                printf("%c%c",
447
                        oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
448
                        oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
449
 
450
                if (oidp->oid_handler)
451
                        printf(" *Handler");
452
 
453
                switch (oidp->oid_kind & CTLTYPE) {
454
                        case CTLTYPE_NODE:
455
                                printf(" Node\n");
456
                                if (!oidp->oid_handler) {
457
                                        sysctl_sysctl_debug_dump_node(
458
                                                oidp->oid_arg1, i+2);
459
                                }
460
                                break;
461
                        case CTLTYPE_INT:    printf(" Int\n"); break;
462
                        case CTLTYPE_STRING: printf(" String\n"); break;
463
                        case CTLTYPE_QUAD:   printf(" Quad\n"); break;
464
                        case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
465
                        default:             printf("\n");
466
                }
467
 
468
        }
469
}
470
 
471
static int
472
sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
473
{
474
        sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
475
        return ENOENT;
476
}
477
 
478
SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
479
        0, 0, sysctl_sysctl_debug, "-", "");
480
 
481
static int
482
sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
483
{
484
        int *name = (int *) arg1;
485
        u_int namelen = arg2;
486
        int error = 0;
487
        struct sysctl_oid *oid;
488
        struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
489
        char buf[10];
490
 
491
        while (namelen) {
492
                if (!lsp) {
493
                        snprintf(buf,sizeof(buf),"%d",*name);
494
                        if (req->oldidx)
495
                                error = SYSCTL_OUT(req, ".", 1);
496
                        if (!error)
497
                                error = SYSCTL_OUT(req, buf, strlen(buf));
498
                        if (error)
499
                                return (error);
500
                        namelen--;
501
                        name++;
502
                        continue;
503
                }
504
                lsp2 = 0;
505
                SLIST_FOREACH(oid, lsp, oid_link) {
506
                        if (oid->oid_number != *name)
507
                                continue;
508
 
509
                        if (req->oldidx)
510
                                error = SYSCTL_OUT(req, ".", 1);
511
                        if (!error)
512
                                error = SYSCTL_OUT(req, oid->oid_name,
513
                                        strlen(oid->oid_name));
514
                        if (error)
515
                                return (error);
516
 
517
                        namelen--;
518
                        name++;
519
 
520
                        if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
521
                                break;
522
 
523
                        if (oid->oid_handler)
524
                                break;
525
 
526
                        lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
527
                        break;
528
                }
529
                lsp = lsp2;
530
        }
531
        return (SYSCTL_OUT(req, "", 1));
532
}
533
 
534
SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
535
 
536
static int
537
sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
538
        int *next, int *len, int level, struct sysctl_oid **oidpp)
539
{
540
        struct sysctl_oid *oidp;
541
 
542
        *len = level;
543
        SLIST_FOREACH(oidp, lsp, oid_link) {
544
                *next = oidp->oid_number;
545
                *oidpp = oidp;
546
 
547
                if (!namelen) {
548
                        if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
549
                                return 0;
550
                        if (oidp->oid_handler)
551
                                /* We really should call the handler here...*/
552
                                return 0;
553
                        lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
554
                        if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
555
                                len, level+1, oidpp))
556
                                return 0;
557
                        goto emptynode;
558
                }
559
 
560
                if (oidp->oid_number < *name)
561
                        continue;
562
 
563
                if (oidp->oid_number > *name) {
564
                        if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
565
                                return 0;
566
                        if (oidp->oid_handler)
567
                                return 0;
568
                        lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
569
                        if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
570
                                next+1, len, level+1, oidpp))
571
                                return (0);
572
                        goto next;
573
                }
574
                if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
575
                        continue;
576
 
577
                if (oidp->oid_handler)
578
                        continue;
579
 
580
                lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
581
                if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
582
                        len, level+1, oidpp))
583
                        return (0);
584
        next:
585
                namelen = 1;
586
        emptynode:
587
                *len = level;
588
        }
589
        return 1;
590
}
591
 
592
static int
593
sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
594
{
595
        int *name = (int *) arg1;
596
        u_int namelen = arg2;
597
        int i, j, error;
598
        struct sysctl_oid *oid;
599
        struct sysctl_oid_list *lsp = &sysctl__children;
600
        int newoid[CTL_MAXNAME];
601
 
602
        i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
603
        if (i)
604
                return ENOENT;
605
        error = SYSCTL_OUT(req, newoid, j * sizeof (int));
606
        return (error);
607
}
608
 
609
SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
610
 
611
static int
612
name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
613
{
614
        int i;
615
        struct sysctl_oid *oidp;
616
        struct sysctl_oid_list *lsp = &sysctl__children;
617
        char *p;
618
 
619
        if (!*name)
620
                return ENOENT;
621
 
622
        p = name + strlen(name) - 1 ;
623
        if (*p == '.')
624
                *p = '\0';
625
 
626
        *len = 0;
627
 
628
        for (p = name; *p && *p != '.'; p++)
629
                ;
630
        i = *p;
631
        if (i == '.')
632
                *p = '\0';
633
 
634
        oidp = SLIST_FIRST(lsp);
635
 
636
        while (oidp && *len < CTL_MAXNAME) {
637
                if (strcmp(name, oidp->oid_name)) {
638
                        oidp = SLIST_NEXT(oidp, oid_link);
639
                        continue;
640
                }
641
                *oid++ = oidp->oid_number;
642
                (*len)++;
643
 
644
                if (!i) {
645
                        if (oidpp)
646
                                *oidpp = oidp;
647
                        return (0);
648
                }
649
 
650
                if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
651
                        break;
652
 
653
                if (oidp->oid_handler)
654
                        break;
655
 
656
                lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
657
                oidp = SLIST_FIRST(lsp);
658
                name = p+1;
659
                for (p = name; *p && *p != '.'; p++)
660
                                ;
661
                i = *p;
662
                if (i == '.')
663
                        *p = '\0';
664
        }
665
        return ENOENT;
666
}
667
 
668
static int
669
sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
670
{
671
        char *p;
672
        int error, oid[CTL_MAXNAME], len;
673
        struct sysctl_oid *op = 0;
674
 
675
        if (!req->newlen)
676
                return ENOENT;
677
        if (req->newlen >= _POSIX_PATH_MAX)     /* XXX arbitrary, undocumented */
678
                return (ENAMETOOLONG);
679
 
680
        p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
681
 
682
        error = SYSCTL_IN(req, p, req->newlen);
683
        if (error) {
684
                free(p, M_SYSCTL);
685
                return (error);
686
        }
687
 
688
        p [req->newlen] = '\0';
689
 
690
        error = name2oid(p, oid, &len, &op);
691
 
692
        free(p, M_SYSCTL);
693
 
694
        if (error)
695
                return (error);
696
 
697
        error = SYSCTL_OUT(req, oid, len * sizeof *oid);
698
        return (error);
699
}
700
 
701
SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
702
        sysctl_sysctl_name2oid, "I", "");
703
 
704
static int
705
sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
706
{
707
        struct sysctl_oid *oid;
708
        int error;
709
 
710
        error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
711
        if (error)
712
                return (error);
713
 
714
        if (!oid->oid_fmt)
715
                return (ENOENT);
716
        error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
717
        if (error)
718
                return (error);
719
        error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
720
        return (error);
721
}
722
 
723
 
724
SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
725
 
726
/*
727
 * Default "handler" functions.
728
 */
729
 
730
/*
731
 * Handle an int, signed or unsigned.
732
 * Two cases:
733
 *     a variable:  point arg1 at it.
734
 *     a constant:  pass it in arg2.
735
 */
736
 
737
int
738
sysctl_handle_int(SYSCTL_HANDLER_ARGS)
739
{
740
        int error = 0;
741
 
742
        if (arg1)
743
                error = SYSCTL_OUT(req, arg1, sizeof(int));
744
        else
745
                error = SYSCTL_OUT(req, &arg2, sizeof(int));
746
 
747
        if (error || !req->newptr)
748
                return (error);
749
 
750
        if (!arg1)
751
                error = EPERM;
752
        else
753
                error = SYSCTL_IN(req, arg1, sizeof(int));
754
        return (error);
755
}
756
 
757
/*
758
 * Handle a long, signed or unsigned.  arg1 points to it.
759
 */
760
 
761
int
762
sysctl_handle_long(SYSCTL_HANDLER_ARGS)
763
{
764
        int error = 0;
765
 
766
        if (!arg1)
767
                return (EINVAL);
768
        error = SYSCTL_OUT(req, arg1, sizeof(long));
769
 
770
        if (error || !req->newptr)
771
                return (error);
772
 
773
        error = SYSCTL_IN(req, arg1, sizeof(long));
774
        return (error);
775
}
776
 
777
/*
778
 * Handle our generic '\0' terminated 'C' string.
779
 * Two cases:
780
 *      a variable string:  point arg1 at it, arg2 is max length.
781
 *      a constant string:  point arg1 at it, arg2 is zero.
782
 */
783
 
784
int
785
sysctl_handle_string(SYSCTL_HANDLER_ARGS)
786
{
787
        int error=0;
788
 
789
        error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
790
 
791
        if (error || !req->newptr)
792
                return (error);
793
 
794
        if ((req->newlen - req->newidx) >= arg2) {
795
                error = EINVAL;
796
        } else {
797
                arg2 = (req->newlen - req->newidx);
798
                error = SYSCTL_IN(req, arg1, arg2);
799
                ((char *)arg1)[arg2] = '\0';
800
        }
801
 
802
        return (error);
803
}
804
 
805
/*
806
 * Handle any kind of opaque data.
807
 * arg1 points to it, arg2 is the size.
808
 */
809
 
810
int
811
sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
812
{
813
        int error;
814
 
815
        error = SYSCTL_OUT(req, arg1, arg2);
816
 
817
        if (error || !req->newptr)
818
                return (error);
819
 
820
        error = SYSCTL_IN(req, arg1, arg2);
821
 
822
        return (error);
823
}
824
 
825
/*
826
 * Transfer function to/from user space.
827
 */
828
static int
829
sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
830
{
831
        int error = 0;
832
        size_t i = 0;
833
 
834
        if (req->oldptr) {
835
                i = l;
836
                if (i > req->oldlen - req->oldidx)
837
                        i = req->oldlen - req->oldidx;
838
                if (i > 0)
839
                        error = copyout(p, (char *)req->oldptr + req->oldidx,
840
                                        i);
841
        }
842
        req->oldidx += l;
843
        if (error)
844
                return (error);
845
        if (req->oldptr && i < l)
846
                return (ENOMEM);
847
        return (0);
848
}
849
 
850
static int
851
sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
852
{
853
        int error;
854
 
855
        if (!req->newptr)
856
                return 0;
857
        if (req->newlen - req->newidx < l)
858
                return (EINVAL);
859
        error = copyin((char *)req->newptr + req->newidx, p, l);
860
        req->newidx += l;
861
        return (error);
862
}
863
 
864
int
865
sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
866
    int *nindx, struct sysctl_req *req)
867
{
868
        struct sysctl_oid *oid;
869
        int indx;
870
 
871
        oid = SLIST_FIRST(&sysctl__children);
872
        indx = 0;
873
        while (oid && indx < CTL_MAXNAME) {
874
                if (oid->oid_number == name[indx]) {
875
                        indx++;
876
                        if (oid->oid_kind & CTLFLAG_NOLOCK)
877
                                req->lock = 0;
878
                        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
879
                                if (oid->oid_handler != NULL ||
880
                                    indx == namelen) {
881
                                        *noid = oid;
882
                                        if (nindx != NULL)
883
                                                *nindx = indx;
884
                                        return (0);
885
                                }
886
                                oid = SLIST_FIRST(
887
                                    (struct sysctl_oid_list *)oid->oid_arg1);
888
                        } else if (indx == namelen) {
889
                                *noid = oid;
890
                                if (nindx != NULL)
891
                                        *nindx = indx;
892
                                return (0);
893
                        } else {
894
                                return (ENOTDIR);
895
                        }
896
                } else {
897
                        oid = SLIST_NEXT(oid, oid_link);
898
                }
899
        }
900
        return (ENOENT);
901
}
902
 
903
/*
904
 * Traverse our tree, and find the right node, execute whatever it points
905
 * to, and return the resulting error code.
906
 */
907
 
908
int
909
sysctl_root(SYSCTL_HANDLER_ARGS)
910
{
911
        struct sysctl_oid *oid;
912
        int error, indx;
913
 
914
        error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
915
        if (error)
916
                return (error);
917
 
918
        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
919
                /*
920
                 * You can't call a sysctl when it's a node, but has
921
                 * no handler.  Inform the user that it's a node.
922
                 * The indx may or may not be the same as namelen.
923
                 */
924
                if (oid->oid_handler == NULL)
925
                        return (EISDIR);
926
        }
927
 
928
        /* If writing isn't allowed */
929
        if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR)))
930
                return (EPERM);
931
 
932
        if (!oid->oid_handler)
933
                return EINVAL;
934
 
935
        if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
936
                error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
937
                    req);
938
        else
939
                error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
940
                    req);
941
        return (error);
942
}
943
 
944
#ifndef _SYS_SYSPROTO_H_
945
struct sysctl_args {
946
        int     *name;
947
        u_int   namelen;
948
        void    *old;
949
        size_t  *oldlenp;
950
        void    *new;
951
        size_t  newlen;
952
};
953
#endif
954
 
955
int
956
sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
957
{
958
        int error = 0;
959
        struct sysctl_req req, req2;
960
        int retval;
961
 
962
        if (!mutex_init) {
963
          cyg_mutex_init(&mutex);
964
          mutex_init = 1;
965
        }
966
 
967
        bzero(&req, sizeof req);
968
 
969
        if (oldlenp) {
970
                req.oldlen = *oldlenp;
971
        }
972
 
973
        if (old) {
974
                req.oldptr= old;
975
        }
976
 
977
        if (new != NULL) {
978
                req.newlen = newlen;
979
                req.newptr = new;
980
        }
981
 
982
        req.oldfunc = sysctl_old_user;
983
        req.newfunc = sysctl_new_user;
984
        req.lock = 1;
985
 
986
        cyg_mutex_lock(&mutex);
987
 
988
        do {
989
            req2 = req;
990
            error = sysctl_root(0, name, namelen, &req2);
991
        } while (error == EAGAIN);
992
 
993
        req = req2;
994
 
995
        cyg_mutex_unlock(&mutex);
996
 
997
        if (error && error != ENOMEM) {
998
          errno = error;
999
          return -1;
1000
        }
1001
 
1002
        if (oldlenp) {
1003
          *oldlenp = req.oldidx;
1004
        }
1005
 
1006
        if (req.oldptr && req.oldidx > req.oldlen)
1007
          retval = req.oldlen;
1008
        else
1009
          retval = req.oldidx;
1010
 
1011
        return retval;
1012
}
1013
 
1014
/* name2oid modify the name passed to it. So we have to make a local copy */
1015
int sysctlnametomib(const char * name, int *mibp, size_t *sizep)
1016
{
1017
  int error = 0, oid[CTL_MAXNAME], len;
1018
  char *namep;
1019
 
1020
  len = strlen(name);
1021
  namep = malloc(len+1,M_SYSCTLOID, M_WAITOK);
1022
  strcpy(namep, name);
1023
 
1024
  error = name2oid(namep, oid, &len, NULL);
1025
  free(namep,M_SYSCTLOID);
1026
 
1027
  if (len * sizeof(int) > *sizep) {
1028
    error = ENOMEM;
1029
  }
1030
 
1031
  if (error) {
1032
    errno = error;
1033
    return -1;
1034
  }
1035
 
1036
  memcpy(mibp, oid, len * sizeof(int));
1037
  *sizep = len;
1038
  return 0;
1039
}
1040
 
1041
int sysctlbyname(const char * name,void *oldp, size_t *oldlenp,
1042
                 void *newp, size_t newlen)
1043
{
1044
  int oid[CTL_MAXNAME];
1045
  size_t sizep = sizeof(oid);
1046
 
1047
  if (sysctlnametomib(name, oid, &sizep) != -1) {
1048
    return (sysctl(oid, sizep, oldp, oldlenp, newp, newlen));
1049
  }
1050
 
1051
  return -1;
1052
}
1053
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.