void sysctl_register_oid(struct sysctl_oid *oidp) { sysctl_lock(LK_EXCLUSIVE); sysctl_register_oid_int(oidp); sysctl_unlock(); }
int netbsd32___sysctl(struct lwp *l, const struct netbsd32___sysctl_args *uap, register_t *retval) { /* { syscallarg(netbsd32_intp) name; syscallarg(u_int) namelen; syscallarg(netbsd32_voidp) old; syscallarg(netbsd32_size_tp) oldlenp; syscallarg(netbsd32_voidp) new; syscallarg(netbsd32_size_t) newlen; } */ const struct sysctlnode *pnode; netbsd32_size_t netbsd32_oldlen; size_t oldlen, *oldlenp, savelen; int name[CTL_MAXNAME], error, nerror, *namep; void *newp, *oldp; /* * get and convert 32 bit size_t to native size_t */ namep = SCARG_P32(uap, name); oldp = SCARG_P32(uap, oldv); newp = SCARG_P32(uap, newv); oldlenp = SCARG_P32(uap, oldlenp); oldlen = 0; if (oldlenp != NULL) { error = copyin(oldlenp, &netbsd32_oldlen, sizeof(netbsd32_oldlen)); if (error) return (error); oldlen = netbsd32_oldlen; } savelen = oldlen; /* * retrieve name and see if we need to dispatch this query to * the shadow tree. if we find it in the shadow tree, * dispatch to there, otherwise NULL means use the built-in * default main tree. */ if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 1) return (EINVAL); error = copyin(namep, &name[0], SCARG(uap, namelen) * sizeof(int)); if (error) return (error); ktrmib(name, SCARG(uap, namelen)); sysctl_lock(newp != NULL); pnode = &netbsd32_sysctl_root; error = sysctl_locate(l, &name[0], SCARG(uap, namelen), &pnode, NULL); pnode = (error == 0) ? &netbsd32_sysctl_root : NULL; error = sysctl_dispatch(&name[0], SCARG(uap, namelen), oldp, &oldlen, newp, SCARG(uap, newlen), &name[0], l, pnode); sysctl_unlock(); /* * reset caller's oldlen, even if we got an error */ if (oldlenp) { netbsd32_oldlen = oldlen; nerror = copyout(&netbsd32_oldlen, oldlenp, sizeof(netbsd32_oldlen)); if (error == 0) error = nerror; } /* * if the only problem is that we weren't given enough space, * that's an ENOMEM error */ if (error == 0 && oldp != NULL && savelen < oldlen) error = ENOMEM; return (error); }
/* * linux sysctl system call */ int linux_sys___sysctl(struct lwp *l, const struct linux_sys___sysctl_args *uap, register_t *retval) { struct linux___sysctl ls; int error, nerror, name[CTL_MAXNAME]; size_t savelen = 0, oldlen = 0; /* * get linux args structure */ if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls)))) return error; /* * get oldlen */ oldlen = 0; if (ls.oldlenp != NULL) { error = copyin(ls.oldlenp, &oldlen, sizeof(oldlen)); if (error) return (error); } savelen = oldlen; /* * top-level sysctl names may or may not be non-terminal, but * we don't care */ if (ls.nlen > CTL_MAXNAME || ls.nlen < 1) return (ENOTDIR); error = copyin(ls.name, &name, ls.nlen * sizeof(int)); if (error) return (error); ktrmib(name, ls.nlen); /* * dispatch request into linux sysctl tree */ sysctl_lock(ls.newval != NULL); error = sysctl_dispatch(&name[0], ls.nlen, ls.oldval, &oldlen, ls.newval, ls.newlen, &name[0], l, &linux_sysctl_root); sysctl_unlock(); /* * reset caller's oldlen, even if we got an error */ if (ls.oldlenp) { nerror = copyout(&oldlen, ls.oldlenp, sizeof(oldlen)); if (error == 0) error = nerror; } /* * if the only problem is that we weren't given enough space, * that's an ENOMEM error */ if (error == 0 && ls.oldval != NULL && savelen < oldlen) error = ENOMEM; return (error); }
/* * Linux compatible /proc/version. Only active when the -o linux * mountflag is used. */ int procfs_doversion(struct lwp *curl, struct proc *p, struct pfsnode *pfs, struct uio *uio) { char *bf; char lostype[20], losrelease[20], lversion[80]; const char *postype, *posrelease, *pversion; const char *emulname = curlwp->l_proc->p_emul->e_name; int len; int error = 0; int nm[4]; size_t buflen; CTASSERT(EMUL_LINUX_KERN_OSTYPE == EMUL_LINUX32_KERN_OSTYPE); CTASSERT(EMUL_LINUX_KERN_OSRELEASE == EMUL_LINUX32_KERN_OSRELEASE); CTASSERT(EMUL_LINUX_KERN_VERSION == EMUL_LINUX32_KERN_VERSION); bf = malloc(LBFSZ, M_TEMP, M_WAITOK); sysctl_lock(false); if (strncmp(emulname, "linux", 5) == 0) { /* * Lookup the emulation ostype, osrelease, and version. * Since compat_linux and compat_linux32 can be built as * modules, we use sysctl to obtain the values instead of * using the symbols directly. */ if (strcmp(emulname, "linux32") == 0) { nm[0] = CTL_EMUL; nm[1] = EMUL_LINUX32; nm[2] = EMUL_LINUX32_KERN; } else { nm[0] = CTL_EMUL; nm[1] = EMUL_LINUX; nm[2] = EMUL_LINUX_KERN; } nm[3] = EMUL_LINUX_KERN_OSTYPE; buflen = sizeof(lostype); error = sysctl_dispatch(nm, __arraycount(nm), lostype, &buflen, NULL, 0, NULL, NULL, NULL); if (error) goto out; nm[3] = EMUL_LINUX_KERN_OSRELEASE; buflen = sizeof(losrelease); error = sysctl_dispatch(nm, __arraycount(nm), losrelease, &buflen, NULL, 0, NULL, NULL, NULL); if (error) goto out; nm[3] = EMUL_LINUX_KERN_VERSION; buflen = sizeof(lversion); error = sysctl_dispatch(nm, __arraycount(nm), lversion, &buflen, NULL, 0, NULL, NULL, NULL); if (error) goto out; postype = lostype; posrelease = losrelease; pversion = lversion; } else { postype = ostype; posrelease = osrelease; strlcpy(lversion, version, sizeof(lversion)); if (strchr(lversion, '\n')) *strchr(lversion, '\n') = '\0'; pversion = lversion; } len = snprintf(bf, LBFSZ, "%s version %s (%s@localhost) (gcc version %s) %s\n", postype, posrelease, emulname, #ifdef __VERSION__ __VERSION__, #else "unknown", #endif pversion); if (len == 0) goto out; error = uiomove_frombuf(bf, len, uio); out: free(bf, M_TEMP); sysctl_unlock(); return error; }
int linux32_sys___sysctl(struct lwp *l, const struct linux32_sys___sysctl_args *uap, register_t *retval) { /* { syscallarg(linux32___sysctlp_t) lsp; } */ struct linux32_sysctl ls32; int name[CTL_MAXNAME]; size_t savelen; netbsd32_size_t oldlen32; size_t oldlen; int error; /* * Read sysctl arguments */ if ((error = copyin(SCARG_P32(uap, lsp), &ls32, sizeof(ls32))) != 0) return error; /* * Read oldlen */ if (NETBSD32PTR64(ls32.oldlenp) != NULL) { if ((error = copyin(NETBSD32PTR64(ls32.oldlenp), &oldlen32, sizeof(oldlen32))) != 0) return error; } else { oldlen32 = 0; } savelen = (size_t)oldlen32; /* * Sanity check nlen */ if ((ls32.nlen > CTL_MAXNAME) || (ls32.nlen < 1)) return ENOTDIR; /* * Read the sysctl name */ if ((error = copyin(NETBSD32PTR64(ls32.name), &name, ls32.nlen * sizeof(int))) != 0) return error; ktrmib(name, ls32.nlen); /* * First try linux32 tree, then linux tree */ oldlen = (size_t)oldlen32; sysctl_lock(NETBSD32PTR64(ls32.newval) != NULL); error = sysctl_dispatch(name, ls32.nlen, NETBSD32PTR64(ls32.oldval), &oldlen, NETBSD32PTR64(ls32.newval), ls32.newlen, name, l, &linux32_sysctl_root); oldlen32 = (netbsd32_size_t)oldlen; sysctl_unlock(); /* * Check for oldlen overflow (not likely, but who knows...) */ if (oldlen != oldlen32) { #ifdef DEBUG_LINUX printf("%s: oldlen32 = %d, oldlen = %ld\n", __func__, oldlen32, oldlen); #endif return EINVAL; } /* * set caller's oldlen, even if we got an error */ if (NETBSD32PTR64(ls32.oldlenp)) { int nerror; nerror = copyout(&oldlen32, NETBSD32PTR64(ls32.oldlenp), sizeof(oldlen32)); if (error == 0) error = nerror; } /* * oldlen was too short */ if ((error == 0) && (NETBSD32PTR64(ls32.oldval) != NULL) && (savelen < oldlen32)) error = ENOMEM; return error; }
/* Register a new filesystem type in the global table */ static int vfs_register(struct vfsconf *vfc) { struct sysctl_oid *oidp; struct vfsops *vfsops; static int once; if (!once) { vattr_null(&va_null); once = 1; } if (vfc->vfc_version != VFS_VERSION) { printf("ERROR: filesystem %s, unsupported ABI version %x\n", vfc->vfc_name, vfc->vfc_version); return (EINVAL); } if (vfs_byname(vfc->vfc_name) != NULL) return EEXIST; vfc->vfc_typenum = maxvfsconf++; TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); /* * If this filesystem has a sysctl node under vfs * (i.e. vfs.xxfs), then change the oid number of that node to * match the filesystem's type number. This allows user code * which uses the type number to read sysctl variables defined * by the filesystem to continue working. Since the oids are * in a sorted list, we need to make sure the order is * preserved by re-registering the oid after modifying its * number. */ sysctl_lock(); SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { sysctl_unregister_oid(oidp); oidp->oid_number = vfc->vfc_typenum; sysctl_register_oid(oidp); break; } sysctl_unlock(); /* * Initialise unused ``struct vfsops'' fields, to use * the vfs_std*() functions. Note, we need the mount * and unmount operations, at the least. The check * for vfsops available is just a debugging aid. */ KASSERT(vfc->vfc_vfsops != NULL, ("Filesystem %s has no vfsops", vfc->vfc_name)); /* * Check the mount and unmount operations. */ vfsops = vfc->vfc_vfsops; KASSERT(vfsops->vfs_mount != NULL, ("Filesystem %s has no mount op", vfc->vfc_name)); KASSERT(vfsops->vfs_unmount != NULL, ("Filesystem %s has no unmount op", vfc->vfc_name)); if (vfsops->vfs_root == NULL) /* return file system's root vnode */ vfsops->vfs_root = vfs_stdroot; if (vfsops->vfs_quotactl == NULL) /* quota control */ vfsops->vfs_quotactl = vfs_stdquotactl; if (vfsops->vfs_statfs == NULL) /* return file system's status */ vfsops->vfs_statfs = vfs_stdstatfs; if (vfsops->vfs_sync == NULL) /* * flush unwritten data (nosync) * file systems can use vfs_stdsync * explicitly by setting it in the * vfsop vector. */ vfsops->vfs_sync = vfs_stdnosync; if (vfsops->vfs_vget == NULL) /* convert an inode number to a vnode */ vfsops->vfs_vget = vfs_stdvget; if (vfsops->vfs_fhtovp == NULL) /* turn an NFS file handle into a vnode */ vfsops->vfs_fhtovp = vfs_stdfhtovp; if (vfsops->vfs_checkexp == NULL) /* check if file system is exported */ vfsops->vfs_checkexp = vfs_stdcheckexp; if (vfsops->vfs_init == NULL) /* file system specific initialisation */ vfsops->vfs_init = vfs_stdinit; if (vfsops->vfs_uninit == NULL) /* file system specific uninitialisation */ vfsops->vfs_uninit = vfs_stduninit; if (vfsops->vfs_extattrctl == NULL) /* extended attribute control */ vfsops->vfs_extattrctl = vfs_stdextattrctl; if (vfsops->vfs_sysctl == NULL) vfsops->vfs_sysctl = vfs_stdsysctl; /* * Call init function for this VFS... */ (*(vfc->vfc_vfsops->vfs_init))(vfc); return 0; }