kern_sysctl.c (77978ab8bc1968d7606144ddc20b2a8a9f9b3382) kern_sysctl.c (bd3cdc3105aaed624b5933269218e0a448781b61)
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

--- 39 unchanged lines hidden (view full) ---

48#include <sys/sysctl.h>
49#include <sys/malloc.h>
50#include <sys/proc.h>
51#include <sys/sysproto.h>
52#include <vm/vm.h>
53#include <vm/vm_extern.h>
54
55static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
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

--- 39 unchanged lines hidden (view full) ---

48#include <sys/sysctl.h>
49#include <sys/malloc.h>
50#include <sys/proc.h>
51#include <sys/sysproto.h>
52#include <vm/vm.h>
53#include <vm/vm_extern.h>
54
55static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
56static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
56
57/*
58 * Locking and stats
59 */
60static struct sysctl_lock {
61 int sl_lock;
62 int sl_want;
63 int sl_locked;
64} memlock;
65
66static int sysctl_root(SYSCTL_HANDLER_ARGS);
67
68struct sysctl_oid_list sysctl__children; /* root list */
69
57
58/*
59 * Locking and stats
60 */
61static struct sysctl_lock {
62 int sl_lock;
63 int sl_want;
64 int sl_locked;
65} memlock;
66
67static int sysctl_root(SYSCTL_HANDLER_ARGS);
68
69struct sysctl_oid_list sysctl__children; /* root list */
70
71static struct sysctl_oid *
72sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
73{
74 struct sysctl_oid *oidp;
75
76 SLIST_FOREACH(oidp, list, oid_link) {
77 if (strcmp(oidp->oid_name, name) == 0) {
78 return (oidp);
79 }
80 }
81 return (NULL);
82}
83
70/*
71 * Initialization of the MIB tree.
72 *
73 * Order by number in each list.
74 */
75
76void sysctl_register_oid(struct sysctl_oid *oidp)
77{
78 struct sysctl_oid_list *parent = oidp->oid_parent;
79 struct sysctl_oid *p;
80 struct sysctl_oid *q;
81 int n;
82
83 /*
84/*
85 * Initialization of the MIB tree.
86 *
87 * Order by number in each list.
88 */
89
90void sysctl_register_oid(struct sysctl_oid *oidp)
91{
92 struct sysctl_oid_list *parent = oidp->oid_parent;
93 struct sysctl_oid *p;
94 struct sysctl_oid *q;
95 int n;
96
97 /*
98 * First check if another oid with the same name already
99 * exists in the parent's list.
100 */
101 p = sysctl_find_oidname(oidp->oid_name, parent);
102 if (p != NULL) {
103 if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
104 p->oid_refcnt++;
105 return;
106 } else {
107 printf("can't re-use a leaf (%s)!\n", p->oid_name);
108 return;
109 }
110 }
111 /*
84 * If this oid has a number OID_AUTO, give it a number which
85 * is greater than any current oid. Make sure it is at least
86 * 100 to leave space for pre-assigned oid numbers.
87 */
88 if (oidp->oid_number == OID_AUTO) {
89 /* First, find the highest oid in the parent list >99 */
90 n = 99;
91 SLIST_FOREACH(p, parent, oid_link) {

--- 18 unchanged lines hidden (view full) ---

110 SLIST_INSERT_HEAD(parent, oidp, oid_link);
111}
112
113void sysctl_unregister_oid(struct sysctl_oid *oidp)
114{
115 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
116}
117
112 * If this oid has a number OID_AUTO, give it a number which
113 * is greater than any current oid. Make sure it is at least
114 * 100 to leave space for pre-assigned oid numbers.
115 */
116 if (oidp->oid_number == OID_AUTO) {
117 /* First, find the highest oid in the parent list >99 */
118 n = 99;
119 SLIST_FOREACH(p, parent, oid_link) {

--- 18 unchanged lines hidden (view full) ---

138 SLIST_INSERT_HEAD(parent, oidp, oid_link);
139}
140
141void sysctl_unregister_oid(struct sysctl_oid *oidp)
142{
143 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
144}
145
146/* Initialize a new context to keep track of dynamically added sysctls. */
147int
148sysctl_ctx_init(struct sysctl_ctx_list *c)
149{
150
151 if (c == NULL) {
152 return (EINVAL);
153 }
154 TAILQ_INIT(c);
155 return (0);
156}
157
158/* Free the context, and destroy all dynamic oids registered in this context */
159int
160sysctl_ctx_free(struct sysctl_ctx_list *clist)
161{
162 struct sysctl_ctx_entry *e, *e1;
163 int error;
164
165 error = 0;
166 /*
167 * First perform a "dry run" to check if it's ok to remove oids.
168 * XXX FIXME
169 * XXX This algorithm is a hack. But I don't know any
170 * XXX better solution for now...
171 */
172 TAILQ_FOREACH(e, clist, link) {
173 error = sysctl_remove_oid(e->entry, 0, 0);
174 if (error)
175 break;
176 }
177 /*
178 * Restore deregistered entries, either from the end,
179 * or from the place where error occured.
180 * e contains the entry that was not unregistered
181 */
182 if (error)
183 e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
184 else
185 e1 = TAILQ_LAST(clist, sysctl_ctx_list);
186 while (e1 != NULL) {
187 sysctl_register_oid(e1->entry);
188 e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
189 }
190 if (error)
191 return(EBUSY);
192 /* Now really delete the entries */
193 e = TAILQ_FIRST(clist);
194 while (e != NULL) {
195 e1 = TAILQ_NEXT(e, link);
196 error = sysctl_remove_oid(e->entry, 1, 0);
197 if (error)
198 panic("sysctl_remove_oid: corrupt tree, entry: %s",
199 e->entry->oid_name);
200 free(e, M_SYSCTLOID);
201 e = e1;
202 }
203 return (error);
204}
205
206/* Add an entry to the context */
207struct sysctl_ctx_entry *
208sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
209{
210 struct sysctl_ctx_entry *e;
211
212 if (clist == NULL || oidp == NULL)
213 return(NULL);
214 e = malloc (sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
215 e->entry = oidp;
216 TAILQ_INSERT_HEAD(clist, e, link);
217 return (e);
218}
219
220/* Find an entry in the context */
221struct sysctl_ctx_entry *
222sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
223{
224 struct sysctl_ctx_entry *e;
225
226 if (clist == NULL || oidp == NULL)
227 return(NULL);
228 for (e = TAILQ_FIRST(clist); e != NULL; e = TAILQ_NEXT(e, link)) {
229 if(e->entry == oidp)
230 return(e);
231 }
232 return (e);
233}
234
118/*
235/*
236 * Delete an entry from the context.
237 * NOTE: this function doesn't free oidp! You have to remove it
238 * with sysctl_remove_oid().
239 */
240int
241sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
242{
243 struct sysctl_ctx_entry *e;
244
245 if (clist == NULL || oidp == NULL)
246 return (EINVAL);
247 e = sysctl_ctx_entry_find(clist, oidp);
248 if (e != NULL) {
249 TAILQ_REMOVE(clist, e, link);
250 free(e, M_SYSCTLOID);
251 return (0);
252 } else
253 return (ENOENT);
254}
255
256/*
257 * Remove dynamically created sysctl trees.
258 * oidp - top of the tree to be removed
259 * del - if 0 - just deregister, otherwise free up entries as well
260 * recurse - if != 0 traverse the subtree to be deleted
261 */
262int
263sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
264{
265 struct sysctl_oid *p;
266 int error;
267
268 if (oidp == NULL)
269 return(EINVAL);
270 if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
271 printf("can't remove non-dynamic nodes!\n");
272 return (EINVAL);
273 }
274 /*
275 * WARNING: normal method to do this should be through
276 * sysctl_ctx_free(). Use recursing as the last resort
277 * method to purge your sysctl tree of leftovers...
278 * However, if some other code still references these nodes,
279 * it will panic.
280 */
281 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
282 if (oidp->oid_refcnt == 1) {
283 SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
284 if (!recurse)
285 return (ENOTEMPTY);
286 error = sysctl_remove_oid(p, del, recurse);
287 if (error)
288 return (error);
289 }
290 if (del)
291 free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
292 }
293 }
294 if (oidp->oid_refcnt > 1 ) {
295 oidp->oid_refcnt--;
296 } else {
297 if (oidp->oid_refcnt == 0) {
298 printf("Warning: bad oid_refcnt=%u (%s)!\n",
299 oidp->oid_refcnt, oidp->oid_name);
300 return (EINVAL);
301 }
302 sysctl_unregister_oid(oidp);
303 if (del) {
304 free ((char *)oidp->oid_name, M_SYSCTLOID);
305 free(oidp, M_SYSCTLOID);
306 }
307 }
308 return (0);
309}
310
311/*
312 * Create new sysctls at run time.
313 * clist may point to a valid context initialized with sysctl_ctx_init().
314 */
315struct sysctl_oid *
316sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
317 int number, char *name, int kind, void *arg1, int arg2,
318 int (*handler)(SYSCTL_HANDLER_ARGS), char *fmt, char *descr)
319{
320 struct sysctl_oid *oidp;
321 ssize_t len;
322
323 /* You have to hook up somewhere.. */
324 if (parent == NULL)
325 return(NULL);
326 /* Check if the node already exists, otherwise create it */
327 oidp = sysctl_find_oidname(name, parent);
328 if (oidp != NULL) {
329 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
330 oidp->oid_refcnt++;
331 /* Update the context */
332 if (clist != NULL)
333 sysctl_ctx_entry_add(clist, oidp);
334 return (oidp);
335 } else {
336 printf("can't re-use a leaf (%s)!\n", name);
337 return (NULL);
338 }
339 }
340 oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK);
341 bzero(oidp, sizeof(struct sysctl_oid));
342 oidp->oid_parent = parent;
343 SLIST_NEXT(oidp, oid_link) = NULL;
344 oidp->oid_number = number;
345 oidp->oid_refcnt = 1;
346 len = strlen(name);
347 oidp->oid_name = (const char *)malloc(len + 1, M_SYSCTLOID, M_WAITOK);
348 bcopy(name, (char *)oidp->oid_name, len + 1);
349 (char)oidp->oid_name[len] = '\0';
350 oidp->oid_handler = handler;
351 oidp->oid_kind = CTLFLAG_DYN | kind;
352 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
353 /* Allocate space for children */
354 SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list),
355 M_SYSCTLOID, M_WAITOK);
356 SLIST_INIT(SYSCTL_CHILDREN(oidp));
357 } else {
358 oidp->oid_arg1 = arg1;
359 oidp->oid_arg2 = arg2;
360 }
361 oidp->oid_fmt = fmt;
362 /* Update the context, if used */
363 if (clist != NULL)
364 sysctl_ctx_entry_add(clist, oidp);
365 /* Register this oid */
366 sysctl_register_oid(oidp);
367 return (oidp);
368}
369
370/*
119 * Bulk-register all the oids in a linker_set.
120 */
121void sysctl_register_set(struct linker_set *lsp)
122{
123 int count = lsp->ls_length;
124 int i;
125 for (i = 0; i < count; i++)
126 sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);

--- 976 unchanged lines hidden ---
371 * Bulk-register all the oids in a linker_set.
372 */
373void sysctl_register_set(struct linker_set *lsp)
374{
375 int count = lsp->ls_length;
376 int i;
377 for (i = 0; i < count; i++)
378 sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);

--- 976 unchanged lines hidden ---