kern_sysctl.c revision 42466
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 * $Id: kern_sysctl.c,v 1.81 1998/12/27 18:03:29 dfr Exp $ 41 */ 42 43#include "opt_compat.h" 44 45#include <sys/param.h> 46#include <sys/buf.h> 47#include <sys/kernel.h> 48#include <sys/sysctl.h> 49#include <sys/malloc.h> 50#include <sys/proc.h> 51#include <sys/systm.h> 52#include <sys/sysproto.h> 53#include <vm/vm.h> 54#include <vm/vm_extern.h> 55 56static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); 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 69extern struct linker_set sysctl_; 70 71/* 72 * Initialization of the MIB tree. 73 * 74 * Order by number in each linker_set. 75 */ 76 77static int 78sysctl_order_cmp(const void *a, const void *b) 79{ 80 struct sysctl_oid const * const *pa; 81 struct sysctl_oid const * const *pb; 82 83 pa = (struct sysctl_oid const * const *)a; 84 pb = (struct sysctl_oid const * const *)b; 85 if (*pa == NULL && *pb == NULL) 86 return 0; 87 if (*pa == NULL) 88 return (1); 89 if (*pb == NULL) 90 return (-1); 91 return ((*pa)->oid_number - (*pb)->oid_number); 92} 93 94static void 95sysctl_order(void *arg) 96{ 97 int j, k; 98 struct linker_set *l = (struct linker_set *) arg; 99 struct sysctl_oid **oidpp; 100 101 /* First, find the highest oid we have */ 102 j = l->ls_length; 103 oidpp = (struct sysctl_oid **) l->ls_items; 104 for (k = 0; j--; oidpp++) { 105 if (!*oidpp) 106 continue; 107 if ((*oidpp)->oid_arg1 == arg) { 108 *oidpp = 0; 109 continue; 110 } 111 if ((*oidpp)->oid_number > k) 112 k = (*oidpp)->oid_number; 113 } 114 115 /* Next, replace all OID_AUTO oids with new numbers */ 116 j = l->ls_length; 117 oidpp = (struct sysctl_oid **) l->ls_items; 118 k += 100; 119 for (; j--; oidpp++) 120 if (*oidpp && (*oidpp)->oid_number == OID_AUTO) 121 (*oidpp)->oid_number = k++; 122 123 /* Finally: sort by oid */ 124 j = l->ls_length; 125 oidpp = (struct sysctl_oid **) l->ls_items; 126 for (; j--; oidpp++) { 127 if (!*oidpp) 128 continue; 129 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 130 if (!(*oidpp)->oid_handler) 131 sysctl_order((*oidpp)->oid_arg1); 132 } 133 qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 134 sysctl_order_cmp); 135} 136 137SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_); 138 139void 140sysctl_order_all(void) 141{ 142 sysctl_order(&sysctl_); 143} 144 145/* 146 * "Staff-functions" 147 * 148 * These functions implement a presently undocumented interface 149 * used by the sysctl program to walk the tree, and get the type 150 * so it can print the value. 151 * This interface is under work and consideration, and should probably 152 * be killed with a big axe by the first person who can find the time. 153 * (be aware though, that the proper interface isn't as obvious as it 154 * may seem, there are various conflicting requirements. 155 * 156 * {0,0} printf the entire MIB-tree. 157 * {0,1,...} return the name of the "..." OID. 158 * {0,2} return the next OID. 159 * {0,3} return the OID of the name in "new" 160 * {0,4,...} return the kind & format info for the "..." OID. 161 * {0,5,...} return the description for the "..." OID. 162 */ 163 164static void 165sysctl_sysctl_debug_dump_node(struct linker_set *l, int i) 166{ 167 int j, k; 168 struct sysctl_oid **oidpp; 169 170 j = l->ls_length; 171 oidpp = (struct sysctl_oid **) l->ls_items; 172 for (; j--; oidpp++) { 173 174 if (!*oidpp) 175 continue; 176 177 for (k=0; k<i; k++) 178 printf(" "); 179 180 printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 181 182 printf("%c%c", 183 (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 184 (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 185 186 if ((*oidpp)->oid_handler) 187 printf(" *Handler"); 188 189 switch ((*oidpp)->oid_kind & CTLTYPE) { 190 case CTLTYPE_NODE: 191 printf(" Node\n"); 192 if (!(*oidpp)->oid_handler) { 193 sysctl_sysctl_debug_dump_node( 194 (*oidpp)->oid_arg1, i+2); 195 } 196 break; 197 case CTLTYPE_INT: printf(" Int\n"); break; 198 case CTLTYPE_STRING: printf(" String\n"); break; 199 case CTLTYPE_QUAD: printf(" Quad\n"); break; 200 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 201 default: printf("\n"); 202 } 203 204 } 205} 206 207static int 208sysctl_sysctl_debug SYSCTL_HANDLER_ARGS 209{ 210 sysctl_sysctl_debug_dump_node(&sysctl_, 0); 211 return ENOENT; 212} 213 214SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 215 0, 0, sysctl_sysctl_debug, "-", ""); 216 217static int 218sysctl_sysctl_name SYSCTL_HANDLER_ARGS 219{ 220 int *name = (int *) arg1; 221 u_int namelen = arg2; 222 int i, j, error = 0; 223 struct sysctl_oid **oidpp; 224 struct linker_set *lsp = &sysctl_; 225 char buf[10]; 226 227 while (namelen) { 228 if (!lsp) { 229 snprintf(buf,sizeof(buf),"%d",*name); 230 if (req->oldidx) 231 error = SYSCTL_OUT(req, ".", 1); 232 if (!error) 233 error = SYSCTL_OUT(req, buf, strlen(buf)); 234 if (error) 235 return (error); 236 namelen--; 237 name++; 238 continue; 239 } 240 oidpp = (struct sysctl_oid **) lsp->ls_items; 241 j = lsp->ls_length; 242 lsp = 0; 243 for (i = 0; i < j; i++, oidpp++) { 244 if (*oidpp && ((*oidpp)->oid_number != *name)) 245 continue; 246 247 if (req->oldidx) 248 error = SYSCTL_OUT(req, ".", 1); 249 if (!error) 250 error = SYSCTL_OUT(req, (*oidpp)->oid_name, 251 strlen((*oidpp)->oid_name)); 252 if (error) 253 return (error); 254 255 namelen--; 256 name++; 257 258 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 259 break; 260 261 if ((*oidpp)->oid_handler) 262 break; 263 264 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 265 break; 266 } 267 } 268 return (SYSCTL_OUT(req, "", 1)); 269} 270 271SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); 272 273static int 274sysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen, 275 int *next, int *len, int level, struct sysctl_oid **oidp) 276{ 277 int i, j; 278 struct sysctl_oid **oidpp; 279 280 oidpp = (struct sysctl_oid **) lsp->ls_items; 281 j = lsp->ls_length; 282 *len = level; 283 for (i = 0; i < j; i++, oidpp++) { 284 if (!*oidpp) 285 continue; 286 287 *next = (*oidpp)->oid_number; 288 *oidp = *oidpp; 289 290 if (!namelen) { 291 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 292 return 0; 293 if ((*oidpp)->oid_handler) 294 /* We really should call the handler here...*/ 295 return 0; 296 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 297 if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 298 len, level+1, oidp)) 299 return 0; 300 goto next; 301 } 302 303 if ((*oidpp)->oid_number < *name) 304 continue; 305 306 if ((*oidpp)->oid_number > *name) { 307 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 308 return 0; 309 if ((*oidpp)->oid_handler) 310 return 0; 311 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 312 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 313 next+1, len, level+1, oidp)) 314 return (0); 315 goto next; 316 } 317 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 318 continue; 319 320 if ((*oidpp)->oid_handler) 321 continue; 322 323 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 324 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 325 len, level+1, oidp)) 326 return (0); 327 next: 328 namelen = 1; 329 *len = level; 330 } 331 return 1; 332} 333 334static int 335sysctl_sysctl_next SYSCTL_HANDLER_ARGS 336{ 337 int *name = (int *) arg1; 338 u_int namelen = arg2; 339 int i, j, error; 340 struct sysctl_oid *oid; 341 struct linker_set *lsp = &sysctl_; 342 int newoid[CTL_MAXNAME]; 343 344 i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid); 345 if (i) 346 return ENOENT; 347 error = SYSCTL_OUT(req, newoid, j * sizeof (int)); 348 return (error); 349} 350 351SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); 352 353static int 354name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp) 355{ 356 int i, j; 357 struct sysctl_oid **oidpp; 358 struct linker_set *lsp = &sysctl_; 359 char *p; 360 361 if (!*name) 362 return ENOENT; 363 364 p = name + strlen(name) - 1 ; 365 if (*p == '.') 366 *p = '\0'; 367 368 *len = 0; 369 370 for (p = name; *p && *p != '.'; p++) 371 ; 372 i = *p; 373 if (i == '.') 374 *p = '\0'; 375 376 j = lsp->ls_length; 377 oidpp = (struct sysctl_oid **) lsp->ls_items; 378 379 while (j-- && *len < CTL_MAXNAME) { 380 if (!*oidpp) 381 continue; 382 if (strcmp(name, (*oidpp)->oid_name)) { 383 oidpp++; 384 continue; 385 } 386 *oid++ = (*oidpp)->oid_number; 387 (*len)++; 388 389 if (!i) { 390 if (oidp) 391 *oidp = *oidpp; 392 return (0); 393 } 394 395 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 396 break; 397 398 if ((*oidpp)->oid_handler) 399 break; 400 401 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 402 j = lsp->ls_length; 403 oidpp = (struct sysctl_oid **)lsp->ls_items; 404 name = p+1; 405 for (p = name; *p && *p != '.'; p++) 406 ; 407 i = *p; 408 if (i == '.') 409 *p = '\0'; 410 } 411 return ENOENT; 412} 413 414static int 415sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS 416{ 417 char *p; 418 int error, oid[CTL_MAXNAME], len; 419 struct sysctl_oid *op = 0; 420 421 if (!req->newlen) 422 return ENOENT; 423 424 p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); 425 426 error = SYSCTL_IN(req, p, req->newlen); 427 if (error) { 428 free(p, M_SYSCTL); 429 return (error); 430 } 431 432 p [req->newlen] = '\0'; 433 434 error = name2oid(p, oid, &len, &op); 435 436 free(p, M_SYSCTL); 437 438 if (error) 439 return (error); 440 441 error = SYSCTL_OUT(req, oid, len * sizeof *oid); 442 return (error); 443} 444 445SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 446 sysctl_sysctl_name2oid, "I", ""); 447 448static int 449sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS 450{ 451 int *name = (int *) arg1, error; 452 u_int namelen = arg2; 453 int indx, j; 454 struct sysctl_oid **oidpp; 455 struct linker_set *lsp = &sysctl_; 456 457 j = lsp->ls_length; 458 oidpp = (struct sysctl_oid **) lsp->ls_items; 459 460 indx = 0; 461 while (j-- && indx < CTL_MAXNAME) { 462 if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 463 indx++; 464 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 465 if ((*oidpp)->oid_handler) 466 goto found; 467 if (indx == namelen) 468 goto found; 469 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 470 j = lsp->ls_length; 471 oidpp = (struct sysctl_oid **)lsp->ls_items; 472 } else { 473 if (indx != namelen) 474 return EISDIR; 475 goto found; 476 } 477 } else { 478 oidpp++; 479 } 480 } 481 return ENOENT; 482found: 483 if (!(*oidpp)->oid_fmt) 484 return ENOENT; 485 error = SYSCTL_OUT(req, 486 &(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind)); 487 if (!error) 488 error = SYSCTL_OUT(req, (*oidpp)->oid_fmt, 489 strlen((*oidpp)->oid_fmt)+1); 490 return (error); 491} 492 493SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); 494 495static int 496sysctl_sysctl_descr SYSCTL_HANDLER_ARGS 497{ 498#ifndef NO_SYSCTL_DESCRIPTIONS 499 int *name = (int *) arg1; 500 u_int namelen = arg2; 501 int i, j, error = 0; 502 struct sysctl_oid **oidpp; 503 struct linker_set *lsp = &sysctl_; 504 505 if (!lsp || !namelen) 506 return (SYSCTL_OUT(req, "", 1)); 507 508 while (namelen) { 509 oidpp = (struct sysctl_oid **) lsp->ls_items; 510 j = lsp->ls_length; 511 lsp = 0; 512 for (i = 0; i < j; i++, oidpp++) { 513 if (*oidpp && ((*oidpp)->oid_number != *name)) 514 continue; 515 516 namelen--; 517 name++; 518 519 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE) 520 break; 521 522 if ((*oidpp)->oid_handler) 523 break; 524 525 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 526 break; 527 } 528 } 529 530 error = SYSCTL_OUT(req, (*oidpp)->oid_descr, 531 strlen((*oidpp)->oid_descr) + 1); 532 return (error); 533#else 534 return (SYSCTL_OUT(req, "", 1)); 535#endif /* !NO_SYSCTL_DESCRIPTIONS */ 536} 537 538SYSCTL_NODE(_sysctl, 5, descr, CTLFLAG_RD, sysctl_sysctl_descr, ""); 539 540/* 541 * Default "handler" functions. 542 */ 543 544/* 545 * Handle an int, signed or unsigned. 546 * Two cases: 547 * a variable: point arg1 at it. 548 * a constant: pass it in arg2. 549 */ 550 551int 552sysctl_handle_int SYSCTL_HANDLER_ARGS 553{ 554 int error = 0; 555 556 if (arg1) 557 error = SYSCTL_OUT(req, arg1, sizeof(int)); 558 else 559 error = SYSCTL_OUT(req, &arg2, sizeof(int)); 560 561 if (error || !req->newptr) 562 return (error); 563 564 if (!arg1) 565 error = EPERM; 566 else 567 error = SYSCTL_IN(req, arg1, sizeof(int)); 568 return (error); 569} 570 571/* 572 * Handle a long, signed or unsigned. 573 * Two cases: 574 * a variable: point arg1 at it. 575 * a constant: pass it in arg2. 576 */ 577 578int 579sysctl_handle_long SYSCTL_HANDLER_ARGS 580{ 581 int error = 0; 582 583 error = SYSCTL_OUT(req, arg1, sizeof(long)); 584 585 if (error || !req->newptr) 586 return (error); 587 588 if (!arg1) 589 error = EPERM; 590 else 591 error = SYSCTL_IN(req, arg1, sizeof(long)); 592 return (error); 593} 594 595/* 596 * Handle our generic '\0' terminated 'C' string. 597 * Two cases: 598 * a variable string: point arg1 at it, arg2 is max length. 599 * a constant string: point arg1 at it, arg2 is zero. 600 */ 601 602int 603sysctl_handle_string SYSCTL_HANDLER_ARGS 604{ 605 int error=0; 606 607 error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); 608 609 if (error || !req->newptr || !arg2) 610 return (error); 611 612 if ((req->newlen - req->newidx) > arg2) { 613 error = E2BIG; 614 } else { 615 arg2 = (req->newlen - req->newidx); 616 error = SYSCTL_IN(req, arg1, arg2); 617 ((char *)arg1)[arg2] = '\0'; 618 } 619 620 return (error); 621} 622 623/* 624 * Handle any kind of opaque data. 625 * arg1 points to it, arg2 is the size. 626 */ 627 628int 629sysctl_handle_opaque SYSCTL_HANDLER_ARGS 630{ 631 int error; 632 633 error = SYSCTL_OUT(req, arg1, arg2); 634 635 if (error || !req->newptr) 636 return (error); 637 638 error = SYSCTL_IN(req, arg1, arg2); 639 640 return (error); 641} 642 643/* 644 * Transfer functions to/from kernel space. 645 * XXX: rather untested at this point 646 */ 647static int 648sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) 649{ 650 size_t i = 0; 651 652 if (req->oldptr) { 653 i = l; 654 if (i > req->oldlen - req->oldidx) 655 i = req->oldlen - req->oldidx; 656 if (i > 0) 657 bcopy(p, (char *)req->oldptr + req->oldidx, i); 658 } 659 req->oldidx += l; 660 if (req->oldptr && i != l) 661 return (ENOMEM); 662 return (0); 663} 664 665static int 666sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) 667{ 668 if (!req->newptr) 669 return 0; 670 if (req->newlen - req->newidx < l) 671 return (EINVAL); 672 bcopy((char *)req->newptr + req->newidx, p, l); 673 req->newidx += l; 674 return (0); 675} 676 677int 678kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval) 679{ 680 int error = 0; 681 struct sysctl_req req; 682 683 bzero(&req, sizeof req); 684 685 req.p = p; 686 687 if (oldlenp) { 688 req.oldlen = *oldlenp; 689 } 690 691 if (old) { 692 req.oldptr= old; 693 } 694 695 if (newlen) { 696 req.newlen = newlen; 697 req.newptr = new; 698 } 699 700 req.oldfunc = sysctl_old_kernel; 701 req.newfunc = sysctl_new_kernel; 702 req.lock = 1; 703 704 /* XXX this should probably be done in a general way */ 705 while (memlock.sl_lock) { 706 memlock.sl_want = 1; 707 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 708 memlock.sl_locked++; 709 } 710 memlock.sl_lock = 1; 711 712 error = sysctl_root(0, name, namelen, &req); 713 714 if (req.lock == 2) 715 vsunlock(req.oldptr, req.oldlen, B_WRITE); 716 717 memlock.sl_lock = 0; 718 719 if (memlock.sl_want) { 720 memlock.sl_want = 0; 721 wakeup((caddr_t)&memlock); 722 } 723 724 if (error && error != ENOMEM) 725 return (error); 726 727 if (retval) { 728 if (req.oldptr && req.oldidx > req.oldlen) 729 *retval = req.oldlen; 730 else 731 *retval = req.oldidx; 732 } 733 return (error); 734} 735 736/* 737 * Transfer function to/from user space. 738 */ 739static int 740sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) 741{ 742 int error = 0; 743 size_t i = 0; 744 745 if (req->lock == 1 && req->oldptr) { 746 vslock(req->oldptr, req->oldlen); 747 req->lock = 2; 748 } 749 if (req->oldptr) { 750 i = l; 751 if (i > req->oldlen - req->oldidx) 752 i = req->oldlen - req->oldidx; 753 if (i > 0) 754 error = copyout(p, (char *)req->oldptr + req->oldidx, 755 i); 756 } 757 req->oldidx += l; 758 if (error) 759 return (error); 760 if (req->oldptr && i < l) 761 return (ENOMEM); 762 return (0); 763} 764 765static int 766sysctl_new_user(struct sysctl_req *req, void *p, size_t l) 767{ 768 int error; 769 770 if (!req->newptr) 771 return 0; 772 if (req->newlen - req->newidx < l) 773 return (EINVAL); 774 error = copyin((char *)req->newptr + req->newidx, p, l); 775 req->newidx += l; 776 return (error); 777} 778 779/* 780 * Traverse our tree, and find the right node, execute whatever it points 781 * at, and return the resulting error code. 782 */ 783 784int 785sysctl_root SYSCTL_HANDLER_ARGS 786{ 787 int *name = (int *) arg1; 788 u_int namelen = arg2; 789 int indx, i, j; 790 struct sysctl_oid **oidpp; 791 struct linker_set *lsp = &sysctl_; 792 793 j = lsp->ls_length; 794 oidpp = (struct sysctl_oid **) lsp->ls_items; 795 796 indx = 0; 797 while (j-- && indx < CTL_MAXNAME) { 798 if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 799 indx++; 800 if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK) 801 req->lock = 0; 802 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 803 if ((*oidpp)->oid_handler) 804 goto found; 805 if (indx == namelen) 806 return ENOENT; 807 lsp = (struct linker_set*)(*oidpp)->oid_arg1; 808 j = lsp->ls_length; 809 oidpp = (struct sysctl_oid **)lsp->ls_items; 810 } else { 811 if (indx != namelen) 812 return EISDIR; 813 goto found; 814 } 815 } else { 816 oidpp++; 817 } 818 } 819 return ENOENT; 820found: 821 /* If writing isn't allowed */ 822 if (req->newptr && (!((*oidpp)->oid_kind & CTLFLAG_WR) || 823 (((*oidpp)->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) 824 return (EPERM); 825 826 /* Most likely only root can write */ 827 if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) && 828 req->newptr && req->p && 829 (i = suser(req->p->p_ucred, &req->p->p_acflag))) 830 return (i); 831 832 if (!(*oidpp)->oid_handler) 833 return EINVAL; 834 835 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 836 i = ((*oidpp)->oid_handler) (*oidpp, 837 name + indx, namelen - indx, 838 req); 839 } else { 840 i = ((*oidpp)->oid_handler) (*oidpp, 841 (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 842 req); 843 } 844 return (i); 845} 846 847#ifndef _SYS_SYSPROTO_H_ 848struct sysctl_args { 849 int *name; 850 u_int namelen; 851 void *old; 852 size_t *oldlenp; 853 void *new; 854 size_t newlen; 855}; 856#endif 857 858int 859__sysctl(struct proc *p, struct sysctl_args *uap) 860{ 861 int error, i, name[CTL_MAXNAME]; 862 size_t j; 863 864 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 865 return (EINVAL); 866 867 error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 868 if (error) 869 return (error); 870 871 error = userland_sysctl(p, name, uap->namelen, 872 uap->old, uap->oldlenp, 0, 873 uap->new, uap->newlen, &j); 874 if (error && error != ENOMEM) 875 return (error); 876 if (uap->oldlenp) { 877 i = copyout(&j, uap->oldlenp, sizeof(j)); 878 if (i) 879 return (i); 880 } 881 return (error); 882} 883 884/* 885 * This is used from various compatibility syscalls too. That's why name 886 * must be in kernel space. 887 */ 888int 889userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval) 890{ 891 int error = 0; 892 struct sysctl_req req, req2; 893 894 bzero(&req, sizeof req); 895 896 req.p = p; 897 898 if (oldlenp) { 899 if (inkernel) { 900 req.oldlen = *oldlenp; 901 } else { 902 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 903 if (error) 904 return (error); 905 } 906 } 907 908 if (old) { 909 if (!useracc(old, req.oldlen, B_WRITE)) 910 return (EFAULT); 911 req.oldptr= old; 912 } 913 914 if (newlen) { 915 if (!useracc(new, req.newlen, B_READ)) 916 return (EFAULT); 917 req.newlen = newlen; 918 req.newptr = new; 919 } 920 921 req.oldfunc = sysctl_old_user; 922 req.newfunc = sysctl_new_user; 923 req.lock = 1; 924 925 /* XXX this should probably be done in a general way */ 926 while (memlock.sl_lock) { 927 memlock.sl_want = 1; 928 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 929 memlock.sl_locked++; 930 } 931 memlock.sl_lock = 1; 932 933 do { 934 req2 = req; 935 error = sysctl_root(0, name, namelen, &req2); 936 } while (error == EAGAIN); 937 938 req = req2; 939 if (req.lock == 2) 940 vsunlock(req.oldptr, req.oldlen, B_WRITE); 941 942 memlock.sl_lock = 0; 943 944 if (memlock.sl_want) { 945 memlock.sl_want = 0; 946 wakeup((caddr_t)&memlock); 947 } 948 949 if (error && error != ENOMEM) 950 return (error); 951 952 if (retval) { 953 if (req.oldptr && req.oldidx > req.oldlen) 954 *retval = req.oldlen; 955 else 956 *retval = req.oldidx; 957 } 958 return (error); 959} 960 961#ifdef COMPAT_43 962#include <sys/socket.h> 963#include <vm/vm_param.h> 964 965#define KINFO_PROC (0<<8) 966#define KINFO_RT (1<<8) 967#define KINFO_VNODE (2<<8) 968#define KINFO_FILE (3<<8) 969#define KINFO_METER (4<<8) 970#define KINFO_LOADAVG (5<<8) 971#define KINFO_CLOCKRATE (6<<8) 972 973/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 974#define KINFO_BSDI_SYSINFO (101<<8) 975 976/* 977 * XXX this is bloat, but I hope it's better here than on the potentially 978 * limited kernel stack... -Peter 979 */ 980 981static struct { 982 int bsdi_machine; /* "i386" on BSD/386 */ 983/* ^^^ this is an offset to the string, relative to the struct start */ 984 char *pad0; 985 long pad1; 986 long pad2; 987 long pad3; 988 u_long pad4; 989 u_long pad5; 990 u_long pad6; 991 992 int bsdi_ostype; /* "BSD/386" on BSD/386 */ 993 int bsdi_osrelease; /* "1.1" on BSD/386 */ 994 long pad7; 995 long pad8; 996 char *pad9; 997 998 long pad10; 999 long pad11; 1000 int pad12; 1001 long pad13; 1002 quad_t pad14; 1003 long pad15; 1004 1005 struct timeval pad16; 1006 /* we dont set this, because BSDI's uname used gethostname() instead */ 1007 int bsdi_hostname; /* hostname on BSD/386 */ 1008 1009 /* the actual string data is appended here */ 1010 1011} bsdi_si; 1012/* 1013 * this data is appended to the end of the bsdi_si structure during copyout. 1014 * The "char *" offsets are relative to the base of the bsdi_si struct. 1015 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 1016 * should not exceed the length of the buffer here... (or else!! :-) 1017 */ 1018static char bsdi_strings[80]; /* It had better be less than this! */ 1019 1020#ifndef _SYS_SYSPROTO_H_ 1021struct getkerninfo_args { 1022 int op; 1023 char *where; 1024 size_t *size; 1025 int arg; 1026}; 1027#endif 1028 1029int 1030ogetkerninfo(struct proc *p, struct getkerninfo_args *uap) 1031{ 1032 int error, name[6]; 1033 size_t size; 1034 1035 switch (uap->op & 0xff00) { 1036 1037 case KINFO_RT: 1038 name[0] = CTL_NET; 1039 name[1] = PF_ROUTE; 1040 name[2] = 0; 1041 name[3] = (uap->op & 0xff0000) >> 16; 1042 name[4] = uap->op & 0xff; 1043 name[5] = uap->arg; 1044 error = userland_sysctl(p, name, 6, uap->where, uap->size, 1045 0, 0, 0, &size); 1046 break; 1047 1048 case KINFO_VNODE: 1049 name[0] = CTL_KERN; 1050 name[1] = KERN_VNODE; 1051 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1052 0, 0, 0, &size); 1053 break; 1054 1055 case KINFO_PROC: 1056 name[0] = CTL_KERN; 1057 name[1] = KERN_PROC; 1058 name[2] = uap->op & 0xff; 1059 name[3] = uap->arg; 1060 error = userland_sysctl(p, name, 4, uap->where, uap->size, 1061 0, 0, 0, &size); 1062 break; 1063 1064 case KINFO_FILE: 1065 name[0] = CTL_KERN; 1066 name[1] = KERN_FILE; 1067 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1068 0, 0, 0, &size); 1069 break; 1070 1071 case KINFO_METER: 1072 name[0] = CTL_VM; 1073 name[1] = VM_METER; 1074 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1075 0, 0, 0, &size); 1076 break; 1077 1078 case KINFO_LOADAVG: 1079 name[0] = CTL_VM; 1080 name[1] = VM_LOADAVG; 1081 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1082 0, 0, 0, &size); 1083 break; 1084 1085 case KINFO_CLOCKRATE: 1086 name[0] = CTL_KERN; 1087 name[1] = KERN_CLOCKRATE; 1088 error = userland_sysctl(p, name, 2, uap->where, uap->size, 1089 0, 0, 0, &size); 1090 break; 1091 1092 case KINFO_BSDI_SYSINFO: { 1093 /* 1094 * this is pretty crude, but it's just enough for uname() 1095 * from BSDI's 1.x libc to work. 1096 * 1097 * In particular, it doesn't return the same results when 1098 * the supplied buffer is too small. BSDI's version apparently 1099 * will return the amount copied, and set the *size to how 1100 * much was needed. The emulation framework here isn't capable 1101 * of that, so we just set both to the amount copied. 1102 * BSDI's 2.x product apparently fails with ENOMEM in this 1103 * scenario. 1104 */ 1105 1106 u_int needed; 1107 u_int left; 1108 char *s; 1109 1110 bzero((char *)&bsdi_si, sizeof(bsdi_si)); 1111 bzero(bsdi_strings, sizeof(bsdi_strings)); 1112 1113 s = bsdi_strings; 1114 1115 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 1116 strcpy(s, ostype); 1117 s += strlen(s) + 1; 1118 1119 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 1120 strcpy(s, osrelease); 1121 s += strlen(s) + 1; 1122 1123 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 1124 strcpy(s, machine); 1125 s += strlen(s) + 1; 1126 1127 needed = sizeof(bsdi_si) + (s - bsdi_strings); 1128 1129 if (uap->where == NULL) { 1130 /* process is asking how much buffer to supply.. */ 1131 size = needed; 1132 error = 0; 1133 break; 1134 } 1135 1136 1137 /* if too much buffer supplied, trim it down */ 1138 if (size > needed) 1139 size = needed; 1140 1141 /* how much of the buffer is remaining */ 1142 left = size; 1143 1144 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 1145 break; 1146 1147 /* is there any point in continuing? */ 1148 if (left > sizeof(bsdi_si)) { 1149 left -= sizeof(bsdi_si); 1150 error = copyout(&bsdi_strings, 1151 uap->where + sizeof(bsdi_si), left); 1152 } 1153 break; 1154 } 1155 1156 default: 1157 return (EOPNOTSUPP); 1158 } 1159 if (error) 1160 return (error); 1161 p->p_retval[0] = size; 1162 if (uap->size) 1163 error = copyout((caddr_t)&size, (caddr_t)uap->size, 1164 sizeof(size)); 1165 return (error); 1166} 1167#endif /* COMPAT_43 */ 1168