/* * 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); }
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); }
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; }