diff options
author | Ian Moffett <ian@osmora.org> | 2024-11-12 00:19:12 -0500 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-11-12 00:19:12 -0500 |
commit | fcb9fd7c83420e6ddcd8f29af6f4e61b0601a529 (patch) | |
tree | 4f81f43538731831ca853c6372505a20624a9f2b /sys/kern/kern_sysctl.c | |
parent | 24c1598929ac4cfd2c0a1e3c34b46a35ed1775bd (diff) |
kernel: syscall: Add SYS_sysctl syscall
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys/kern/kern_sysctl.c')
-rw-r--r-- | sys/kern/kern_sysctl.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 970bc70..3d0b118 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -28,7 +28,9 @@ */ #include <sys/sysctl.h> +#include <sys/syscall.h> #include <sys/errno.h> +#include <sys/systm.h> #include <vm/dynalloc.h> #include <string.h> @@ -46,6 +48,76 @@ static struct sysctl_entry common_kerntab[] = { [KERN_VERSION] = { KERN_VERSION, SYSCTL_OPTYPE_STR, &hyra_version }, }; +/* + * Helper for sys_sysctl() + */ +static int +do_sysctl(struct sysctl_args *args) +{ + struct sysctl_args new_args; + size_t name_len, oldlenp; + int *name = NULL; + void *oldp = NULL, *newp = NULL; + int retval = 0; + + if (args->oldlenp == NULL) { + return -EINVAL; + } + + name_len = args->nlen; + retval = copyin(args->oldlenp, &oldlenp, sizeof(oldlenp)); + if (retval != 0) { + goto done; + } + + /* Copy in newp if it is set */ + if (args->newp == NULL) { + newp = NULL; + } else { + newp = dynalloc(args->newlen); + retval = copyin(args->newp, newp, args->newlen); + } + + if (retval != 0) { + goto done; + } + + name = dynalloc(name_len * sizeof(int)); + retval = copyin(args->name, name, name_len * sizeof(int)); + if (retval != 0) { + return retval; + } + + oldp = dynalloc(oldlenp); + retval = copyin(args->oldp, oldp, oldlenp); + if (retval != 0) { + return retval; + } + + /* Prepare the arguments for the sysctl call */ + new_args.name = name; + new_args.nlen = name_len; + new_args.oldp = oldp; + new_args.oldlenp = &oldlenp; + new_args.newp = newp; + + retval = sysctl(&new_args); + if (retval != 0) { + goto done; + } + + copyout(oldp, args->oldp, oldlenp); +done: + if (name != NULL) + dynfree(name); + if (newp != NULL) + dynfree(newp); + if (oldp != NULL) + dynfree(oldp); + + return retval; +} + int sysctl(struct sysctl_args *args) { @@ -96,3 +168,17 @@ sysctl(struct sysctl_args *args) memcpy(args->oldp, tmp_str, oldlen); return (len > oldlen) ? -ENOMEM : 0; } + +scret_t +sys_sysctl(struct syscall_args *scargs) +{ + struct sysctl_args args; + int error; + + error = copyin((void *)scargs->arg0, &args, sizeof(args)); + if (error != 0) { + return error; + } + + return do_sysctl(&args); +} |