summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-11-13 04:33:33 -0500
committerIan Moffett <ian@osmora.org>2024-11-13 04:33:33 -0500
commitbb2210b76c8757cb4263c881a350f2b7921a67ff (patch)
tree4676844d598b202612695067f15400c05c32ae2b /sys/kern
parent0440e0255a107bcd77390c3f1959bd908c18cef7 (diff)
kernel: sysctl: Make sysctl(2) more flexible
This commit makes various changes such as updating how readonly and writable entries are stored and how entry lookups are made to improve flexibility. Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_sysctl.c130
1 files changed, 97 insertions, 33 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index f3f436c..a1bd91a 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -29,6 +29,7 @@
#include <sys/sysctl.h>
#include <sys/syscall.h>
+#include <sys/param.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <vm/dynalloc.h>
@@ -38,16 +39,50 @@
HYRA_VERSION " " \
HYRA_BUILDDATE
-static const char *hyra = "Hyra";
-static const char *hyra_version = HYRA_VERSION;
-static const char *osrelease = HYRA_RELEASE;
+static char hyra[] = "Hyra";
+static char hyra_version[] = HYRA_VERSION;
+static char osrelease[] = HYRA_RELEASE;
-static struct sysctl_entry common_kerntab[] = {
- [KERN_OSTYPE] = { KERN_OSTYPE, SYSCTL_OPTYPE_STR_RO, &hyra },
+/*
+ * XXX: Readonly values can be statically allocated as they won't
+ * ever be changed. Values that are not readonly *must* be dynamically
+ * allocated through dynalloc(9).
+ */
+static struct sysctl_entry common_optab[] = {
+ [KERN_OSTYPE] = { KERN_OSTYPE, SYSCTL_OPTYPE_STR_RO, hyra },
[KERN_OSRELEASE] = { KERN_OSRELEASE, SYSCTL_OPTYPE_STR_RO, &osrelease },
[KERN_VERSION] = { KERN_VERSION, SYSCTL_OPTYPE_STR_RO, &hyra_version },
};
+static int
+sysctl_write(struct sysctl_entry *entry, void *p, size_t len)
+{
+ void *tmp;
+
+ /* Allocate a new value if needed */
+ if (entry->data == NULL) {
+ entry->data = dynalloc(len);
+ goto done;
+ }
+ if (entry->data == NULL) {
+ return -ENOMEM;
+ }
+
+ /* If we already have data allocated, resize it */
+ if ((tmp = entry->data) != NULL) {
+ entry->data = dynrealloc(entry->data, len);
+ goto done;
+ }
+ if (entry->data == NULL) {
+ entry->data = tmp;
+ return -ENOMEM;
+ }
+
+done:
+ memcpy(entry->data, p, len);
+ return 0;
+}
+
/*
* Helper for sys_sysctl()
*/
@@ -122,50 +157,79 @@ int
sysctl(struct sysctl_args *args)
{
struct sysctl_entry *tmp;
- char *tmp_str;
+ char *tmp_str = NULL;
+ int tmp_int = 0;
size_t oldlen, len;
+ int name;
if (args->name == NULL) {
return -EINVAL;
}
- if (args->oldlenp == NULL) {
+ /* If oldlenp is not set, oldp must be the same */
+ if (args->oldlenp == NULL && args->oldp != NULL) {
return -EINVAL;
}
- /* TODO: Support writable values */
- if (args->newp != NULL) {
+ /* Get the name and make sure it is in range */
+ name = *args->name;
+ if (name >= NELEM(common_optab) || name < 0) {
+ return -EINVAL;
+ }
+
+ tmp = &common_optab[name];
+ oldlen = (args->oldlenp == NULL) ? 0 : *args->oldlenp;
+
+ /*
+ * Make sure we aren't trying to write readonly
+ * entries to avoid issues...
+ */
+ switch (tmp->optype) {
+ case SYSCTL_OPTYPE_STR_RO:
+ case SYSCTL_OPTYPE_INT_RO:
+ if (args->newp != NULL) {
+ return -EACCES;
+ }
+ }
+
+ /* If the value is unknown, bail out */
+ if (args->oldp != NULL && tmp->data == NULL) {
return -ENOTSUP;
}
/*
- * TODO: We only support toplevel names as of now and should
- * expand this in the future. As of now, users will only
- * be able to access kern.* entries.
+ * Now it is time to extract the value from this sysctl
+ * entry if requested by the user.
*/
- switch (*args->name) {
- case KERN_OSTYPE:
- tmp = &common_kerntab[KERN_OSTYPE];
- tmp_str = *((char **)tmp->data);
- len = strlen(tmp_str);
- break;
- case KERN_OSRELEASE:
- tmp = &common_kerntab[KERN_OSRELEASE];
- tmp_str = *((char **)tmp->data);
- len = strlen(tmp_str);
- break;
- case KERN_VERSION:
- tmp = &common_kerntab[KERN_VERSION];
- tmp_str = *((char **)tmp->data);
- len = strlen(tmp_str);
- break;
- default:
- return -EINVAL;
+ if (args->oldp != NULL) {
+ switch (tmp->optype) {
+ /* Check for strings */
+ case SYSCTL_OPTYPE_STR_RO:
+ case SYSCTL_OPTYPE_STR:
+ tmp_str = (char *)tmp->data;
+ len = strlen(tmp_str);
+ break;
+ /* Check for ints */
+ case SYSCTL_OPTYPE_INT_RO:
+ case SYSCTL_OPTYPE_INT:
+ tmp_int = *((int *)tmp->data);
+ len = sizeof(tmp_int);
+ break;
+ }
+ }
+
+ /* If newp is set, write the new value */
+ if (args->newp != NULL) {
+ sysctl_write(tmp, args->newp, args->newlen);
+ }
+
+ /* Copy back old value if oldp is not NULL */
+ if (args->oldp != NULL && tmp_str != NULL) {
+ memcpy(args->oldp, tmp_str, oldlen);
+ } else if (args->oldp != NULL) {
+ memcpy(args->oldp, &tmp_int, oldlen);
}
- /* Copy new data */
- oldlen = *args->oldlenp;
- memcpy(args->oldp, tmp_str, oldlen);
return (len > oldlen) ? -ENOMEM : 0;
}