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