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