summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/include/sys/syscall.h1
-rw-r--r--sys/include/sys/sysctl.h5
-rw-r--r--sys/kern/kern_syscall.c2
-rw-r--r--sys/kern/kern_sysctl.c86
4 files changed, 94 insertions, 0 deletions
diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h
index b9e1d09..e93c0ce 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -41,6 +41,7 @@
#define SYS_read 3
#define SYS_close 4
#define SYS_stat 5
+#define SYS_sysctl 6
#if defined(_KERNEL)
/* Syscall return value and arg type */
diff --git a/sys/include/sys/sysctl.h b/sys/include/sys/sysctl.h
index 364d8e5..0f1df26 100644
--- a/sys/include/sys/sysctl.h
+++ b/sys/include/sys/sysctl.h
@@ -31,6 +31,9 @@
#define _SYS_SYSCTL_H_
#include <sys/types.h>
+#if defined(_KERNEL)
+#include <sys/syscall.h>
+#endif
#include <sys/param.h>
#define KERN_OSTYPE 0
@@ -55,6 +58,8 @@ struct sysctl_entry {
int optype;
void *data;
};
+
+scret_t sys_sysctl(struct syscall_args *scargs);
#endif /* _KERNEL */
/*
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index f4d9cb8..2d3d6ea 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -28,6 +28,7 @@
*/
#include <sys/syscall.h>
+#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/proc.h>
#include <sys/vfs.h>
@@ -39,6 +40,7 @@ scret_t(*g_sctab[])(struct syscall_args *) = {
sys_read, /* SYS_read */
sys_close, /* SYS_close */
sys_stat, /* SYS_stat */
+ sys_sysctl, /* SYS_sysctl */
};
const size_t MAX_SYSCALLS = NELEM(g_sctab);
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);
+}