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