summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/gen/sysctl.34
-rw-r--r--sys/kern/kern_sysctl.c133
-rw-r--r--sys/sys/sysctl.h2
3 files changed, 71 insertions, 68 deletions
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index 6e95014..098d4f2 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -704,6 +704,10 @@ is too short to hold the requested value.
The
.Fa name
array specifies an intermediate rather than terminal name.
+.It Bq Er EISDIR
+The
+.Fa name
+array specifies a terminal name, but the actual name is not terminal.
.It Bq Er EOPNOTSUPP
The
.Fa name
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index a00d7a1..a1fab08 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -438,43 +438,19 @@ SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
static int
sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
{
- int *name = (int *) arg1, error;
- u_int namelen = arg2;
- int indx;
struct sysctl_oid *oid;
- struct sysctl_oid_list *lsp = &sysctl__children;
+ int error;
- oid = SLIST_FIRST(lsp);
+ error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
+ if (error)
+ return (error);
- indx = 0;
- while (oid && indx < CTL_MAXNAME) {
- if (oid->oid_number == name[indx]) {
- indx++;
- if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
- if (oid->oid_handler)
- goto found;
- if (indx == namelen)
- goto found;
- lsp = (struct sysctl_oid_list *)oid->oid_arg1;
- oid = SLIST_FIRST(lsp);
- } else {
- if (indx != namelen)
- return EISDIR;
- goto found;
- }
- } else {
- oid = SLIST_NEXT(oid, oid_link);
- }
- }
- return ENOENT;
-found:
if (!oid->oid_fmt)
- return ENOENT;
- error = SYSCTL_OUT(req,
- &oid->oid_kind, sizeof(oid->oid_kind));
- if (!error)
- error = SYSCTL_OUT(req, oid->oid_fmt,
- strlen(oid->oid_fmt)+1);
+ return (ENOENT);
+ error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
+ if (error)
+ return (error);
+ error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
return (error);
}
@@ -716,22 +692,14 @@ sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
return (error);
}
-/*
- * Traverse our tree, and find the right node, execute whatever it points
- * at, and return the resulting error code.
- */
-
int
-sysctl_root SYSCTL_HANDLER_ARGS
+sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
+ int *nindx, struct sysctl_req *req)
{
- int *name = (int *) arg1;
- u_int namelen = arg2;
- int indx, i;
struct sysctl_oid *oid;
- struct sysctl_oid_list *lsp = &sysctl__children;
-
- oid = SLIST_FIRST(lsp);
+ int indx;
+ oid = SLIST_FIRST(&sysctl__children);
indx = 0;
while (oid && indx < CTL_MAXNAME) {
if (oid->oid_number == name[indx]) {
@@ -739,23 +707,55 @@ sysctl_root SYSCTL_HANDLER_ARGS
if (oid->oid_kind & CTLFLAG_NOLOCK)
req->lock = 0;
if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
- if (oid->oid_handler)
- goto found;
- if (indx == namelen)
- return ENOENT;
- lsp = (struct sysctl_oid_list *)oid->oid_arg1;
- oid = SLIST_FIRST(lsp);
+ if (oid->oid_handler != NULL ||
+ indx == namelen) {
+ *noid = oid;
+ if (nindx != NULL)
+ *nindx = indx;
+ return (0);
+ }
+ oid = SLIST_FIRST(
+ (struct sysctl_oid_list *)oid->oid_arg1);
+ } else if (indx == namelen) {
+ *noid = oid;
+ if (nindx != NULL)
+ *nindx = indx;
+ return (0);
} else {
- if (indx != namelen)
- return EISDIR;
- goto found;
+ return (ENOTDIR);
}
} else {
oid = SLIST_NEXT(oid, oid_link);
}
}
- return ENOENT;
-found:
+ return (ENOENT);
+}
+
+/*
+ * Traverse our tree, and find the right node, execute whatever it points
+ * to, and return the resulting error code.
+ */
+
+int
+sysctl_root SYSCTL_HANDLER_ARGS
+{
+ struct sysctl_oid *oid;
+ int error, indx;
+
+ error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
+ if (error)
+ return (error);
+
+ if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
+ /*
+ * You can't call a sysctl when it's a node, but has
+ * no handler. Inform the user that it's a node.
+ * The indx may or may not be the same as namelen.
+ */
+ if (oid->oid_handler == NULL)
+ return (EISDIR);
+ }
+
/* If writing isn't allowed */
if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
@@ -764,23 +764,20 @@ found:
/* Most likely only root can write */
if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
req->newptr && req->p &&
- (i = suser_xxx(0, req->p,
+ (error = suser_xxx(0, req->p,
(oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0)))
- return (i);
+ return (error);
if (!oid->oid_handler)
return EINVAL;
- if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
- i = (oid->oid_handler) (oid,
- name + indx, namelen - indx,
- req);
- } else {
- i = (oid->oid_handler) (oid,
- oid->oid_arg1, oid->oid_arg2,
- req);
- }
- return (i);
+ if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
+ error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
+ req);
+ else
+ error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
+ req);
+ return (error);
}
#ifndef _SYS_SYSPROTO_H_
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index bea866e..c1ef6c8 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -499,6 +499,8 @@ int kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old,
int userland_sysctl(struct proc *p, int *name, u_int namelen, void *old,
size_t *oldlenp, int inkernel, void *new, size_t newlen,
size_t *retval);
+int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
+ int *nindx, struct sysctl_req *req);
#else /* !KERNEL */
#include <sys/cdefs.h>
OpenPOWER on IntegriCloud