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