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