|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /*- ! 23: * Copyright (c) 1982, 1986, 1989, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * This code is derived from software contributed to Berkeley by ! 27: * Mike Karels at Berkeley Software Design, Inc. ! 28: * ! 29: * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD ! 30: * project, to make these variables more userfriendly. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 ! 61: */ ! 62: ! 63: ! 64: #include <sys/param.h> ! 65: #include <sys/buf.h> ! 66: #include <sys/kernel.h> ! 67: #include <sys/sysctl.h> ! 68: #include <sys/malloc.h> ! 69: #include <sys/proc.h> ! 70: #include <sys/systm.h> ! 71: ! 72: /* ! 73: struct sysctl_oid_list sysctl__debug_children; ! 74: struct sysctl_oid_list sysctl__kern_children; ! 75: struct sysctl_oid_list sysctl__net_children; ! 76: struct sysctl_oid_list sysctl__sysctl_children; ! 77: */ ! 78: ! 79: extern struct sysctl_oid *newsysctl_list[]; ! 80: ! 81: ! 82: static void ! 83: sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i); ! 84: ! 85: ! 86: ! 87: /* ! 88: * Locking and stats ! 89: */ ! 90: static struct sysctl_lock { ! 91: int sl_lock; ! 92: int sl_want; ! 93: int sl_locked; ! 94: } memlock; ! 95: ! 96: static int sysctl_root SYSCTL_HANDLER_ARGS; ! 97: ! 98: struct sysctl_oid_list sysctl__children; /* root list */ ! 99: ! 100: /* ! 101: * Initialization of the MIB tree. ! 102: * ! 103: * Order by number in each list. ! 104: */ ! 105: ! 106: void sysctl_register_oid(struct sysctl_oid *oidp) ! 107: { ! 108: struct sysctl_oid_list *parent = oidp->oid_parent; ! 109: struct sysctl_oid *p; ! 110: struct sysctl_oid *q; ! 111: int n; ! 112: ! 113: /* ! 114: * If this oid has a number OID_AUTO, give it a number which ! 115: * is greater than any current oid. Make sure it is at least ! 116: * 100 to leave space for pre-assigned oid numbers. ! 117: */ ! 118: /* sysctl_sysctl_debug_dump_node(parent, 3); */ ! 119: if (oidp->oid_number == OID_AUTO) { ! 120: /* First, find the highest oid in the parent list >99 */ ! 121: n = 99; ! 122: SLIST_FOREACH(p, parent, oid_link) { ! 123: if (p->oid_number > n) ! 124: n = p->oid_number; ! 125: } ! 126: oidp->oid_number = n + 1; ! 127: } ! 128: ! 129: /* ! 130: * Insert the oid into the parent's list in order. ! 131: */ ! 132: q = NULL; ! 133: SLIST_FOREACH(p, parent, oid_link) { ! 134: if (oidp->oid_number < p->oid_number) ! 135: break; ! 136: q = p; ! 137: } ! 138: if (q) ! 139: SLIST_INSERT_AFTER(q, oidp, oid_link); ! 140: else ! 141: SLIST_INSERT_HEAD(parent, oidp, oid_link); ! 142: } ! 143: ! 144: void sysctl_unregister_oid(struct sysctl_oid *oidp) ! 145: { ! 146: SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link); ! 147: } ! 148: ! 149: /* ! 150: * Bulk-register all the oids in a linker_set. ! 151: */ ! 152: void sysctl_register_set(struct linker_set *lsp) ! 153: { ! 154: int count = lsp->ls_length; ! 155: int i; ! 156: for (i = 0; i < count; i++) ! 157: sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]); ! 158: } ! 159: ! 160: void sysctl_unregister_set(struct linker_set *lsp) ! 161: { ! 162: int count = lsp->ls_length; ! 163: int i; ! 164: for (i = 0; i < count; i++) ! 165: sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]); ! 166: } ! 167: ! 168: ! 169: /* ! 170: * Register OID's from fixed list ! 171: */ ! 172: ! 173: void sysctl_register_fixed() ! 174: { ! 175: int i = 0; ! 176: ! 177: ! 178: while (newsysctl_list[i]) { ! 179: /* printf("Registering %d\n", i); */ ! 180: sysctl_register_oid(newsysctl_list[i++]); ! 181: } ! 182: } ! 183: ! 184: /* ! 185: * Register the kernel's oids on startup. ! 186: */ ! 187: struct linker_set sysctl_set; ! 188: ! 189: void sysctl_register_all(void *arg) ! 190: { ! 191: sysctl_register_set(&sysctl_set); ! 192: } ! 193: ! 194: SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); ! 195: ! 196: /* ! 197: * "Staff-functions" ! 198: * ! 199: * These functions implement a presently undocumented interface ! 200: * used by the sysctl program to walk the tree, and get the type ! 201: * so it can print the value. ! 202: * This interface is under work and consideration, and should probably ! 203: * be killed with a big axe by the first person who can find the time. ! 204: * (be aware though, that the proper interface isn't as obvious as it ! 205: * may seem, there are various conflicting requirements. ! 206: * ! 207: * {0,0} printf the entire MIB-tree. ! 208: * {0,1,...} return the name of the "..." OID. ! 209: * {0,2,...} return the next OID. ! 210: * {0,3} return the OID of the name in "new" ! 211: * {0,4,...} return the kind & format info for the "..." OID. ! 212: */ ! 213: ! 214: static void ! 215: sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) ! 216: { ! 217: int k; ! 218: struct sysctl_oid *oidp; ! 219: ! 220: SLIST_FOREACH(oidp, l, oid_link) { ! 221: ! 222: for (k=0; k<i; k++) ! 223: printf(" "); ! 224: ! 225: printf("%d %s ", oidp->oid_number, oidp->oid_name); ! 226: ! 227: printf("%c%c", ! 228: oidp->oid_kind & CTLFLAG_RD ? 'R':' ', ! 229: oidp->oid_kind & CTLFLAG_WR ? 'W':' '); ! 230: ! 231: if (oidp->oid_handler) ! 232: printf(" *Handler"); ! 233: ! 234: switch (oidp->oid_kind & CTLTYPE) { ! 235: case CTLTYPE_NODE: ! 236: printf(" Node\n"); ! 237: if (!oidp->oid_handler) { ! 238: sysctl_sysctl_debug_dump_node( ! 239: oidp->oid_arg1, i+2); ! 240: } ! 241: break; ! 242: case CTLTYPE_INT: printf(" Int\n"); break; ! 243: case CTLTYPE_STRING: printf(" String\n"); break; ! 244: case CTLTYPE_QUAD: printf(" Quad\n"); break; ! 245: case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; ! 246: default: printf("\n"); ! 247: } ! 248: ! 249: } ! 250: } ! 251: ! 252: static int ! 253: sysctl_sysctl_debug SYSCTL_HANDLER_ARGS ! 254: { ! 255: sysctl_sysctl_debug_dump_node(&sysctl__children, 0); ! 256: return ENOENT; ! 257: } ! 258: ! 259: SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, ! 260: 0, 0, sysctl_sysctl_debug, "-", ""); ! 261: ! 262: static int ! 263: sysctl_sysctl_name SYSCTL_HANDLER_ARGS ! 264: { ! 265: int *name = (int *) arg1; ! 266: u_int namelen = arg2; ! 267: int error = 0; ! 268: struct sysctl_oid *oid; ! 269: struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; ! 270: char buf[10]; ! 271: ! 272: while (namelen) { ! 273: if (!lsp) { ! 274: snprintf(buf,sizeof(buf),"%d",*name); ! 275: if (req->oldidx) ! 276: error = SYSCTL_OUT(req, ".", 1); ! 277: if (!error) ! 278: error = SYSCTL_OUT(req, buf, strlen(buf)); ! 279: if (error) ! 280: return (error); ! 281: namelen--; ! 282: name++; ! 283: continue; ! 284: } ! 285: lsp2 = 0; ! 286: SLIST_FOREACH(oid, lsp, oid_link) { ! 287: if (oid->oid_number != *name) ! 288: continue; ! 289: ! 290: if (req->oldidx) ! 291: error = SYSCTL_OUT(req, ".", 1); ! 292: if (!error) ! 293: error = SYSCTL_OUT(req, oid->oid_name, ! 294: strlen(oid->oid_name)); ! 295: if (error) ! 296: return (error); ! 297: ! 298: namelen--; ! 299: name++; ! 300: ! 301: if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) ! 302: break; ! 303: ! 304: if (oid->oid_handler) ! 305: break; ! 306: ! 307: lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; ! 308: break; ! 309: } ! 310: lsp = lsp2; ! 311: } ! 312: return (SYSCTL_OUT(req, "", 1)); ! 313: } ! 314: ! 315: SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); ! 316: ! 317: static int ! 318: sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen, ! 319: int *next, int *len, int level, struct sysctl_oid **oidpp) ! 320: { ! 321: struct sysctl_oid *oidp; ! 322: ! 323: *len = level; ! 324: SLIST_FOREACH(oidp, lsp, oid_link) { ! 325: *next = oidp->oid_number; ! 326: *oidpp = oidp; ! 327: ! 328: if (!namelen) { ! 329: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) ! 330: return 0; ! 331: if (oidp->oid_handler) ! 332: /* We really should call the handler here...*/ ! 333: return 0; ! 334: lsp = (struct sysctl_oid_list *)oidp->oid_arg1; ! 335: if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, ! 336: len, level+1, oidpp)) ! 337: return 0; ! 338: goto next; ! 339: } ! 340: ! 341: if (oidp->oid_number < *name) ! 342: continue; ! 343: ! 344: if (oidp->oid_number > *name) { ! 345: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) ! 346: return 0; ! 347: if (oidp->oid_handler) ! 348: return 0; ! 349: lsp = (struct sysctl_oid_list *)oidp->oid_arg1; ! 350: if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, ! 351: next+1, len, level+1, oidpp)) ! 352: return (0); ! 353: goto next; ! 354: } ! 355: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) ! 356: continue; ! 357: ! 358: if (oidp->oid_handler) ! 359: continue; ! 360: ! 361: lsp = (struct sysctl_oid_list *)oidp->oid_arg1; ! 362: if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, ! 363: len, level+1, oidpp)) ! 364: return (0); ! 365: next: ! 366: namelen = 1; ! 367: *len = level; ! 368: } ! 369: return 1; ! 370: } ! 371: ! 372: static int ! 373: sysctl_sysctl_next SYSCTL_HANDLER_ARGS ! 374: { ! 375: int *name = (int *) arg1; ! 376: u_int namelen = arg2; ! 377: int i, j, error; ! 378: struct sysctl_oid *oid; ! 379: struct sysctl_oid_list *lsp = &sysctl__children; ! 380: int newoid[CTL_MAXNAME]; ! 381: ! 382: i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid); ! 383: if (i) ! 384: return ENOENT; ! 385: error = SYSCTL_OUT(req, newoid, j * sizeof (int)); ! 386: return (error); ! 387: } ! 388: ! 389: SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); ! 390: ! 391: static int ! 392: name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp) ! 393: { ! 394: int i; ! 395: struct sysctl_oid *oidp; ! 396: struct sysctl_oid_list *lsp = &sysctl__children; ! 397: char *p; ! 398: ! 399: if (!*name) ! 400: return ENOENT; ! 401: ! 402: p = name + strlen(name) - 1 ; ! 403: if (*p == '.') ! 404: *p = '\0'; ! 405: ! 406: *len = 0; ! 407: ! 408: for (p = name; *p && *p != '.'; p++) ! 409: ; ! 410: i = *p; ! 411: if (i == '.') ! 412: *p = '\0'; ! 413: ! 414: oidp = SLIST_FIRST(lsp); ! 415: ! 416: while (oidp && *len < CTL_MAXNAME) { ! 417: if (strcmp(name, oidp->oid_name)) { ! 418: oidp = SLIST_NEXT(oidp, oid_link); ! 419: continue; ! 420: } ! 421: *oid++ = oidp->oid_number; ! 422: (*len)++; ! 423: ! 424: if (!i) { ! 425: if (oidpp) ! 426: *oidpp = oidp; ! 427: return (0); ! 428: } ! 429: ! 430: if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) ! 431: break; ! 432: ! 433: if (oidp->oid_handler) ! 434: break; ! 435: ! 436: lsp = (struct sysctl_oid_list *)oidp->oid_arg1; ! 437: oidp = SLIST_FIRST(lsp); ! 438: name = p+1; ! 439: for (p = name; *p && *p != '.'; p++) ! 440: ; ! 441: i = *p; ! 442: if (i == '.') ! 443: *p = '\0'; ! 444: } ! 445: return ENOENT; ! 446: } ! 447: ! 448: static int ! 449: sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS ! 450: { ! 451: char *p; ! 452: int error, oid[CTL_MAXNAME], len; ! 453: struct sysctl_oid *op = 0; ! 454: ! 455: if (!req->newlen) ! 456: return ENOENT; ! 457: if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */ ! 458: return (ENAMETOOLONG); ! 459: ! 460: p = _MALLOC(req->newlen+1, M_TEMP, M_WAITOK); ! 461: ! 462: if (!p) ! 463: return ENOMEM; ! 464: ! 465: error = SYSCTL_IN(req, p, req->newlen); ! 466: if (error) { ! 467: FREE(p, M_TEMP); ! 468: return (error); ! 469: } ! 470: ! 471: p [req->newlen] = '\0'; ! 472: ! 473: error = name2oid(p, oid, &len, &op); ! 474: ! 475: FREE(p, M_TEMP); ! 476: ! 477: if (error) ! 478: return (error); ! 479: ! 480: error = SYSCTL_OUT(req, oid, len * sizeof *oid); ! 481: return (error); ! 482: } ! 483: ! 484: SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, ! 485: sysctl_sysctl_name2oid, "I", ""); ! 486: ! 487: static int ! 488: sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS ! 489: { ! 490: int *name = (int *) arg1, error; ! 491: u_int namelen = arg2; ! 492: int indx; ! 493: struct sysctl_oid *oid; ! 494: struct sysctl_oid_list *lsp = &sysctl__children; ! 495: ! 496: oid = SLIST_FIRST(lsp); ! 497: ! 498: indx = 0; ! 499: while (oid && indx < CTL_MAXNAME) { ! 500: if (oid->oid_number == name[indx]) { ! 501: indx++; ! 502: if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { ! 503: if (oid->oid_handler) ! 504: goto found; ! 505: if (indx == namelen) ! 506: goto found; ! 507: lsp = (struct sysctl_oid_list *)oid->oid_arg1; ! 508: oid = SLIST_FIRST(lsp); ! 509: } else { ! 510: if (indx != namelen) ! 511: return EISDIR; ! 512: goto found; ! 513: } ! 514: } else { ! 515: oid = SLIST_NEXT(oid, oid_link); ! 516: } ! 517: } ! 518: return ENOENT; ! 519: found: ! 520: if (!oid->oid_fmt) ! 521: return ENOENT; ! 522: error = SYSCTL_OUT(req, ! 523: &oid->oid_kind, sizeof(oid->oid_kind)); ! 524: if (!error) ! 525: error = SYSCTL_OUT(req, oid->oid_fmt, ! 526: strlen(oid->oid_fmt)+1); ! 527: return (error); ! 528: } ! 529: ! 530: ! 531: SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); ! 532: ! 533: /* ! 534: * Default "handler" functions. ! 535: */ ! 536: ! 537: /* ! 538: * Handle an int, signed or unsigned. ! 539: * Two cases: ! 540: * a variable: point arg1 at it. ! 541: * a constant: pass it in arg2. ! 542: */ ! 543: ! 544: int ! 545: sysctl_handle_int SYSCTL_HANDLER_ARGS ! 546: { ! 547: int error = 0; ! 548: ! 549: if (arg1) ! 550: error = SYSCTL_OUT(req, arg1, sizeof(int)); ! 551: else ! 552: error = SYSCTL_OUT(req, &arg2, sizeof(int)); ! 553: ! 554: if (error || !req->newptr) ! 555: return (error); ! 556: ! 557: if (!arg1) ! 558: error = EPERM; ! 559: else ! 560: error = SYSCTL_IN(req, arg1, sizeof(int)); ! 561: return (error); ! 562: } ! 563: ! 564: /* ! 565: * Handle a long, signed or unsigned. arg1 points to it. ! 566: */ ! 567: ! 568: int ! 569: sysctl_handle_long SYSCTL_HANDLER_ARGS ! 570: { ! 571: int error = 0; ! 572: ! 573: if (!arg1) ! 574: return (EINVAL); ! 575: error = SYSCTL_OUT(req, arg1, sizeof(long)); ! 576: ! 577: if (error || !req->newptr) ! 578: return (error); ! 579: ! 580: error = SYSCTL_IN(req, arg1, sizeof(long)); ! 581: return (error); ! 582: } ! 583: ! 584: /* ! 585: * Handle our generic '\0' terminated 'C' string. ! 586: * Two cases: ! 587: * a variable string: point arg1 at it, arg2 is max length. ! 588: * a constant string: point arg1 at it, arg2 is zero. ! 589: */ ! 590: ! 591: int ! 592: sysctl_handle_string SYSCTL_HANDLER_ARGS ! 593: { ! 594: int error=0; ! 595: ! 596: error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1); ! 597: ! 598: if (error || !req->newptr) ! 599: return (error); ! 600: ! 601: if ((req->newlen - req->newidx) >= arg2) { ! 602: error = EINVAL; ! 603: } else { ! 604: arg2 = (req->newlen - req->newidx); ! 605: error = SYSCTL_IN(req, arg1, arg2); ! 606: ((char *)arg1)[arg2] = '\0'; ! 607: } ! 608: ! 609: return (error); ! 610: } ! 611: ! 612: /* ! 613: * Handle any kind of opaque data. ! 614: * arg1 points to it, arg2 is the size. ! 615: */ ! 616: ! 617: int ! 618: sysctl_handle_opaque SYSCTL_HANDLER_ARGS ! 619: { ! 620: int error; ! 621: ! 622: error = SYSCTL_OUT(req, arg1, arg2); ! 623: ! 624: if (error || !req->newptr) ! 625: return (error); ! 626: ! 627: error = SYSCTL_IN(req, arg1, arg2); ! 628: ! 629: return (error); ! 630: } ! 631: ! 632: /* ! 633: * Transfer functions to/from kernel space. ! 634: * XXX: rather untested at this point ! 635: */ ! 636: static int ! 637: sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) ! 638: { ! 639: size_t i = 0; ! 640: int error = 0; ! 641: ! 642: if (req->oldptr) { ! 643: i = l; ! 644: if (i > req->oldlen - req->oldidx) ! 645: i = req->oldlen - req->oldidx; ! 646: if (i > 0) { ! 647: error = copyout(p, (char *)req->oldptr + req->oldidx, i); ! 648: if (error) ! 649: return error; ! 650: } ! 651: } ! 652: req->oldidx += l; ! 653: if (req->oldptr && i != l) ! 654: return (ENOMEM); ! 655: return (0); ! 656: } ! 657: ! 658: static int ! 659: sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) ! 660: { ! 661: if (!req->newptr) ! 662: return 0; ! 663: if (req->newlen - req->newidx < l) ! 664: return (EINVAL); ! 665: copyin((char *)req->newptr + req->newidx, p, l); ! 666: req->newidx += l; ! 667: return (0); ! 668: } ! 669: ! 670: int ! 671: kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval) ! 672: { ! 673: int error = 0; ! 674: struct sysctl_req req; ! 675: ! 676: bzero(&req, sizeof req); ! 677: ! 678: req.p = p; ! 679: ! 680: if (oldlenp) { ! 681: req.oldlen = *oldlenp; ! 682: } ! 683: ! 684: if (old) { ! 685: req.oldptr= old; ! 686: } ! 687: ! 688: if (newlen) { ! 689: req.newlen = newlen; ! 690: req.newptr = new; ! 691: } ! 692: ! 693: req.oldfunc = sysctl_old_kernel; ! 694: req.newfunc = sysctl_new_kernel; ! 695: req.lock = 1; ! 696: ! 697: /* XXX this should probably be done in a general way */ ! 698: while (memlock.sl_lock) { ! 699: memlock.sl_want = 1; ! 700: (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); ! 701: memlock.sl_locked++; ! 702: } ! 703: memlock.sl_lock = 1; ! 704: ! 705: error = sysctl_root(0, name, namelen, &req); ! 706: ! 707: if (req.lock == 2) ! 708: vsunlock(req.oldptr, req.oldlen, B_WRITE); ! 709: ! 710: memlock.sl_lock = 0; ! 711: ! 712: if (memlock.sl_want) { ! 713: memlock.sl_want = 0; ! 714: wakeup((caddr_t)&memlock); ! 715: } ! 716: ! 717: if (error && error != ENOMEM) ! 718: return (error); ! 719: ! 720: if (retval) { ! 721: if (req.oldptr && req.oldidx > req.oldlen) ! 722: *retval = req.oldlen; ! 723: else ! 724: *retval = req.oldidx; ! 725: } ! 726: return (error); ! 727: } ! 728: ! 729: /* ! 730: * Transfer function to/from user space. ! 731: */ ! 732: static int ! 733: sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) ! 734: { ! 735: int error = 0; ! 736: size_t i = 0; ! 737: ! 738: if (req->oldptr) { ! 739: i = l; ! 740: if (i > req->oldlen - req->oldidx) ! 741: i = req->oldlen - req->oldidx; ! 742: if (i > 0) ! 743: error = copyout(p, (char *)req->oldptr + req->oldidx, ! 744: i); ! 745: } ! 746: req->oldidx += l; ! 747: if (error) ! 748: return (error); ! 749: if (req->oldptr && i < l) ! 750: return (ENOMEM); ! 751: return (0); ! 752: } ! 753: ! 754: static int ! 755: sysctl_new_user(struct sysctl_req *req, void *p, size_t l) ! 756: { ! 757: int error; ! 758: ! 759: if (!req->newptr) ! 760: return 0; ! 761: if (req->newlen - req->newidx < l) ! 762: return (EINVAL); ! 763: error = copyin((char *)req->newptr + req->newidx, p, l); ! 764: req->newidx += l; ! 765: return (error); ! 766: } ! 767: ! 768: /* ! 769: * Traverse our tree, and find the right node, execute whatever it points ! 770: * at, and return the resulting error code. ! 771: */ ! 772: ! 773: int ! 774: sysctl_root SYSCTL_HANDLER_ARGS ! 775: { ! 776: int *name = (int *) arg1; ! 777: u_int namelen = arg2; ! 778: int indx, i; ! 779: struct sysctl_oid *oid; ! 780: struct sysctl_oid_list *lsp = &sysctl__children; ! 781: ! 782: oid = SLIST_FIRST(lsp); ! 783: ! 784: indx = 0; ! 785: while (oid && indx < CTL_MAXNAME) { ! 786: if (oid->oid_number == name[indx]) { ! 787: indx++; ! 788: if (oid->oid_kind & CTLFLAG_NOLOCK) ! 789: req->lock = 0; ! 790: if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { ! 791: if (oid->oid_handler) ! 792: goto found; ! 793: if (indx == namelen) ! 794: return ENOENT; ! 795: lsp = (struct sysctl_oid_list *)oid->oid_arg1; ! 796: oid = SLIST_FIRST(lsp); ! 797: } else { ! 798: if (indx != namelen) ! 799: return EISDIR; ! 800: goto found; ! 801: } ! 802: } else { ! 803: oid = SLIST_NEXT(oid, oid_link); ! 804: } ! 805: } ! 806: return ENOENT; ! 807: found: ! 808: /* If writing isn't allowed */ ! 809: if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) || ! 810: ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) { ! 811: return (EPERM); ! 812: } ! 813: ! 814: ! 815: if (!oid->oid_handler) { ! 816: return EINVAL; ! 817: } ! 818: ! 819: if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { ! 820: i = (oid->oid_handler) (oid, ! 821: name + indx, namelen - indx, ! 822: req); ! 823: } else { ! 824: i = (oid->oid_handler) (oid, ! 825: oid->oid_arg1, oid->oid_arg2, ! 826: req); ! 827: } ! 828: return (i); ! 829: } ! 830: ! 831: #ifndef _SYS_SYSPROTO_H_ ! 832: struct sysctl_args { ! 833: int *name; ! 834: u_int namelen; ! 835: void *old; ! 836: size_t *oldlenp; ! 837: void *new; ! 838: size_t newlen; ! 839: }; ! 840: #endif ! 841: ! 842: int ! 843: /* __sysctl(struct proc *p, struct sysctl_args *uap) */ ! 844: new_sysctl(struct proc *p, struct sysctl_args *uap) ! 845: { ! 846: int error, i, name[CTL_MAXNAME]; ! 847: size_t j; ! 848: ! 849: if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) ! 850: return (EINVAL); ! 851: ! 852: error = copyin(uap->name, &name, uap->namelen * sizeof(int)); ! 853: if (error) ! 854: return (error); ! 855: ! 856: error = userland_sysctl(p, name, uap->namelen, ! 857: uap->old, uap->oldlenp, 0, ! 858: uap->new, uap->newlen, &j); ! 859: if (error && error != ENOMEM) ! 860: return (error); ! 861: if (uap->oldlenp) { ! 862: i = copyout(&j, uap->oldlenp, sizeof(j)); ! 863: if (i) ! 864: return (i); ! 865: } ! 866: return (error); ! 867: } ! 868: ! 869: /* ! 870: * This is used from various compatibility syscalls too. That's why name ! 871: * must be in kernel space. ! 872: */ ! 873: int ! 874: userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval) ! 875: { ! 876: int error = 0; ! 877: struct sysctl_req req, req2; ! 878: ! 879: bzero(&req, sizeof req); ! 880: ! 881: req.p = p; ! 882: ! 883: if (oldlenp) { ! 884: if (inkernel) { ! 885: req.oldlen = *oldlenp; ! 886: } else { ! 887: error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); ! 888: if (error) ! 889: return (error); ! 890: } ! 891: } ! 892: ! 893: if (old) { ! 894: req.oldptr= old; ! 895: } ! 896: ! 897: if (newlen) { ! 898: req.newlen = newlen; ! 899: req.newptr = new; ! 900: } ! 901: ! 902: req.oldfunc = sysctl_old_user; ! 903: req.newfunc = sysctl_new_user; ! 904: req.lock = 1; ! 905: ! 906: do { ! 907: req2 = req; ! 908: error = sysctl_root(0, name, namelen, &req2); ! 909: } while (error == EAGAIN); ! 910: ! 911: req = req2; ! 912: ! 913: if (error && error != ENOMEM) ! 914: return (error); ! 915: ! 916: if (retval) { ! 917: if (req.oldptr && req.oldidx > req.oldlen) ! 918: *retval = req.oldlen; ! 919: else ! 920: *retval = req.oldidx; ! 921: } ! 922: return (error); ! 923: } ! 924: #if 0 ! 925: ! 926: #if COMPAT_43 ! 927: #include <sys/socket.h> ! 928: #include <vm/vm_param.h> ! 929: ! 930: #define KINFO_PROC (0<<8) ! 931: #define KINFO_RT (1<<8) ! 932: #define KINFO_VNODE (2<<8) ! 933: #define KINFO_FILE (3<<8) ! 934: #define KINFO_METER (4<<8) ! 935: #define KINFO_LOADAVG (5<<8) ! 936: #define KINFO_CLOCKRATE (6<<8) ! 937: ! 938: /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ ! 939: #define KINFO_BSDI_SYSINFO (101<<8) ! 940: ! 941: /* ! 942: * XXX this is bloat, but I hope it's better here than on the potentially ! 943: * limited kernel stack... -Peter ! 944: */ ! 945: ! 946: static struct { ! 947: int bsdi_machine; /* "i386" on BSD/386 */ ! 948: /* ^^^ this is an offset to the string, relative to the struct start */ ! 949: char *pad0; ! 950: long pad1; ! 951: long pad2; ! 952: long pad3; ! 953: u_long pad4; ! 954: u_long pad5; ! 955: u_long pad6; ! 956: ! 957: int bsdi_ostype; /* "BSD/386" on BSD/386 */ ! 958: int bsdi_osrelease; /* "1.1" on BSD/386 */ ! 959: long pad7; ! 960: long pad8; ! 961: char *pad9; ! 962: ! 963: long pad10; ! 964: long pad11; ! 965: int pad12; ! 966: long pad13; ! 967: quad_t pad14; ! 968: long pad15; ! 969: ! 970: struct timeval pad16; ! 971: /* we dont set this, because BSDI's uname used gethostname() instead */ ! 972: int bsdi_hostname; /* hostname on BSD/386 */ ! 973: ! 974: /* the actual string data is appended here */ ! 975: ! 976: } bsdi_si; ! 977: /* ! 978: * this data is appended to the end of the bsdi_si structure during copyout. ! 979: * The "char *" offsets are relative to the base of the bsdi_si struct. ! 980: * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings ! 981: * should not exceed the length of the buffer here... (or else!! :-) ! 982: */ ! 983: static char bsdi_strings[80]; /* It had better be less than this! */ ! 984: ! 985: #ifndef _SYS_SYSPROTO_H_ ! 986: struct getkerninfo_args { ! 987: int op; ! 988: char *where; ! 989: size_t *size; ! 990: int arg; ! 991: }; ! 992: #endif ! 993: ! 994: int ! 995: ogetkerninfo(struct proc *p, struct getkerninfo_args *uap) ! 996: { ! 997: int error, name[6]; ! 998: size_t size; ! 999: ! 1000: switch (uap->op & 0xff00) { ! 1001: ! 1002: case KINFO_RT: ! 1003: name[0] = CTL_NET; ! 1004: name[1] = PF_ROUTE; ! 1005: name[2] = 0; ! 1006: name[3] = (uap->op & 0xff0000) >> 16; ! 1007: name[4] = uap->op & 0xff; ! 1008: name[5] = uap->arg; ! 1009: error = userland_sysctl(p, name, 6, uap->where, uap->size, ! 1010: 0, 0, 0, &size); ! 1011: break; ! 1012: ! 1013: case KINFO_VNODE: ! 1014: name[0] = CTL_KERN; ! 1015: name[1] = KERN_VNODE; ! 1016: error = userland_sysctl(p, name, 2, uap->where, uap->size, ! 1017: 0, 0, 0, &size); ! 1018: break; ! 1019: ! 1020: case KINFO_PROC: ! 1021: name[0] = CTL_KERN; ! 1022: name[1] = KERN_PROC; ! 1023: name[2] = uap->op & 0xff; ! 1024: name[3] = uap->arg; ! 1025: error = userland_sysctl(p, name, 4, uap->where, uap->size, ! 1026: 0, 0, 0, &size); ! 1027: break; ! 1028: ! 1029: case KINFO_FILE: ! 1030: name[0] = CTL_KERN; ! 1031: name[1] = KERN_FILE; ! 1032: error = userland_sysctl(p, name, 2, uap->where, uap->size, ! 1033: 0, 0, 0, &size); ! 1034: break; ! 1035: ! 1036: case KINFO_METER: ! 1037: name[0] = CTL_VM; ! 1038: name[1] = VM_METER; ! 1039: error = userland_sysctl(p, name, 2, uap->where, uap->size, ! 1040: 0, 0, 0, &size); ! 1041: break; ! 1042: ! 1043: case KINFO_LOADAVG: ! 1044: name[0] = CTL_VM; ! 1045: name[1] = VM_LOADAVG; ! 1046: error = userland_sysctl(p, name, 2, uap->where, uap->size, ! 1047: 0, 0, 0, &size); ! 1048: break; ! 1049: ! 1050: case KINFO_CLOCKRATE: ! 1051: name[0] = CTL_KERN; ! 1052: name[1] = KERN_CLOCKRATE; ! 1053: error = userland_sysctl(p, name, 2, uap->where, uap->size, ! 1054: 0, 0, 0, &size); ! 1055: break; ! 1056: ! 1057: case KINFO_BSDI_SYSINFO: { ! 1058: /* ! 1059: * this is pretty crude, but it's just enough for uname() ! 1060: * from BSDI's 1.x libc to work. ! 1061: * ! 1062: * In particular, it doesn't return the same results when ! 1063: * the supplied buffer is too small. BSDI's version apparently ! 1064: * will return the amount copied, and set the *size to how ! 1065: * much was needed. The emulation framework here isn't capable ! 1066: * of that, so we just set both to the amount copied. ! 1067: * BSDI's 2.x product apparently fails with ENOMEM in this ! 1068: * scenario. ! 1069: */ ! 1070: ! 1071: u_int needed; ! 1072: u_int left; ! 1073: char *s; ! 1074: ! 1075: bzero((char *)&bsdi_si, sizeof(bsdi_si)); ! 1076: bzero(bsdi_strings, sizeof(bsdi_strings)); ! 1077: ! 1078: s = bsdi_strings; ! 1079: ! 1080: bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); ! 1081: strcpy(s, ostype); ! 1082: s += strlen(s) + 1; ! 1083: ! 1084: bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); ! 1085: strcpy(s, osrelease); ! 1086: s += strlen(s) + 1; ! 1087: ! 1088: bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); ! 1089: strcpy(s, machine); ! 1090: s += strlen(s) + 1; ! 1091: ! 1092: needed = sizeof(bsdi_si) + (s - bsdi_strings); ! 1093: ! 1094: if (uap->where == NULL) { ! 1095: /* process is asking how much buffer to supply.. */ ! 1096: size = needed; ! 1097: error = 0; ! 1098: break; ! 1099: } ! 1100: ! 1101: ! 1102: /* if too much buffer supplied, trim it down */ ! 1103: if (size > needed) ! 1104: size = needed; ! 1105: ! 1106: /* how much of the buffer is remaining */ ! 1107: left = size; ! 1108: ! 1109: if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) ! 1110: break; ! 1111: ! 1112: /* is there any point in continuing? */ ! 1113: if (left > sizeof(bsdi_si)) { ! 1114: left -= sizeof(bsdi_si); ! 1115: error = copyout(&bsdi_strings, ! 1116: uap->where + sizeof(bsdi_si), left); ! 1117: } ! 1118: break; ! 1119: } ! 1120: ! 1121: default: ! 1122: return (EOPNOTSUPP); ! 1123: } ! 1124: if (error) ! 1125: return (error); ! 1126: p->p_retval[0] = size; ! 1127: if (uap->size) ! 1128: error = copyout((caddr_t)&size, (caddr_t)uap->size, ! 1129: sizeof(size)); ! 1130: return (error); ! 1131: } ! 1132: #endif /* COMPAT_43 */ ! 1133: ! 1134: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.