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 --- |