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