kern_sysctl.c revision 12152
1239310Sdim/*- 2239310Sdim * Copyright (c) 1982, 1986, 1989, 1993 3239310Sdim * The Regents of the University of California. All rights reserved. 4239310Sdim * 5239310Sdim * This code is derived from software contributed to Berkeley by 6239310Sdim * Mike Karels at Berkeley Software Design, Inc. 7239310Sdim * 8239310Sdim * Redistribution and use in source and binary forms, with or without 9239310Sdim * modification, are permitted provided that the following conditions 10239310Sdim * are met: 11239310Sdim * 1. Redistributions of source code must retain the above copyright 12239310Sdim * notice, this list of conditions and the following disclaimer. 13239310Sdim * 2. Redistributions in binary form must reproduce the above copyright 14239310Sdim * notice, this list of conditions and the following disclaimer in the 15239310Sdim * documentation and/or other materials provided with the distribution. 16239310Sdim * 3. All advertising materials mentioning features or use of this software 17249423Sdim * must display the following acknowledgement: 18249423Sdim * This product includes software developed by the University of 19239310Sdim * California, Berkeley and its contributors. 20263508Sdim * 4. Neither the name of the University nor the names of its contributors 21263508Sdim * may be used to endorse or promote products derived from this software 22249423Sdim * without specific prior written permission. 23239310Sdim * 24239310Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25263508Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26239310Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27239310Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28239310Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29263508Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30263508Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31263508Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32263508Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33263508Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34263508Sdim * SUCH DAMAGE. 35263508Sdim * 36263508Sdim * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 37263508Sdim * $Id: kern_sysctl.c,v 1.31 1995/11/06 16:18:52 phk Exp $ 38263508Sdim */ 39263508Sdim 40263508Sdim/* 41263508Sdim * sysctl system call. 42263508Sdim */ 43263508Sdim 44239310Sdim#include <sys/param.h> 45263508Sdim#include <sys/systm.h> 46263508Sdim#include <sys/kernel.h> 47263508Sdim#include <sys/malloc.h> 48263508Sdim#include <sys/proc.h> 49263508Sdim#include <sys/file.h> 50263508Sdim#include <sys/vnode.h> 51263508Sdim#include <sys/unistd.h> 52263508Sdim#include <sys/buf.h> 53239310Sdim#include <sys/ioctl.h> 54263508Sdim#include <sys/tty.h> 55263508Sdim#include <sys/conf.h> 56239310Sdim#include <vm/vm.h> 57263508Sdim#include <sys/sysctl.h> 58263508Sdim#include <sys/user.h> 59263508Sdim 60263508Sdimextern struct linker_set sysctl_; 61263508Sdim 62263508Sdim/* BEGIN_MIB */ 63263508SdimSYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, 64239310Sdim "Sysctl internal magic"); 65263508SdimSYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, 66263508Sdim "High kernel, proc, limits &c"); 67263508SdimSYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, 68263508Sdim "Virtual memory"); 69263508SdimSYSCTL_NODE(, CTL_FS, fs, CTLFLAG_RW, 0, 70263508Sdim "File system"); 71263508SdimSYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, 72263508Sdim "Network, (see socket.h)"); 73263508SdimSYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, 74263508Sdim "Debugging"); 75263508SdimSYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, 76263508Sdim "hardware"); 77263508SdimSYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, 78263508Sdim "machine dependent"); 79263508SdimSYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, 80263508Sdim "user-level"); 81263508Sdim 82239310SdimSYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, ""); 83263508Sdim 84263508SdimSYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, ""); 85239310Sdim 86263508SdimSYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, ""); 87263508Sdim 88263508SdimSYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, ""); 89263508Sdim 90263508Sdimextern int osreldate; 91263508SdimSYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, ""); 92263508Sdim 93239310SdimSYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 94263508Sdim 95263508SdimSYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, ""); 96263508Sdim 97239310SdimSYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, 98263508Sdim CTLFLAG_RD, &maxprocperuid, 0, ""); 99263508Sdim 100263508SdimSYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, 101263508Sdim CTLFLAG_RD, &maxfilesperproc, 0, ""); 102239310Sdim 103263508SdimSYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, ""); 104263508Sdim 105239310SdimSYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, ""); 106263508Sdim 107239310SdimSYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, ""); 108263508Sdim 109263508SdimSYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, ""); 110239310Sdim 111263508SdimSYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, ""); 112263508Sdim 113263508Sdim#ifdef _POSIX_SAVED_IDS 114263508SdimSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, ""); 115263508Sdim#else 116263508SdimSYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, ""); 117239310Sdim#endif 118263508Sdim 119263508Sdimchar kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ 120239310Sdim 121263508SdimSYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, 122263508Sdim CTLFLAG_RW, kernelname, sizeof kernelname, ""); 123263508Sdim 124239310SdimSYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, 125263508Sdim CTLFLAG_RW, &boottime, timeval, ""); 126263508Sdim 127263508SdimSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 128263508Sdim 129263508SdimSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 130263508Sdim 131263508SdimSYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, ""); 132263508Sdim 133263508SdimSYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, ""); 134263508Sdim 135263508SdimSYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, ""); 136263508Sdim 137263508Sdim/* END_MIB */ 138263508Sdim 139263508Sdimextern int vfs_update_wakeup; 140263508Sdimextern int vfs_update_interval; 141263508Sdimstatic int 142263508Sdimsysctl_kern_updateinterval SYSCTL_HANDLER_ARGS 143263508Sdim{ 144263508Sdim int error = sysctl_handle_int(oidp, 145239310Sdim oidp->oid_arg1, oidp->oid_arg2, 146263508Sdim oldp, oldlenp, newp, newlen); 147263508Sdim if (!error) 148239310Sdim wakeup(&vfs_update_wakeup); 149263508Sdim return error; 150263508Sdim} 151263508Sdim 152239310SdimSYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW, 153263508Sdim &vfs_update_interval, 0, sysctl_kern_updateinterval, ""); 154263508Sdim 155263508Sdim 156263508Sdimchar hostname[MAXHOSTNAMELEN]; 157239310Sdimint hostnamelen; 158263508Sdimstatic int 159263508Sdimsysctl_kern_hostname SYSCTL_HANDLER_ARGS 160249423Sdim{ 161263508Sdim int error = sysctl_handle_string(oidp, 162263508Sdim oidp->oid_arg1, oidp->oid_arg2, 163263508Sdim oldp, oldlenp, newp, newlen); 164263508Sdim if (newp && (error == 0 || error == ENOMEM)) 165239310Sdim hostnamelen = newlen; 166263508Sdim return error; 167263508Sdim} 168263508Sdim 169263508SdimSYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW, 170239310Sdim &hostname, sizeof(hostname), sysctl_kern_hostname, ""); 171263508Sdim 172263508Sdimstatic int 173263508Sdimsysctl_order_cmp(void *a, void *b) 174263508Sdim{ 175263508Sdim struct sysctl_oid **pa,**pb; 176239310Sdim pa = (struct sysctl_oid**) a; 177263508Sdim pb = (struct sysctl_oid**) b; 178263508Sdim if (!*pa) return 1; 179263508Sdim if (!*pb) return -1; 180263508Sdim return ((*pa)->oid_number - (*pb)->oid_number); 181263508Sdim} 182263508Sdim 183239310Sdimstatic void 184263508Sdimsysctl_order(void *arg) 185263508Sdim{ 186249423Sdim int j,k; 187263508Sdim struct linker_set *l = (struct linker_set *) arg; 188263508Sdim struct sysctl_oid **oidpp; 189263508Sdim 190263508Sdim j = l->ls_length; 191239310Sdim oidpp = (struct sysctl_oid **) l->ls_items; 192263508Sdim for (; j--; oidpp++) { 193263508Sdim if (!*oidpp) 194263508Sdim continue; 195239310Sdim if ((*oidpp)->oid_arg1 == arg) { 196263508Sdim *oidpp = 0; 197263508Sdim continue; 198263508Sdim } 199263508Sdim if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) 200263508Sdim if (!(*oidpp)->oid_handler) 201239310Sdim sysctl_order((*oidpp)->oid_arg1); 202263508Sdim } 203263508Sdim qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0], 204239310Sdim sysctl_order_cmp); 205263508Sdim} 206263508Sdim 207263508SdimSYSINIT(sysctl,SI_SUB_KMEM,SI_ORDER_ANY,sysctl_order,&sysctl_); 208263508Sdim 209263508Sdimstatic void 210263508Sdimsysctl_sysctl_debug_dump_node(struct linker_set *l,int i) 211263508Sdim{ 212239310Sdim int j,k; 213263508Sdim struct sysctl_oid **oidpp; 214263508Sdim 215263508Sdim j = l->ls_length; 216263508Sdim oidpp = (struct sysctl_oid **) l->ls_items; 217239310Sdim for (; j--; oidpp++) { 218263508Sdim 219263508Sdim if (!*oidpp) 220263508Sdim continue; 221263508Sdim 222263508Sdim for (k=0; k<i; k++) 223263508Sdim printf(" "); 224263508Sdim 225239310Sdim if ((*oidpp)->oid_number > 100) { 226263508Sdim printf("Junk! %p nm %x # %x k %x a1 %x a2 %x h %x\n", 227263508Sdim *oidpp, 228263508Sdim (*oidpp)->oid_number, (*oidpp)->oid_name, 229263508Sdim (*oidpp)->oid_kind, (*oidpp)->oid_arg1, 230239310Sdim (*oidpp)->oid_arg2, (*oidpp)->oid_handler); 231263508Sdim continue; 232263508Sdim } 233263508Sdim printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name); 234263508Sdim 235263508Sdim printf("%c%c", 236239310Sdim (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ', 237263508Sdim (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' '); 238263508Sdim 239263508Sdim switch ((*oidpp)->oid_kind & CTLTYPE) { 240263508Sdim case CTLTYPE_NODE: 241239310Sdim if ((*oidpp)->oid_handler) { 242263508Sdim printf(" Node(proc)\n"); 243263508Sdim } else { 244239310Sdim printf(" Node\n"); 245263508Sdim sysctl_sysctl_debug_dump_node( 246263508Sdim (*oidpp)->oid_arg1,i+2); 247263508Sdim } 248263508Sdim break; 249263508Sdim case CTLTYPE_INT: printf(" Int\n"); break; 250263508Sdim case CTLTYPE_STRING: printf(" String\n"); break; 251263508Sdim case CTLTYPE_QUAD: printf(" Quad\n"); break; 252263508Sdim case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 253239310Sdim default: printf("\n"); 254263508Sdim } 255263508Sdim 256263508Sdim } 257239310Sdim} 258263508Sdim 259263508Sdim 260239310Sdimstatic int 261263508Sdimsysctl_sysctl_debug SYSCTL_HANDLER_ARGS 262263508Sdim{ 263263508Sdim sysctl_sysctl_debug_dump_node(&sysctl_,0); 264249423Sdim return ENOENT; 265263508Sdim} 266263508Sdim 267263508SdimSYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 268263508Sdim 0, 0, sysctl_sysctl_debug, ""); 269239310Sdim 270263508Sdimchar domainname[MAXHOSTNAMELEN]; 271263508Sdimint domainnamelen; 272263508Sdimstatic int 273263508Sdimsysctl_kern_domainname SYSCTL_HANDLER_ARGS 274239310Sdim{ 275263508Sdim int error = sysctl_handle_string(oidp, 276263508Sdim oidp->oid_arg1, oidp->oid_arg2, 277263508Sdim oldp, oldlenp, newp, newlen); 278263508Sdim if (newp && (error == 0 || error == ENOMEM)) 279263508Sdim domainnamelen = newlen; 280263508Sdim return error; 281263508Sdim} 282239310Sdim 283263508SdimSYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW, 284263508Sdim &domainname, sizeof(domainname), sysctl_kern_domainname, ""); 285239310Sdim 286263508Sdimlong hostid; 287263508Sdim/* Some trouble here, if sizeof (int) != sizeof (long) */ 288239310SdimSYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, ""); 289263508Sdim 290263508Sdimint 291263508Sdimsysctl_handle_int SYSCTL_HANDLER_ARGS 292263508Sdim{ 293263508Sdim /* If there isn't sufficient space to return */ 294263508Sdim if (oldp && *oldlenp < sizeof(int)) 295263508Sdim return (ENOMEM); 296263508Sdim 297263508Sdim /* If it is a constant, don't write */ 298263508Sdim if (newp && !arg1) 299263508Sdim return (EPERM); 300263508Sdim 301263508Sdim /* If we get more than an int */ 302263508Sdim if (newp && newlen != sizeof(int)) 303263508Sdim return (EINVAL); 304263508Sdim 305263508Sdim *oldlenp = sizeof(int); 306263508Sdim if (oldp && arg1 ) 307263508Sdim bcopy(arg1, oldp, sizeof(int)); 308263508Sdim else if (oldp) 309263508Sdim bcopy(&arg2, oldp, sizeof(int)); 310263508Sdim if (newp) 311263508Sdim bcopy(newp, arg1, sizeof(int)); 312263508Sdim return (0); 313263508Sdim} 314263508Sdim 315263508Sdimint 316263508Sdimsysctl_handle_string SYSCTL_HANDLER_ARGS 317239310Sdim{ 318263508Sdim int len, error=0; 319263508Sdim char *str = (char *)arg1; 320263508Sdim 321263508Sdim len = strlen(str) + 1; 322263508Sdim 323239310Sdim if (oldp && *oldlenp < len) { 324263508Sdim len = *oldlenp; 325263508Sdim error=ENOMEM; 326263508Sdim } 327263508Sdim 328239310Sdim if (newp && newlen >= arg2) 329263508Sdim return (EINVAL); 330239310Sdim 331263508Sdim if (oldp) { 332263508Sdim *oldlenp = len; 333263508Sdim bcopy(str, oldp, len); 334239310Sdim } 335263508Sdim 336263508Sdim if (newp) { 337263508Sdim bcopy(newp, str, newlen); 338263508Sdim str[newlen] = 0; 339263508Sdim } 340263508Sdim return (error); 341239310Sdim} 342263508Sdim 343263508Sdimint 344239310Sdimsysctl_handle_opaque SYSCTL_HANDLER_ARGS 345263508Sdim{ 346239310Sdim if (oldp && *oldlenp < arg2) 347263508Sdim return (ENOMEM); 348263508Sdim 349263508Sdim if (newp && newlen != arg2) 350239310Sdim return (EINVAL); 351263508Sdim 352263508Sdim if (oldp) { 353263508Sdim *oldlenp = arg2; 354263508Sdim bcopy(arg1, oldp, arg2); 355239310Sdim } 356263508Sdim if (newp) 357263508Sdim bcopy(newp, arg1, arg2); 358263508Sdim return (0); 359263508Sdim} 360249423Sdim 361263508Sdim#ifdef DEBUG 362263508Sdimstatic sysctlfn debug_sysctl; 363263508Sdim#endif 364239310Sdim 365263508Sdim/* 366263508Sdim * Locking and stats 367263508Sdim */ 368263508Sdimstatic struct sysctl_lock { 369263508Sdim int sl_lock; 370263508Sdim int sl_want; 371263508Sdim int sl_locked; 372263508Sdim} memlock; 373263508Sdim 374239310Sdimstruct sysctl_args { 375263508Sdim int *name; 376263508Sdim u_int namelen; 377239310Sdim void *old; 378263508Sdim size_t *oldlenp; 379263508Sdim void *new; 380263508Sdim size_t newlen; 381263508Sdim}; 382263508Sdim 383263508Sdim 384263508Sdim 385263508Sdim/* 386239310Sdim * Traverse our tree, and find the right node, execute whatever it points 387263508Sdim * at, and return the resulting error code. 388263508Sdim * We work entirely in kernel-space at this time. 389263508Sdim */ 390239310Sdim 391263508Sdim 392263508Sdimint 393263508Sdimsysctl_root SYSCTL_HANDLER_ARGS 394239310Sdim{ 395263508Sdim int *name = (int *) arg1; 396263508Sdim int namelen = arg2; 397263508Sdim int indx, i, j; 398263508Sdim struct sysctl_oid **oidpp; 399263508Sdim struct linker_set *lsp = &sysctl_; 400239310Sdim 401263508Sdim j = lsp->ls_length; 402263508Sdim oidpp = (struct sysctl_oid **) lsp->ls_items; 403263508Sdim 404263508Sdim indx = 0; 405239310Sdim while (j-- && indx < CTL_MAXNAME) { 406263508Sdim if (*oidpp && ((*oidpp)->oid_number == name[indx])) { 407263508Sdim indx++; 408239310Sdim if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 409263508Sdim if ((*oidpp)->oid_handler) 410263508Sdim goto found; 411239310Sdim if (indx == namelen) 412263508Sdim return ENOENT; 413263508Sdim lsp = (struct linker_set*)(*oidpp)->oid_arg1; 414263508Sdim j = lsp->ls_length; 415239310Sdim oidpp = (struct sysctl_oid **)lsp->ls_items; 416263508Sdim } else { 417263508Sdim if (indx != namelen) 418263508Sdim return EISDIR; 419263508Sdim goto found; 420263508Sdim } 421239310Sdim } else { 422263508Sdim oidpp++; 423239310Sdim } 424263508Sdim } 425263508Sdim return EJUSTRETURN; 426263508Sdimfound: 427249423Sdim 428263508Sdim /* If writing isn't allowed */ 429263508Sdim if (newp && !((*oidpp)->oid_kind & CTLFLAG_WR)) 430263508Sdim return (EPERM); 431263508Sdim 432239310Sdim if (!(*oidpp)->oid_handler) 433263508Sdim return EINVAL; 434263508Sdim 435243830Sdim if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 436263508Sdim i = ((*oidpp)->oid_handler) (*oidpp, 437263508Sdim name + indx, namelen - indx, 438263508Sdim oldp, oldlenp, newp, newlen); 439263508Sdim } else { 440263508Sdim i = ((*oidpp)->oid_handler) (*oidpp, 441263508Sdim (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, 442239310Sdim oldp, oldlenp, newp, newlen); 443263508Sdim } 444263508Sdim return (i); 445263508Sdim} 446263508Sdim 447239310Sdimint 448263508Sdim__sysctl(p, uap, retval) 449263508Sdim struct proc *p; 450239310Sdim register struct sysctl_args *uap; 451263508Sdim int *retval; 452249423Sdim{ 453263508Sdim int error, dolock = 1, i; 454239310Sdim u_int savelen = 0, oldlen = 0; 455263508Sdim sysctlfn *fn; 456263508Sdim int name[CTL_MAXNAME]; 457263508Sdim void *oldp = 0; 458263508Sdim void *newp = 0; 459263508Sdim 460263508Sdim if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag))) 461263508Sdim return (error); 462263508Sdim 463263508Sdim /* 464263508Sdim * all top-level sysctl names are non-terminal 465263508Sdim */ 466263508Sdim 467263508Sdim if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 468263508Sdim return (EINVAL); 469263508Sdim 470263508Sdim error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 471263508Sdim if (error) 472239310Sdim return (error); 473263508Sdim 474239310Sdim if (uap->oldlenp && 475263508Sdim (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) 476263508Sdim return (error); 477239310Sdim 478263508Sdim if (uap->old) 479263508Sdim oldp = malloc(oldlen, M_TEMP, M_WAITOK); 480263508Sdim 481239310Sdim if (uap->newlen) { 482263508Sdim newp = malloc(uap->newlen, M_TEMP, M_WAITOK); 483263508Sdim error = copyin(uap->new, newp, uap->newlen); 484263508Sdim } 485263508Sdim if (error) { 486263508Sdim if (oldp) 487263508Sdim free(oldp, M_TEMP); 488263508Sdim if (newp) 489263508Sdim free(newp, M_TEMP); 490239310Sdim return error; 491263508Sdim } 492263508Sdim 493263508Sdim error = sysctl_root(0, name, uap->namelen, oldp, &oldlen, 494263508Sdim newp, uap->newlen); 495263508Sdim 496239310Sdim if (!error || error == ENOMEM) { 497263508Sdim if (uap->oldlenp) { 498263508Sdim i = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 499263508Sdim if (i) 500263508Sdim error = i; 501263508Sdim } 502263508Sdim if ((error == ENOMEM || !error ) && oldp) { 503263508Sdim i = copyout(oldp, uap->old, oldlen); 504263508Sdim if (i) 505263508Sdim error = i; 506239310Sdim free(oldp, M_TEMP); 507263508Sdim } 508263508Sdim if (newp) 509263508Sdim free(newp, M_TEMP); 510263508Sdim return (error); 511263508Sdim } 512263508Sdim 513263508Sdim if (oldp) 514263508Sdim free(oldp, M_TEMP); 515263508Sdim if (newp) 516263508Sdim free(newp, M_TEMP); 517263508Sdim 518263508Sdim switch (name[0]) { 519263508Sdim case CTL_KERN: 520263508Sdim fn = kern_sysctl; 521263508Sdim if (name[1] != KERN_VNODE) /* XXX */ 522239310Sdim dolock = 0; 523263508Sdim break; 524263508Sdim case CTL_HW: 525263508Sdim fn = hw_sysctl; 526263508Sdim break; 527239310Sdim case CTL_VM: 528263508Sdim fn = vm_sysctl; 529263508Sdim break; 530263508Sdim case CTL_NET: 531263508Sdim fn = net_sysctl; 532263508Sdim break; 533263508Sdim case CTL_FS: 534263508Sdim fn = fs_sysctl; 535239310Sdim break; 536263508Sdim case CTL_MACHDEP: 537263508Sdim fn = cpu_sysctl; 538263508Sdim break; 539263508Sdim#ifdef DEBUG 540239310Sdim case CTL_DEBUG: 541263508Sdim fn = debug_sysctl; 542263508Sdim break; 543263508Sdim#endif 544263508Sdim default: 545263508Sdim return (EOPNOTSUPP); 546263508Sdim } 547263508Sdim if (uap->old != NULL) { 548263508Sdim if (!useracc(uap->old, oldlen, B_WRITE)) 549263508Sdim return (EFAULT); 550263508Sdim while (memlock.sl_lock) { 551263508Sdim memlock.sl_want = 1; 552239310Sdim (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); 553263508Sdim memlock.sl_locked++; 554263508Sdim } 555263508Sdim memlock.sl_lock = 1; 556263508Sdim if (dolock) 557239310Sdim vslock(uap->old, oldlen); 558263508Sdim savelen = oldlen; 559263508Sdim } 560263508Sdim 561263508Sdim 562263508Sdim error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen, 563263508Sdim uap->new, uap->newlen, p); 564263508Sdim 565263508Sdim 566263508Sdim if (uap->old != NULL) { 567263508Sdim if (dolock) 568263508Sdim vsunlock(uap->old, savelen, B_WRITE); 569263508Sdim memlock.sl_lock = 0; 570251662Sdim if (memlock.sl_want) { 571263508Sdim memlock.sl_want = 0; 572263508Sdim wakeup((caddr_t)&memlock); 573263508Sdim } 574263508Sdim } 575239310Sdim#if 0 576263508Sdim if (error) { 577263508Sdim printf("SYSCTL_ERROR: "); 578239310Sdim for(i=0;i<uap->namelen;i++) 579263508Sdim printf("%d ", name[i]); 580263508Sdim printf("= %d\n", error); 581263508Sdim } 582263508Sdim#endif 583263508Sdim if (error) 584263508Sdim return (error); 585263508Sdim if (uap->oldlenp) 586263508Sdim error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 587239310Sdim *retval = oldlen; 588263508Sdim return (0); 589263508Sdim} 590263508Sdim 591263508Sdim/* 592239310Sdim * Attributes stored in the kernel. 593263508Sdim */ 594263508Sdimint securelevel = -1; 595263508Sdim 596263508Sdim/* 597263508Sdim * kernel related system variables. 598239310Sdim */ 599263508Sdimint 600263508Sdimkern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 601263508Sdim int *name; 602239310Sdim u_int namelen; 603263508Sdim void *oldp; 604263508Sdim size_t *oldlenp; 605263508Sdim void *newp; 606263508Sdim size_t newlen; 607263508Sdim struct proc *p; 608239310Sdim{ 609263508Sdim int error, level; 610263508Sdim dev_t ndumpdev; 611239310Sdim 612263508Sdim /* all sysctl names at this level are terminal */ 613263508Sdim if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF 614263508Sdim || name[0] == KERN_NTP_PLL)) 615263508Sdim return (ENOTDIR); /* overloaded */ 616263508Sdim 617263508Sdim switch (name[0]) { 618263508Sdim 619263508Sdim case KERN_SECURELVL: 620263508Sdim level = securelevel; 621239310Sdim if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 622263508Sdim newp == NULL) 623263508Sdim return (error); 624263508Sdim if (level < securelevel && p->p_pid != 1) 625263508Sdim return (EPERM); 626239310Sdim securelevel = level; 627263508Sdim return (0); 628263508Sdim case KERN_VNODE: 629263508Sdim return (sysctl_vnode(oldp, oldlenp)); 630239310Sdim case KERN_PROC: 631263508Sdim return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 632263508Sdim case KERN_FILE: 633263508Sdim return (sysctl_file(oldp, oldlenp)); 634263508Sdim#ifdef GPROF 635239310Sdim case KERN_PROF: 636263508Sdim return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 637263508Sdim newp, newlen)); 638239310Sdim#endif 639263508Sdim case KERN_NTP_PLL: 640263508Sdim return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp, 641239310Sdim newp, newlen, p)); 642263508Sdim case KERN_DUMPDEV: 643263508Sdim ndumpdev = dumpdev; 644239310Sdim error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev, 645263508Sdim sizeof ndumpdev); 646239310Sdim if (!error && ndumpdev != dumpdev) { 647263508Sdim error = setdumpdev(ndumpdev); 648263508Sdim } 649263508Sdim return error; 650239310Sdim default: 651263508Sdim return (EOPNOTSUPP); 652263508Sdim } 653263508Sdim /* NOTREACHED */ 654239310Sdim} 655263508Sdim 656263508Sdim/* 657263508Sdim * hardware related system variables. 658239310Sdim */ 659263508Sdimint 660263508Sdimhw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 661263508Sdim int *name; 662263508Sdim u_int namelen; 663263508Sdim void *oldp; 664263508Sdim size_t *oldlenp; 665263508Sdim void *newp; 666263508Sdim size_t newlen; 667263508Sdim struct proc *p; 668263508Sdim{ 669263508Sdim /* almost all sysctl names at this level are terminal */ 670263508Sdim if (namelen != 1 && name[0] != HW_DEVCONF) 671263508Sdim return (ENOTDIR); /* overloaded */ 672263508Sdim 673263508Sdim switch (name[0]) { 674263508Sdim case HW_PHYSMEM: 675263508Sdim return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 676263508Sdim case HW_USERMEM: 677263508Sdim return (sysctl_rdint(oldp, oldlenp, newp, 678263508Sdim ctob(physmem - cnt.v_wire_count))); 679263508Sdim case HW_DEVCONF: 680263508Sdim return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp, 681263508Sdim newp, newlen, p)); 682263508Sdim default: 683263508Sdim return (EOPNOTSUPP); 684263508Sdim } 685263508Sdim /* NOTREACHED */ 686263508Sdim} 687263508Sdim 688263508Sdim#ifdef DEBUG 689263508Sdim/* 690263508Sdim * Debugging related system variables. 691263508Sdim */ 692263508Sdimstruct ctldebug debug0, debug1, debug2, debug3, debug4; 693263508Sdimstruct ctldebug debug5, debug6, debug7, debug8, debug9; 694263508Sdimstruct ctldebug debug10, debug11, debug12, debug13, debug14; 695263508Sdimstruct ctldebug debug15, debug16, debug17, debug18, debug19; 696263508Sdimstatic struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 697263508Sdim &debug0, &debug1, &debug2, &debug3, &debug4, 698263508Sdim &debug5, &debug6, &debug7, &debug8, &debug9, 699263508Sdim &debug10, &debug11, &debug12, &debug13, &debug14, 700263508Sdim &debug15, &debug16, &debug17, &debug18, &debug19, 701263508Sdim}; 702263508Sdimstatic int 703263508Sdimdebug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 704263508Sdim int *name; 705263508Sdim u_int namelen; 706263508Sdim void *oldp; 707263508Sdim size_t *oldlenp; 708263508Sdim void *newp; 709263508Sdim size_t newlen; 710263508Sdim struct proc *p; 711263508Sdim{ 712263508Sdim struct ctldebug *cdp; 713263508Sdim 714263508Sdim /* all sysctl names at this level are name and field */ 715263508Sdim if (namelen != 2) 716263508Sdim return (ENOTDIR); /* overloaded */ 717263508Sdim cdp = debugvars[name[0]]; 718263508Sdim if (cdp->debugname == 0) 719263508Sdim return (EOPNOTSUPP); 720263508Sdim switch (name[1]) { 721263508Sdim case CTL_DEBUG_NAME: 722263508Sdim return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 723263508Sdim case CTL_DEBUG_VALUE: 724263508Sdim return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 725263508Sdim default: 726263508Sdim return (EOPNOTSUPP); 727263508Sdim } 728263508Sdim /* NOTREACHED */ 729263508Sdim} 730263508Sdim#endif /* DEBUG */ 731263508Sdim 732263508Sdim/* 733263508Sdim * Validate parameters and get old / set new parameters 734263508Sdim * for an integer-valued sysctl function. 735263508Sdim */ 736263508Sdimint 737263508Sdimsysctl_int(oldp, oldlenp, newp, newlen, valp) 738263508Sdim void *oldp; 739263508Sdim size_t *oldlenp; 740263508Sdim void *newp; 741263508Sdim size_t newlen; 742263508Sdim int *valp; 743263508Sdim{ 744263508Sdim int error = 0; 745263508Sdim 746263508Sdim if (oldp && *oldlenp < sizeof(int)) 747263508Sdim return (ENOMEM); 748263508Sdim if (newp && newlen != sizeof(int)) 749263508Sdim return (EINVAL); 750263508Sdim *oldlenp = sizeof(int); 751263508Sdim if (oldp) 752263508Sdim error = copyout(valp, oldp, sizeof(int)); 753263508Sdim if (error == 0 && newp) 754263508Sdim error = copyin(newp, valp, sizeof(int)); 755263508Sdim return (error); 756263508Sdim} 757263508Sdim 758263508Sdim/* 759263508Sdim * As above, but read-only. 760263508Sdim */ 761263508Sdimint 762263508Sdimsysctl_rdint(oldp, oldlenp, newp, val) 763263508Sdim void *oldp; 764263508Sdim size_t *oldlenp; 765263508Sdim void *newp; 766263508Sdim int val; 767263508Sdim{ 768263508Sdim int error = 0; 769263508Sdim 770263508Sdim if (oldp && *oldlenp < sizeof(int)) 771263508Sdim return (ENOMEM); 772263508Sdim if (newp) 773263508Sdim return (EPERM); 774263508Sdim *oldlenp = sizeof(int); 775263508Sdim if (oldp) 776263508Sdim error = copyout((caddr_t)&val, oldp, sizeof(int)); 777263508Sdim return (error); 778263508Sdim} 779263508Sdim 780263508Sdim/* 781263508Sdim * Validate parameters and get old / set new parameters 782263508Sdim * for a string-valued sysctl function. 783263508Sdim */ 784263508Sdimint 785263508Sdimsysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 786263508Sdim void *oldp; 787263508Sdim size_t *oldlenp; 788263508Sdim void *newp; 789263508Sdim size_t newlen; 790263508Sdim char *str; 791263508Sdim int maxlen; 792263508Sdim{ 793263508Sdim int len, error = 0, rval = 0; 794263508Sdim 795263508Sdim len = strlen(str) + 1; 796263508Sdim if (oldp && *oldlenp < len) { 797263508Sdim len = *oldlenp; 798263508Sdim rval = ENOMEM; 799263508Sdim } 800263508Sdim if (newp && newlen >= maxlen) 801263508Sdim return (EINVAL); 802263508Sdim if (oldp) { 803263508Sdim *oldlenp = len; 804263508Sdim error = copyout(str, oldp, len); 805263508Sdim if (error) 806263508Sdim rval = error; 807263508Sdim } 808263508Sdim if ((error == 0 || error == ENOMEM) && newp) { 809263508Sdim error = copyin(newp, str, newlen); 810263508Sdim if (error) 811263508Sdim rval = error; 812263508Sdim str[newlen] = 0; 813263508Sdim } 814263508Sdim return (rval); 815263508Sdim} 816263508Sdim 817263508Sdim/* 818263508Sdim * As above, but read-only. 819263508Sdim */ 820263508Sdimint 821263508Sdimsysctl_rdstring(oldp, oldlenp, newp, str) 822263508Sdim void *oldp; 823263508Sdim size_t *oldlenp; 824263508Sdim void *newp; 825263508Sdim char *str; 826263508Sdim{ 827263508Sdim int len, error = 0, rval = 0; 828263508Sdim 829263508Sdim len = strlen(str) + 1; 830263508Sdim if (oldp && *oldlenp < len) { 831263508Sdim len = *oldlenp; 832263508Sdim rval = ENOMEM; 833263508Sdim } 834263508Sdim if (newp) 835263508Sdim return (EPERM); 836263508Sdim *oldlenp = len; 837263508Sdim if (oldp) 838263508Sdim error = copyout(str, oldp, len); 839263508Sdim if (error) 840263508Sdim rval = error; 841263508Sdim return (rval); 842263508Sdim} 843263508Sdim 844263508Sdim/* 845263508Sdim * Validate parameters and get old / set new parameters 846263508Sdim * for a structure oriented sysctl function. 847263508Sdim */ 848239310Sdimint 849239310Sdimsysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 850239310Sdim void *oldp; 851 size_t *oldlenp; 852 void *newp; 853 size_t newlen; 854 void *sp; 855 int len; 856{ 857 int error = 0; 858 859 if (oldp && *oldlenp < len) 860 return (ENOMEM); 861 if (newp && newlen > len) 862 return (EINVAL); 863 if (oldp) { 864 *oldlenp = len; 865 error = copyout(sp, oldp, len); 866 } 867 if (error == 0 && newp) 868 error = copyin(newp, sp, len); 869 return (error); 870} 871 872/* 873 * Validate parameters and get old parameters 874 * for a structure oriented sysctl function. 875 */ 876int 877sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 878 void *oldp; 879 size_t *oldlenp; 880 void *newp, *sp; 881 int len; 882{ 883 int error = 0; 884 885 if (oldp && *oldlenp < len) 886 return (ENOMEM); 887 if (newp) 888 return (EPERM); 889 *oldlenp = len; 890 if (oldp) 891 error = copyout(sp, oldp, len); 892 return (error); 893} 894 895/* 896 * Get file structures. 897 */ 898int 899sysctl_file(where, sizep) 900 char *where; 901 size_t *sizep; 902{ 903 int buflen, error; 904 struct file *fp; 905 char *start = where; 906 907 buflen = *sizep; 908 if (where == NULL) { 909 /* 910 * overestimate by 10 files 911 */ 912 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 913 return (0); 914 } 915 916 /* 917 * first copyout filehead 918 */ 919 if (buflen < sizeof(filehead)) { 920 *sizep = 0; 921 return (0); 922 } 923 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 924 if (error) 925 return (error); 926 buflen -= sizeof(filehead); 927 where += sizeof(filehead); 928 929 /* 930 * followed by an array of file structures 931 */ 932 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 933 if (buflen < sizeof(struct file)) { 934 *sizep = where - start; 935 return (ENOMEM); 936 } 937 error = copyout((caddr_t)fp, where, sizeof (struct file)); 938 if (error) 939 return (error); 940 buflen -= sizeof(struct file); 941 where += sizeof(struct file); 942 } 943 *sizep = where - start; 944 return (0); 945} 946 947/* 948 * try over estimating by 5 procs 949 */ 950#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 951 952int 953sysctl_doproc(name, namelen, where, sizep) 954 int *name; 955 u_int namelen; 956 char *where; 957 size_t *sizep; 958{ 959 register struct proc *p; 960 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 961 register int needed = 0; 962 int buflen = where != NULL ? *sizep : 0; 963 int doingzomb; 964 struct eproc eproc; 965 int error = 0; 966 967 if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 968 return (EINVAL); 969 p = (struct proc *)allproc; 970 doingzomb = 0; 971again: 972 for (; p != NULL; p = p->p_next) { 973 /* 974 * Skip embryonic processes. 975 */ 976 if (p->p_stat == SIDL) 977 continue; 978 /* 979 * TODO - make more efficient (see notes below). 980 * do by session. 981 */ 982 switch (name[0]) { 983 984 case KERN_PROC_PID: 985 /* could do this with just a lookup */ 986 if (p->p_pid != (pid_t)name[1]) 987 continue; 988 break; 989 990 case KERN_PROC_PGRP: 991 /* could do this by traversing pgrp */ 992 if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1]) 993 continue; 994 break; 995 996 case KERN_PROC_TTY: 997 if ((p->p_flag & P_CONTROLT) == 0 || 998 p->p_session == NULL || 999 p->p_session->s_ttyp == NULL || 1000 p->p_session->s_ttyp->t_dev != (dev_t)name[1]) 1001 continue; 1002 break; 1003 1004 case KERN_PROC_UID: 1005 if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1]) 1006 continue; 1007 break; 1008 1009 case KERN_PROC_RUID: 1010 if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1]) 1011 continue; 1012 break; 1013 } 1014 if (buflen >= sizeof(struct kinfo_proc)) { 1015 fill_eproc(p, &eproc); 1016 error = copyout((caddr_t)p, &dp->kp_proc, 1017 sizeof(struct proc)); 1018 if (error) 1019 return (error); 1020 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 1021 sizeof(eproc)); 1022 if (error) 1023 return (error); 1024 dp++; 1025 buflen -= sizeof(struct kinfo_proc); 1026 } 1027 needed += sizeof(struct kinfo_proc); 1028 } 1029 if (doingzomb == 0) { 1030 p = zombproc; 1031 doingzomb++; 1032 goto again; 1033 } 1034 if (where != NULL) { 1035 *sizep = (caddr_t)dp - where; 1036 if (needed > *sizep) 1037 return (ENOMEM); 1038 } else { 1039 needed += KERN_PROCSLOP; 1040 *sizep = needed; 1041 } 1042 return (0); 1043} 1044 1045/* 1046 * Fill in an eproc structure for the specified process. 1047 */ 1048void 1049fill_eproc(p, ep) 1050 register struct proc *p; 1051 register struct eproc *ep; 1052{ 1053 register struct tty *tp; 1054 1055 bzero(ep, sizeof(*ep)); 1056 1057 ep->e_paddr = p; 1058 if (p->p_cred) { 1059 ep->e_pcred = *p->p_cred; 1060 if (p->p_ucred) 1061 ep->e_ucred = *p->p_ucred; 1062 } 1063 if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) { 1064 register struct vmspace *vm = p->p_vmspace; 1065 1066#ifdef pmap_resident_count 1067 ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/ 1068#else 1069 ep->e_vm.vm_rssize = vm->vm_rssize; 1070#endif 1071 ep->e_vm.vm_tsize = vm->vm_tsize; 1072 ep->e_vm.vm_dsize = vm->vm_dsize; 1073 ep->e_vm.vm_ssize = vm->vm_ssize; 1074#ifndef sparc 1075 ep->e_vm.vm_pmap = vm->vm_pmap; 1076#endif 1077 } 1078 if (p->p_pptr) 1079 ep->e_ppid = p->p_pptr->p_pid; 1080 if (p->p_pgrp) { 1081 ep->e_sess = p->p_pgrp->pg_session; 1082 ep->e_pgid = p->p_pgrp->pg_id; 1083 ep->e_jobc = p->p_pgrp->pg_jobc; 1084 } 1085 if ((p->p_flag & P_CONTROLT) && 1086 (ep->e_sess != NULL) && 1087 ((tp = ep->e_sess->s_ttyp) != NULL)) { 1088 ep->e_tdev = tp->t_dev; 1089 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1090 ep->e_tsess = tp->t_session; 1091 } else 1092 ep->e_tdev = NODEV; 1093 if (ep->e_sess && ep->e_sess->s_ttyvp) 1094 ep->e_flag = EPROC_CTTY; 1095 if (SESS_LEADER(p)) 1096 ep->e_flag |= EPROC_SLEADER; 1097 if (p->p_wmesg) { 1098 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 1099 ep->e_wmesg[WMESGLEN] = 0; 1100 } 1101} 1102 1103#ifdef COMPAT_43 1104#include <sys/socket.h> 1105#define KINFO_PROC (0<<8) 1106#define KINFO_RT (1<<8) 1107#define KINFO_VNODE (2<<8) 1108#define KINFO_FILE (3<<8) 1109#define KINFO_METER (4<<8) 1110#define KINFO_LOADAVG (5<<8) 1111#define KINFO_CLOCKRATE (6<<8) 1112 1113/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 1114#define KINFO_BSDI_SYSINFO (101<<8) 1115 1116/* 1117 * XXX this is bloat, but I hope it's better here than on the potentially 1118 * limited kernel stack... -Peter 1119 */ 1120 1121struct { 1122 int bsdi_machine; /* "i386" on BSD/386 */ 1123/* ^^^ this is an offset to the string, relative to the struct start */ 1124 char *pad0; 1125 long pad1; 1126 long pad2; 1127 long pad3; 1128 u_long pad4; 1129 u_long pad5; 1130 u_long pad6; 1131 1132 int bsdi_ostype; /* "BSD/386" on BSD/386 */ 1133 int bsdi_osrelease; /* "1.1" on BSD/386 */ 1134 long pad7; 1135 long pad8; 1136 char *pad9; 1137 1138 long pad10; 1139 long pad11; 1140 int pad12; 1141 long pad13; 1142 quad_t pad14; 1143 long pad15; 1144 1145 struct timeval pad16; 1146 /* we dont set this, because BSDI's uname used gethostname() instead */ 1147 int bsdi_hostname; /* hostname on BSD/386 */ 1148 1149 /* the actual string data is appended here */ 1150 1151} bsdi_si; 1152/* 1153 * this data is appended to the end of the bsdi_si structure during copyout. 1154 * The "char *" offsets are relative to the base of the bsdi_si struct. 1155 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings 1156 * should not exceed the length of the buffer here... (or else!! :-) 1157 */ 1158char bsdi_strings[80]; /* It had better be less than this! */ 1159 1160struct getkerninfo_args { 1161 int op; 1162 char *where; 1163 int *size; 1164 int arg; 1165}; 1166 1167int 1168ogetkerninfo(p, uap, retval) 1169 struct proc *p; 1170 register struct getkerninfo_args *uap; 1171 int *retval; 1172{ 1173 int error, name[5]; 1174 u_int size; 1175 1176 if (uap->size && 1177 (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))) 1178 return (error); 1179 1180 switch (uap->op & 0xff00) { 1181 1182 case KINFO_RT: 1183 name[0] = PF_ROUTE; 1184 name[1] = 0; 1185 name[2] = (uap->op & 0xff0000) >> 16; 1186 name[3] = uap->op & 0xff; 1187 name[4] = uap->arg; 1188 error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p); 1189 break; 1190 1191 case KINFO_VNODE: 1192 name[0] = KERN_VNODE; 1193 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 1194 break; 1195 1196 case KINFO_PROC: 1197 name[0] = KERN_PROC; 1198 name[1] = uap->op & 0xff; 1199 name[2] = uap->arg; 1200 error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p); 1201 break; 1202 1203 case KINFO_FILE: 1204 name[0] = KERN_FILE; 1205 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 1206 break; 1207 1208 case KINFO_METER: 1209 name[0] = VM_METER; 1210 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 1211 break; 1212 1213 case KINFO_LOADAVG: 1214 name[0] = VM_LOADAVG; 1215 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p); 1216 break; 1217 1218 case KINFO_CLOCKRATE: 1219 name[0] = KERN_CLOCKRATE; 1220 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p); 1221 break; 1222 1223 case KINFO_BSDI_SYSINFO: { 1224 /* 1225 * this is pretty crude, but it's just enough for uname() 1226 * from BSDI's 1.x libc to work. 1227 * 1228 * In particular, it doesn't return the same results when 1229 * the supplied buffer is too small. BSDI's version apparently 1230 * will return the amount copied, and set the *size to how 1231 * much was needed. The emulation framework here isn't capable 1232 * of that, so we just set both to the amount copied. 1233 * BSDI's 2.x product apparently fails with ENOMEM in this 1234 * scenario. 1235 */ 1236 1237 u_int needed; 1238 u_int left; 1239 char *s; 1240 1241 bzero((char *)&bsdi_si, sizeof(bsdi_si)); 1242 bzero(bsdi_strings, sizeof(bsdi_strings)); 1243 1244 s = bsdi_strings; 1245 1246 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); 1247 strcpy(s, ostype); 1248 s += strlen(s) + 1; 1249 1250 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); 1251 strcpy(s, osrelease); 1252 s += strlen(s) + 1; 1253 1254 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); 1255 strcpy(s, machine); 1256 s += strlen(s) + 1; 1257 1258 needed = sizeof(bsdi_si) + (s - bsdi_strings); 1259 1260 if (uap->where == NULL) { 1261 /* process is asking how much buffer to supply.. */ 1262 size = needed; 1263 error = 0; 1264 break; 1265 } 1266 1267 1268 /* if too much buffer supplied, trim it down */ 1269 if (size > needed) 1270 size = needed; 1271 1272 /* how much of the buffer is remaining */ 1273 left = size; 1274 1275 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) 1276 break; 1277 1278 /* is there any point in continuing? */ 1279 if (left > sizeof(bsdi_si)) { 1280 left -= sizeof(bsdi_si); 1281 error = copyout(&bsdi_strings, 1282 uap->where + sizeof(bsdi_si), left); 1283 } 1284 break; 1285 } 1286 1287 default: 1288 return (EOPNOTSUPP); 1289 } 1290 if (error) 1291 return (error); 1292 *retval = size; 1293 if (uap->size) 1294 error = copyout((caddr_t)&size, (caddr_t)uap->size, 1295 sizeof(size)); 1296 return (error); 1297} 1298#endif /* COMPAT_43 */ 1299