Merge branch 'vendor/TCSH'
[dragonfly.git] / sys / kern / kern_sysctl.c
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.92.2.9 2003/05/01 22:48:09 trhodes Exp $
37  */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/buf.h>
43 #include <sys/sysctl.h>
44 #include <sys/malloc.h>
45 #include <sys/proc.h>
46 #include <sys/priv.h>
47 #include <sys/sysproto.h>
48 #include <sys/lock.h>
49
50 #include <sys/mplock2.h>
51
52 #include <vm/vm.h>
53 #include <vm/vm_extern.h>
54
55 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
56 static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
57
58 static struct lock sysctl_lkp;
59 static struct lock sysctl_ctx_lkp;
60
61 static void     sysctl_lock(int type);
62 static void     sysctl_unlock(void);
63 static void     sysctl_ctx_lock(int type);
64 static void     sysctl_ctx_unlock(void);
65
66 static int      sysctl_root(SYSCTL_HANDLER_ARGS);
67 static void     sysctl_register_oid_int(struct sysctl_oid *oipd);
68 static void     sysctl_unregister_oid_int(struct sysctl_oid *oipd);
69 static struct sysctl_ctx_entry* sysctl_ctx_entry_find_int
70         (struct sysctl_ctx_list *, struct sysctl_oid *oidp);
71
72 struct sysctl_oid_list sysctl__children; /* root list */
73
74 static struct sysctl_oid *
75 sysctl_find_oidname(const char *name, struct sysctl_oid_list *list, int lock)
76 {
77         struct sysctl_oid *oidp;
78
79         SLIST_FOREACH(oidp, list, oid_link) {
80                 if (strcmp(oidp->oid_name, name) == 0) {
81                         break;
82                 }
83         }
84         return (oidp);
85 }
86
87 /*
88  * Initialization of the MIB tree.
89  *
90  * Order by number in each list.
91  */
92
93 void
94 sysctl_register_oid(struct sysctl_oid *oidp)
95 {
96         sysctl_lock(LK_EXCLUSIVE);
97         sysctl_register_oid_int(oidp);
98         sysctl_unlock();
99 }
100
101 static void
102 sysctl_register_oid_int(struct sysctl_oid *oidp)
103 {
104         struct sysctl_oid_list *parent = oidp->oid_parent;
105         struct sysctl_oid *p;
106         struct sysctl_oid *q;
107
108         /*
109          * First check if another oid with the same name already
110          * exists in the parent's list.
111          */
112         p = sysctl_find_oidname(oidp->oid_name, parent, 0);
113         if (p != NULL) {
114                 if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE)
115                         p->oid_refcnt++;
116                 else
117                         kprintf("can't re-use a leaf (%s)!\n", p->oid_name);
118                 return;
119         }
120
121         /*
122          * If this oid has a number OID_AUTO, give it a number which
123          * is greater than any current oid.  Make sure it is at least
124          * 256 to leave space for pre-assigned oid numbers.
125          */
126         if (oidp->oid_number == OID_AUTO) {
127                 int newoid = 0x100;     /* minimum AUTO oid */
128
129                 /*
130                  * Adjust based on highest oid in parent list
131                  */
132                 SLIST_FOREACH(p, parent, oid_link) {
133                         if (newoid <= p->oid_number)
134                                 newoid = p->oid_number + 1;
135                 }
136                 oidp->oid_number = newoid;
137         }
138
139         /*
140          * Insert the oid into the parent's list in order.
141          */
142         q = NULL;
143         SLIST_FOREACH(p, parent, oid_link) {
144                 if (oidp->oid_number < p->oid_number)
145                         break;
146                 q = p;
147         }
148         if (q)
149                 SLIST_INSERT_AFTER(q, oidp, oid_link);
150         else
151                 SLIST_INSERT_HEAD(parent, oidp, oid_link);
152 }
153
154 void
155 sysctl_unregister_oid(struct sysctl_oid *oidp)
156 {
157         sysctl_lock(LK_EXCLUSIVE);
158         sysctl_unregister_oid_int(oidp);
159         sysctl_unlock();
160 }
161
162 static void
163 sysctl_unregister_oid_int(struct sysctl_oid *oidp)
164 {
165         struct sysctl_oid *p;
166
167         if (oidp->oid_number == OID_AUTO)
168                 panic("Trying to unregister OID_AUTO entry: %p", oidp);
169
170         SLIST_FOREACH(p, oidp->oid_parent, oid_link) {
171                 if (p != oidp)
172                         continue;
173                 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
174                 return;
175         }
176
177         /*
178          * This can happen when a module fails to register and is
179          * being unloaded afterwards.  It should not be a panic()
180          * for normal use.
181          */
182         kprintf("%s: failed to unregister sysctl\n", __func__);
183 }
184
185 /* Initialize a new context to keep track of dynamically added sysctls. */
186 int
187 sysctl_ctx_init(struct sysctl_ctx_list *c)
188 {
189         if (c == NULL)
190                 return(EINVAL);
191         TAILQ_INIT(c);
192         return(0);
193 }
194
195 /* Free the context, and destroy all dynamic oids registered in this context */
196 int
197 sysctl_ctx_free(struct sysctl_ctx_list *clist)
198 {
199         struct sysctl_ctx_entry *e, *e1;
200         int error;
201
202         error = 0;
203         sysctl_ctx_lock(LK_EXCLUSIVE);
204         /*
205          * First perform a "dry run" to check if it's ok to remove oids.
206          * XXX FIXME
207          * XXX This algorithm is a hack. But I don't know any
208          * XXX better solution for now...
209          */
210         TAILQ_FOREACH(e, clist, link) {
211                 error = sysctl_remove_oid(e->entry, 0, 0);
212                 if (error)
213                         break;
214         }
215         /*
216          * Restore deregistered entries, either from the end,
217          * or from the place where error occured.
218          * e contains the entry that was not unregistered
219          */
220         if (error)
221                 e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
222         else
223                 e1 = TAILQ_LAST(clist, sysctl_ctx_list);
224         while (e1 != NULL) {
225                 sysctl_register_oid(e1->entry);
226                 e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
227         }
228         if (error) {
229                 sysctl_ctx_unlock();
230                 return(EBUSY);
231         }
232         /* Now really delete the entries */
233         e = TAILQ_FIRST(clist);
234         while (e != NULL) {
235                 e1 = TAILQ_NEXT(e, link);
236                 error = sysctl_remove_oid(e->entry, 1, 0);
237                 if (error)
238                         panic("sysctl_remove_oid: corrupt tree, entry: %s",
239                             e->entry->oid_name);
240                 kfree(e, M_SYSCTLOID);
241                 e = e1;
242         }
243         sysctl_ctx_unlock();
244         return (error);
245 }
246
247 /* Add an entry to the context */
248 struct sysctl_ctx_entry *
249 sysctl_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 = kmalloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
256         e->entry = oidp;
257         sysctl_ctx_lock(LK_EXCLUSIVE);
258         TAILQ_INSERT_HEAD(clist, e, link);
259         sysctl_ctx_unlock();
260         return (e);
261 }
262
263 /* Find an entry in the context */
264 struct sysctl_ctx_entry *
265 sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
266 {
267         struct sysctl_ctx_entry *e;
268
269         if (clist == NULL || oidp == NULL)
270                 return(NULL);
271
272         sysctl_ctx_lock(LK_SHARED);
273         e = sysctl_ctx_entry_find_int(clist, oidp);
274         sysctl_ctx_unlock();
275
276         return(e);
277 }
278
279 struct sysctl_ctx_entry *
280 sysctl_ctx_entry_find_int(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
281 {
282         struct sysctl_ctx_entry *e;
283
284         KKASSERT(clist != NULL && oidp != NULL);
285
286         for (e = TAILQ_FIRST(clist); e != NULL; e = TAILQ_NEXT(e, link)) {
287                 if(e->entry == oidp)
288                         break;
289         }
290
291         return (e);
292 }
293
294 /*
295  * Delete an entry from the context.
296  * NOTE: this function doesn't free oidp! You have to remove it
297  * with sysctl_remove_oid().
298  */
299 int
300 sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
301 {
302         struct sysctl_ctx_entry *e;
303
304         if (clist == NULL || oidp == NULL)
305                 return (EINVAL);
306
307         sysctl_ctx_lock(LK_EXCLUSIVE);
308         e = sysctl_ctx_entry_find_int(clist, oidp);
309         if (e == NULL) {
310                 sysctl_ctx_unlock();
311                 return (ENOENT);
312         }
313         TAILQ_REMOVE(clist, e, link);
314         kfree(e, M_SYSCTLOID);
315         sysctl_ctx_unlock();
316
317         return(0);
318 }
319
320 /*
321  * Remove dynamically created sysctl trees.
322  * oidp - top of the tree to be removed
323  * del - if 0 - just deregister, otherwise free up entries as well
324  * recurse - if != 0 traverse the subtree to be deleted
325  */
326 int
327 sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
328 {
329         struct sysctl_oid *p;
330         int error;
331
332         if (oidp == NULL)
333                 return(EINVAL);
334         if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
335                 kprintf("can't remove non-dynamic nodes!\n");
336                 return (EINVAL);
337         }
338         sysctl_lock(LK_EXCLUSIVE | LK_CANRECURSE);
339         /*
340          * WARNING: normal method to do this should be through
341          * sysctl_ctx_free(). Use recursing as the last resort
342          * method to purge your sysctl tree of leftovers...
343          * However, if some other code still references these nodes,
344          * it will panic.
345          */
346         if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
347                 if (oidp->oid_refcnt == 1) {
348                         SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
349                                 if (!recurse) {
350                                         sysctl_unlock();
351                                         return(ENOTEMPTY);
352                                 }
353                                 error = sysctl_remove_oid(p, del, recurse);
354                                 if (error) {
355                                         sysctl_unlock();
356                                         return(error);
357                                 }
358                         }
359                         if (del)
360                                 kfree(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
361                 }
362         }
363         if (oidp->oid_refcnt > 1 ) {
364                 oidp->oid_refcnt--;
365         } else {
366                 if (oidp->oid_refcnt == 0) {
367                         kprintf("Warning: bad oid_refcnt=%u (%s)!\n",
368                                oidp->oid_refcnt, oidp->oid_name);
369                         sysctl_unlock();
370                         return(EINVAL);
371                 }
372                 sysctl_unregister_oid_int(oidp);
373                 if (del) {
374                         if (oidp->oid_descr)
375                                 kfree(__DECONST(char *,oidp->oid_descr),
376                                      M_SYSCTLOID);
377                         kfree(__DECONST(char *, oidp->oid_name), M_SYSCTLOID);
378                         kfree(oidp, M_SYSCTLOID);
379                 }
380         }
381         sysctl_unlock();
382         return(0);
383 }
384
385 /*
386  * Create new sysctls at run time.
387  * clist may point to a valid context initialized with sysctl_ctx_init().
388  */
389 struct sysctl_oid *
390 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
391         int number, const char *name, int kind, void *arg1, int arg2,
392         int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
393 {
394         struct sysctl_oid *oidp;
395         ssize_t len;
396         char *newname;
397
398         /* You have to hook up somewhere.. */
399         if (parent == NULL)
400                 return(NULL);
401         sysctl_lock(LK_EXCLUSIVE);
402         /* Check if the node already exists, otherwise create it */
403         oidp = sysctl_find_oidname(name, parent, 0);
404         if (oidp != NULL) {
405                 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
406                         oidp->oid_refcnt++;
407                         /* Update the context */
408                         if (clist != NULL)
409                                 sysctl_ctx_entry_add(clist, oidp);
410                         sysctl_unlock();
411                         return (oidp);
412                 } else {
413                         kprintf("can't re-use a leaf (%s)!\n", name);
414                         sysctl_unlock();
415                         return (NULL);
416                 }
417         }
418         oidp = kmalloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK | M_ZERO);
419         oidp->oid_parent = parent;
420         SLIST_NEXT(oidp, oid_link) = NULL;
421         oidp->oid_number = number;
422         oidp->oid_refcnt = 1;
423         len = strlen(name);
424         newname = kmalloc(len + 1, M_SYSCTLOID, M_WAITOK);
425         bcopy(name, newname, len + 1);
426         newname[len] = '\0';
427         oidp->oid_name = newname;
428         oidp->oid_handler = handler;
429         oidp->oid_kind = CTLFLAG_DYN | kind;
430         if ((kind & CTLTYPE) == CTLTYPE_NODE) {
431                 struct sysctl_oid_list *children;
432
433                 /* Allocate space for children */
434                 children = kmalloc(sizeof(*children), M_SYSCTLOID, M_WAITOK);
435                 SYSCTL_SET_CHILDREN(oidp, children);
436                 SLIST_INIT(children);
437         } else {
438                 oidp->oid_arg1 = arg1;
439                 oidp->oid_arg2 = arg2;
440         }
441         oidp->oid_fmt = fmt;
442         if (descr) {
443                 int len = strlen(descr) + 1;
444                 oidp->oid_descr = kmalloc(len, M_SYSCTLOID, M_WAITOK);
445                 strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
446         };
447         /* Update the context, if used */
448         if (clist != NULL)
449                 sysctl_ctx_entry_add(clist, oidp);
450         /* Register this oid */
451         sysctl_register_oid_int(oidp);
452         sysctl_unlock();
453         return (oidp);
454 }
455
456 /*
457  * Register the kernel's oids on startup.
458  */
459 SET_DECLARE(sysctl_set, struct sysctl_oid);
460
461 static void
462 sysctl_register_all(void *arg)
463 {
464         struct sysctl_oid **oidp;
465
466         lockinit(&sysctl_lkp, "sysctl", 0, 0);
467         lockinit(&sysctl_ctx_lkp, "sysctl ctx", 0, 0);
468         SET_FOREACH(oidp, sysctl_set)
469                 sysctl_register_oid_int(*oidp);
470 }
471
472 SYSINIT(sysctl, SI_BOOT1_POST, SI_ORDER_ANY, sysctl_register_all, 0);
473
474 /*
475  * "Staff-functions"
476  *
477  * These functions implement a presently undocumented interface 
478  * used by the sysctl program to walk the tree, and get the type
479  * so it can print the value.
480  * This interface is under work and consideration, and should probably
481  * be killed with a big axe by the first person who can find the time.
482  * (be aware though, that the proper interface isn't as obvious as it
483  * may seem, there are various conflicting requirements.
484  *
485  * {0,0}        kprintf the entire MIB-tree.
486  * {0,1,...}    return the name of the "..." OID.
487  * {0,2,...}    return the next OID.
488  * {0,3}        return the OID of the name in "new"
489  * {0,4,...}    return the kind & format info for the "..." OID.
490  */
491
492 static void
493 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
494 {
495         int k;
496         struct sysctl_oid *oidp;
497
498         sysctl_lock(LK_SHARED);
499         SLIST_FOREACH(oidp, l, oid_link) {
500
501                 for (k=0; k<i; k++)
502                         kprintf(" ");
503
504                 kprintf("%d %s ", oidp->oid_number, oidp->oid_name);
505
506                 kprintf("%c%c",
507                         oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
508                         oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
509
510                 if (oidp->oid_handler)
511                         kprintf(" *Handler");
512
513                 switch (oidp->oid_kind & CTLTYPE) {
514                         case CTLTYPE_NODE:
515                                 kprintf(" Node\n");
516                                 if (!oidp->oid_handler) {
517                                         sysctl_sysctl_debug_dump_node(
518                                                 oidp->oid_arg1, i+2);
519                                 }
520                                 break;
521                         case CTLTYPE_INT:    kprintf(" Int\n"); break;
522                         case CTLTYPE_STRING: kprintf(" String\n"); break;
523                         case CTLTYPE_QUAD:   kprintf(" Quad\n"); break;
524                         case CTLTYPE_OPAQUE: kprintf(" Opaque/struct\n"); break;
525                         default:             kprintf("\n");
526                 }
527
528         }
529         sysctl_unlock();
530 }
531
532 static int
533 sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
534 {
535         int error;
536
537         error = priv_check(req->td, PRIV_SYSCTL_DEBUG);
538         if (error)
539                 return error;
540         sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
541         return ENOENT;
542 }
543
544 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
545         0, 0, sysctl_sysctl_debug, "-", "");
546
547 static int
548 sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
549 {
550         int *name = (int *) arg1;
551         u_int namelen = arg2;
552         int error = 0;
553         struct sysctl_oid *oid;
554         struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
555         char buf[16];
556
557         sysctl_lock(LK_SHARED);
558         while (namelen) {
559                 if (!lsp) {
560                         ksnprintf(buf, sizeof(buf), "%d", *name);
561                         if (req->oldidx)
562                                 error = SYSCTL_OUT(req, ".", 1);
563                         if (!error)
564                                 error = SYSCTL_OUT(req, buf, strlen(buf));
565                         if (error) {
566                                 sysctl_unlock();
567                                 return (error);
568                         }
569                         namelen--;
570                         name++;
571                         continue;
572                 }
573                 lsp2 = NULL;
574                 SLIST_FOREACH(oid, lsp, oid_link) {
575                         if (oid->oid_number != *name)
576                                 continue;
577
578                         if (req->oldidx)
579                                 error = SYSCTL_OUT(req, ".", 1);
580                         if (!error)
581                                 error = SYSCTL_OUT(req, oid->oid_name,
582                                         strlen(oid->oid_name));
583                         if (error) {
584                                 sysctl_unlock();
585                                 return (error);
586                         }
587
588                         namelen--;
589                         name++;
590
591                         if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 
592                                 break;
593
594                         if (oid->oid_handler)
595                                 break;
596
597                         lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
598                         break;
599                 }
600                 lsp = lsp2;
601         }
602         sysctl_unlock();
603         return (SYSCTL_OUT(req, "", 1));
604 }
605
606 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
607
608 static int
609 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, 
610         int *next, int *len, int level, struct sysctl_oid **oidpp)
611 {
612         struct sysctl_oid *oidp;
613
614         *len = level;
615         sysctl_lock(LK_SHARED);
616         SLIST_FOREACH(oidp, lsp, oid_link) {
617                 *next = oidp->oid_number;
618                 *oidpp = oidp;
619
620                 if (!namelen) {
621                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
622                                 sysctl_unlock();
623                                 return 0;
624                         }
625                         if (oidp->oid_handler) {
626                                 /* We really should call the handler here...*/
627                                 sysctl_unlock();
628                                 return 0;
629                         }
630                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
631                         if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, 
632                                 len, level+1, oidpp)) {
633                                 sysctl_unlock();
634                                 return 0;
635                         }
636                         goto emptynode;
637                 }
638
639                 if (oidp->oid_number < *name)
640                         continue;
641
642                 if (oidp->oid_number > *name) {
643                         if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
644                                 sysctl_unlock();
645                                 return 0;
646                         }
647                         if (oidp->oid_handler) {
648                                 sysctl_unlock();
649                                 return 0;
650                         }
651                         lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
652                         if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, 
653                                 next+1, len, level+1, oidpp)) {
654                                 sysctl_unlock();
655                                 return (0);
656                         }
657                         goto next;
658                 }
659                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
660                         continue;
661
662                 if (oidp->oid_handler)
663                         continue;
664
665                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
666                 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, 
667                         len, level+1, oidpp)) {
668                         sysctl_unlock();
669                         return (0);
670                 }
671         next:
672                 namelen = 1;
673                 *len = level;
674         emptynode:
675                 *len = level;
676         }
677         sysctl_unlock();
678         return 1;
679 }
680
681 static int
682 sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
683 {
684         int *name = (int *) arg1;
685         u_int namelen = arg2;
686         int i, j, error;
687         struct sysctl_oid *oid;
688         struct sysctl_oid_list *lsp = &sysctl__children;
689         int newoid[CTL_MAXNAME];
690
691         i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
692         if (i)
693                 return ENOENT;
694         error = SYSCTL_OUT(req, newoid, j * sizeof (int));
695         return (error);
696 }
697
698 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
699
700 static int
701 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
702 {
703         int i;
704         struct sysctl_oid *oidp;
705         struct sysctl_oid_list *lsp = &sysctl__children;
706         char *p;
707
708         if (!*name)
709                 return ENOENT;
710
711         p = name + strlen(name) - 1 ;
712         if (*p == '.')
713                 *p = '\0';
714
715         *len = 0;
716
717         for (p = name; *p && *p != '.'; p++) 
718                 ;
719         i = *p;
720         if (i == '.')
721                 *p = '\0';
722
723         sysctl_lock(LK_SHARED);
724         oidp = SLIST_FIRST(lsp);
725
726         while (oidp && *len < CTL_MAXNAME) {
727                 if (strcmp(name, oidp->oid_name)) {
728                         oidp = SLIST_NEXT(oidp, oid_link);
729                         continue;
730                 }
731                 *oid++ = oidp->oid_number;
732                 (*len)++;
733
734                 if (!i) {
735                         if (oidpp)
736                                 *oidpp = oidp;
737                         sysctl_unlock();
738                         return (0);
739                 }
740
741                 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
742                         break;
743
744                 if (oidp->oid_handler)
745                         break;
746
747                 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
748                 oidp = SLIST_FIRST(lsp);
749                 name = p+1;
750                 for (p = name; *p && *p != '.'; p++) 
751                                 ;
752                 i = *p;
753                 if (i == '.')
754                         *p = '\0';
755         }
756         sysctl_unlock();
757         return ENOENT;
758 }
759
760 static int
761 sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
762 {
763         char *p;
764         int error, oid[CTL_MAXNAME], len;
765         struct sysctl_oid *op = NULL;
766
767         if (!req->newlen) 
768                 return ENOENT;
769         if (req->newlen >= MAXPATHLEN)  /* XXX arbitrary, undocumented */
770                 return (ENAMETOOLONG);
771
772         p = kmalloc(req->newlen+1, M_SYSCTL, M_WAITOK);
773
774         error = SYSCTL_IN(req, p, req->newlen);
775         if (error) {
776                 kfree(p, M_SYSCTL);
777                 return (error);
778         }
779
780         p [req->newlen] = '\0';
781
782         error = name2oid(p, oid, &len, &op);
783
784         kfree(p, M_SYSCTL);
785
786         if (error)
787                 return (error);
788
789         error = SYSCTL_OUT(req, oid, len * sizeof *oid);
790         return (error);
791 }
792
793 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 
794         sysctl_sysctl_name2oid, "I", "");
795
796 static int
797 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
798 {
799         struct sysctl_oid *oid;
800         int error;
801
802         error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
803         if (error)
804                 return (error);
805
806         if (!oid->oid_fmt)
807                 return (ENOENT);
808         error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
809         if (error)
810                 return (error);
811         error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
812         return (error);
813 }
814
815
816 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
817
818 static int
819 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
820 {
821         struct sysctl_oid *oid;
822         int error;
823
824         error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
825         if (error)
826                 return (error);
827         
828         if (!oid->oid_descr)
829                 return (ENOENT);
830         error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
831         return (error);
832 }
833
834 SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
835
836 /*
837  * Default "handler" functions.
838  */
839
840 /*
841  * Handle an int, signed or unsigned.
842  * Two cases:
843  *     a variable:  point arg1 at it.
844  *     a constant:  pass it in arg2.
845  */
846
847 int
848 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
849 {
850         int error = 0;
851
852         if (arg1)
853                 error = SYSCTL_OUT(req, arg1, sizeof(int));
854         else
855                 error = SYSCTL_OUT(req, &arg2, sizeof(int));
856
857         if (error || !req->newptr)
858                 return (error);
859
860         if (!arg1)
861                 error = EPERM;
862         else
863                 error = SYSCTL_IN(req, arg1, sizeof(int));
864         return (error);
865 }
866
867 /*
868  * Handle a long, signed or unsigned.  arg1 points to it.
869  */
870
871 int
872 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
873 {
874         int error = 0;
875
876         if (!arg1)
877                 return (EINVAL);
878         error = SYSCTL_OUT(req, arg1, sizeof(long));
879
880         if (error || !req->newptr)
881                 return (error);
882
883         error = SYSCTL_IN(req, arg1, sizeof(long));
884         return (error);
885 }
886
887 /*
888  * Handle a quad, signed or unsigned.  arg1 points to it.
889  */
890
891 int
892 sysctl_handle_quad(SYSCTL_HANDLER_ARGS)
893 {
894         int error = 0;
895
896         if (!arg1)
897                 return (EINVAL);
898         error = SYSCTL_OUT(req, arg1, sizeof(quad_t));
899
900         if (error || !req->newptr)
901                 return (error);
902
903         error = SYSCTL_IN(req, arg1, sizeof(quad_t));
904         return (error);
905 }
906
907 /*
908  * Handle our generic '\0' terminated 'C' string.
909  * Two cases:
910  *      a variable string:  point arg1 at it, arg2 is max length.
911  *      a constant string:  point arg1 at it, arg2 is zero.
912  */
913
914 int
915 sysctl_handle_string(SYSCTL_HANDLER_ARGS)
916 {
917         int error=0;
918
919         error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
920
921         if (error || !req->newptr)
922                 return (error);
923
924         if ((req->newlen - req->newidx) >= arg2) {
925                 error = EINVAL;
926         } else {
927                 arg2 = (req->newlen - req->newidx);
928                 error = SYSCTL_IN(req, arg1, arg2);
929                 ((char *)arg1)[arg2] = '\0';
930         }
931
932         return (error);
933 }
934
935 /*
936  * Handle any kind of opaque data.
937  * arg1 points to it, arg2 is the size.
938  */
939
940 int
941 sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
942 {
943         int error;
944
945         error = SYSCTL_OUT(req, arg1, arg2);
946
947         if (error || !req->newptr)
948                 return (error);
949
950         error = SYSCTL_IN(req, arg1, arg2);
951
952         return (error);
953 }
954
955 /*
956  * Transfer functions to/from kernel space.
957  * XXX: rather untested at this point
958  */
959 static int
960 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
961 {
962         size_t i = 0;
963
964         if (req->oldptr) {
965                 i = l;
966                 if (i > req->oldlen - req->oldidx)
967                         i = req->oldlen - req->oldidx;
968                 if (i > 0)
969                         bcopy(p, (char *)req->oldptr + req->oldidx, i);
970         }
971         req->oldidx += l;
972         if (req->oldptr && i != l)
973                 return (ENOMEM);
974         return (0);
975 }
976
977 static int
978 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
979 {
980
981         if (!req->newptr)
982                 return 0;
983         if (req->newlen - req->newidx < l)
984                 return (EINVAL);
985         bcopy((char *)req->newptr + req->newidx, p, l);
986         req->newidx += l;
987         return (0);
988 }
989
990 int
991 kernel_sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
992 {
993         int error = 0;
994         struct sysctl_req req;
995
996         bzero(&req, sizeof req);
997
998         req.td = curthread;
999
1000         if (oldlenp) {
1001                 req.oldlen = *oldlenp;
1002         }
1003
1004         if (old) {
1005                 req.oldptr = old;
1006         }
1007
1008         if (new != NULL) {
1009                 req.newlen = newlen;
1010                 req.newptr = new;
1011         }
1012
1013         req.oldfunc = sysctl_old_kernel;
1014         req.newfunc = sysctl_new_kernel;
1015 #if 0
1016         req.lock = 1;
1017 #endif
1018
1019         sysctl_lock(LK_SHARED);
1020
1021         error = sysctl_root(0, name, namelen, &req);
1022
1023 #if 0
1024         if (req.lock == 2)
1025                 vsunlock(req.oldptr, req.oldlen);
1026 #endif
1027
1028         sysctl_unlock();
1029
1030         if (error && error != ENOMEM)
1031                 return (error);
1032
1033         if (retval) {
1034                 if (req.oldptr && req.oldidx > req.oldlen)
1035                         *retval = req.oldlen;
1036                 else
1037                         *retval = req.oldidx;
1038         }
1039         return (error);
1040 }
1041
1042 int
1043 kernel_sysctlbyname(char *name, void *old, size_t *oldlenp,
1044     void *new, size_t newlen, size_t *retval)
1045 {
1046         int oid[CTL_MAXNAME];
1047         size_t oidlen, plen;
1048         int error;
1049
1050         oid[0] = 0;             /* sysctl internal magic */
1051         oid[1] = 3;             /* name2oid */
1052         oidlen = sizeof(oid);
1053
1054         error = kernel_sysctl(oid, 2, oid, &oidlen, name, strlen(name), &plen);
1055         if (error)
1056                 return (error);
1057
1058         error = kernel_sysctl(oid, plen / sizeof(int), old, oldlenp,
1059             new, newlen, retval);
1060         return (error);
1061 }
1062
1063 /*
1064  * Transfer function to/from user space.
1065  */
1066 static int
1067 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1068 {
1069         int error = 0;
1070         size_t i = 0;
1071
1072 #if 0
1073         if (req->lock == 1 && req->oldptr) {
1074                 vslock(req->oldptr, req->oldlen);
1075                 req->lock = 2;
1076         }
1077 #endif
1078         if (req->oldptr) {
1079                 i = l;
1080                 if (i > req->oldlen - req->oldidx)
1081                         i = req->oldlen - req->oldidx;
1082                 if (i > 0)
1083                         error = copyout(p, (char *)req->oldptr + req->oldidx,
1084                                         i);
1085         }
1086         req->oldidx += l;
1087         if (error)
1088                 return (error);
1089         if (req->oldptr && i < l)
1090                 return (ENOMEM);
1091         return (0);
1092 }
1093
1094 static int
1095 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1096 {
1097         int error;
1098
1099         if (!req->newptr)
1100                 return 0;
1101         if (req->newlen - req->newidx < l)
1102                 return (EINVAL);
1103         error = copyin((char *)req->newptr + req->newidx, p, l);
1104         req->newidx += l;
1105         return (error);
1106 }
1107
1108 int
1109 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1110     int *nindx, struct sysctl_req *req)
1111 {
1112         struct sysctl_oid *oid;
1113         int indx;
1114
1115         sysctl_lock(LK_SHARED);
1116         oid = SLIST_FIRST(&sysctl__children);
1117         indx = 0;
1118         while (oid && indx < CTL_MAXNAME) {
1119                 if (oid->oid_number == name[indx]) {
1120                         indx++;
1121                         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1122                                 if (oid->oid_handler != NULL ||
1123                                     indx == namelen) {
1124                                         *noid = oid;
1125                                         if (nindx != NULL)
1126                                                 *nindx = indx;
1127                                         sysctl_unlock();
1128                                         return (0);
1129                                 }
1130                                 oid = SLIST_FIRST(
1131                                     (struct sysctl_oid_list *)oid->oid_arg1);
1132                         } else if (indx == namelen) {
1133                                 *noid = oid;
1134                                 if (nindx != NULL)
1135                                         *nindx = indx;
1136                                 sysctl_unlock();
1137                                 return (0);
1138                         } else {
1139                                 sysctl_unlock();
1140                                 return (ENOTDIR);
1141                         }
1142                 } else {
1143                         oid = SLIST_NEXT(oid, oid_link);
1144                 }
1145         }
1146         sysctl_unlock();
1147         return (ENOENT);
1148 }
1149
1150 /*
1151  * Traverse our tree, and find the right node, execute whatever it points
1152  * to, and return the resulting error code.
1153  */
1154
1155 int
1156 sysctl_root(SYSCTL_HANDLER_ARGS)
1157 {
1158         struct thread *td = req->td;
1159         struct proc *p = td ? td->td_proc : NULL;
1160         struct sysctl_oid *oid;
1161         int error, indx;
1162
1163         error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1164         if (error)
1165                 return (error);
1166
1167         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1168                 /*
1169                  * You can't call a sysctl when it's a node, but has
1170                  * no handler.  Inform the user that it's a node.
1171                  * The indx may or may not be the same as namelen.
1172                  */
1173                 if (oid->oid_handler == NULL)
1174                         return (EISDIR);
1175         }
1176
1177         /* If writing isn't allowed */
1178         if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
1179             ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
1180                 return (EPERM);
1181
1182         /* Most likely only root can write */
1183         if (!(oid->oid_kind & CTLFLAG_ANYBODY) && req->newptr && p &&
1184             (error = priv_check_cred(td->td_ucred,
1185              (oid->oid_kind & CTLFLAG_PRISON) ? PRIV_SYSCTL_WRITEJAIL :
1186                                                 PRIV_SYSCTL_WRITE, 0)))
1187                 return (error);
1188
1189         if (!oid->oid_handler)
1190                 return EINVAL;
1191
1192         if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
1193                 error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
1194                     req);
1195         else
1196                 error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
1197                     req);
1198         return (error);
1199 }
1200
1201 /*
1202  * MPALMOSTSAFE
1203  */
1204 int
1205 sys___sysctl(struct sysctl_args *uap)
1206 {
1207         int error, i, name[CTL_MAXNAME];
1208         size_t j;
1209
1210         if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1211                 return (EINVAL);
1212
1213         error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1214         if (error)
1215                 return (error);
1216
1217         error = userland_sysctl(name, uap->namelen,
1218                 uap->old, uap->oldlenp, 0,
1219                 uap->new, uap->newlen, &j);
1220         if (error && error != ENOMEM)
1221                 return (error);
1222         if (uap->oldlenp) {
1223                 i = copyout(&j, uap->oldlenp, sizeof(j));
1224                 if (i)
1225                         return (i);
1226         }
1227         return (error);
1228 }
1229
1230 /*
1231  * This is used from various compatibility syscalls too.  That's why name
1232  * must be in kernel space.
1233  */
1234 int
1235 userland_sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1236 {
1237         int error = 0;
1238         struct sysctl_req req, req2;
1239
1240         bzero(&req, sizeof req);
1241
1242         if (oldlenp) {
1243                 if (inkernel) {
1244                         req.oldlen = *oldlenp;
1245                 } else {
1246                         error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1247                         if (error)
1248                                 return (error);
1249                 }
1250         }
1251
1252         if (old) {
1253                 if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1254                         return (EFAULT);
1255                 req.oldptr= old;
1256         }
1257
1258         if (new != NULL) {
1259                 if (!useracc(new, newlen, VM_PROT_READ))
1260                         return (EFAULT);
1261                 req.newlen = newlen;
1262                 req.newptr = new;
1263         }
1264
1265         req.oldfunc = sysctl_old_user;
1266         req.newfunc = sysctl_new_user;
1267 #if 0
1268         req.lock = 1;
1269 #endif
1270         req.td = curthread;
1271
1272         sysctl_lock(LK_SHARED);
1273
1274         do {
1275             req2 = req;
1276             error = sysctl_root(0, name, namelen, &req2);
1277         } while (error == EAGAIN);
1278
1279         req = req2;
1280 #if 0
1281         if (req.lock == 2)
1282                 vsunlock(req.oldptr, req.oldlen);
1283 #endif
1284
1285         sysctl_unlock();
1286
1287         if (error && error != ENOMEM)
1288                 return (error);
1289
1290         if (retval) {
1291                 if (req.oldptr && req.oldidx > req.oldlen)
1292                         *retval = req.oldlen;
1293                 else
1294                         *retval = req.oldidx;
1295         }
1296         return (error);
1297 }
1298
1299 static void
1300 sysctl_lock(int flag)
1301 {
1302         lockmgr(&sysctl_lkp, flag);
1303 }
1304
1305 static void
1306 sysctl_unlock(void)
1307 {
1308         lockmgr(&sysctl_lkp, LK_RELEASE);
1309 }
1310
1311 static void
1312 sysctl_ctx_lock(int flag)
1313 {
1314         lockmgr(&sysctl_ctx_lkp, flag);
1315 }
1316
1317 static void
1318 sysctl_ctx_unlock(void)
1319 {
1320         lockmgr(&sysctl_ctx_lkp, LK_RELEASE);
1321 }
1322
1323 int
1324 sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
1325 {
1326         int error, value;
1327
1328         value = *(int *)arg1;
1329         error = sysctl_handle_int(oidp, &value, 0, req);
1330         if (error || !req->newptr)
1331                 return (error);
1332         if (value < low || value > high)
1333                 return (EINVAL);
1334         *(int *)arg1 = value;
1335         return (0);
1336 }