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