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