summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/kern_sysctl.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 11:33:00 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 15:28:21 +0100
commitaf5333e0a02b2295304d4e029b15ee15a4fe2b3a (patch)
treec5c43680d374f58b487eeeaf18fb7ec6b84ba074 /freebsd/sys/kern/kern_sysctl.c
parentBUS_SPACE(9): Use simple memory model for ARM (diff)
downloadrtems-libbsd-af5333e0a02b2295304d4e029b15ee15a4fe2b3a.tar.bz2
Update to FreeBSD 8.4
Diffstat (limited to 'freebsd/sys/kern/kern_sysctl.c')
-rw-r--r--freebsd/sys/kern/kern_sysctl.c294
1 files changed, 174 insertions, 120 deletions
diff --git a/freebsd/sys/kern/kern_sysctl.c b/freebsd/sys/kern/kern_sysctl.c
index 750de376..fad7ec10 100644
--- a/freebsd/sys/kern/kern_sysctl.c
+++ b/freebsd/sys/kern/kern_sysctl.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_ktrace.h>
#include <rtems/bsd/sys/param.h>
+#include <sys/fail.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
@@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/jail.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sbuf.h>
#include <sys/sx.h>
#include <sys/sysproto.h>
#include <sys/uio.h>
@@ -87,13 +89,12 @@ static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
static struct sx sysctllock;
static struct sx sysctlmemlock;
-#define SYSCTL_SLOCK() sx_slock(&sysctllock)
-#define SYSCTL_SUNLOCK() sx_sunlock(&sysctllock)
#define SYSCTL_XLOCK() sx_xlock(&sysctllock)
#define SYSCTL_XUNLOCK() sx_xunlock(&sysctllock)
#define SYSCTL_ASSERT_XLOCKED() sx_assert(&sysctllock, SA_XLOCKED)
-#define SYSCTL_ASSERT_LOCKED() sx_assert(&sysctllock, SA_LOCKED)
#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock")
+#define SYSCTL_SLEEP(ch, wmesg, timo) \
+ sx_sleep(ch, &sysctllock, 0, wmesg, timo)
static int sysctl_root(SYSCTL_HANDLER_ARGS);
@@ -107,7 +108,7 @@ sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
{
struct sysctl_oid *oidp;
- SYSCTL_ASSERT_LOCKED();
+ SYSCTL_ASSERT_XLOCKED();
SLIST_FOREACH(oidp, list, oid_link) {
if (strcmp(oidp->oid_name, name) == 0) {
return (oidp);
@@ -314,7 +315,7 @@ sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
{
struct sysctl_ctx_entry *e;
- SYSCTL_ASSERT_LOCKED();
+ SYSCTL_ASSERT_XLOCKED();
if (clist == NULL || oidp == NULL)
return(NULL);
TAILQ_FOREACH(e, clist, link) {
@@ -410,10 +411,20 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
}
sysctl_unregister_oid(oidp);
if (del) {
+ /*
+ * Wait for all threads running the handler to drain.
+ * This preserves the previous behavior when the
+ * sysctl lock was held across a handler invocation,
+ * and is necessary for module unload correctness.
+ */
+ while (oidp->oid_running > 0) {
+ oidp->oid_kind |= CTLFLAG_DYING;
+ SYSCTL_SLEEP(&oidp->oid_running, "oidrm", 0);
+ }
if (oidp->oid_descr)
- free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID);
- free((void *)(uintptr_t)(const void *)oidp->oid_name,
- M_SYSCTLOID);
+ free(__DECONST(char *, oidp->oid_descr),
+ M_SYSCTLOID);
+ free(__DECONST(char *, oidp->oid_name), M_SYSCTLOID);
free(oidp, M_SYSCTLOID);
}
}
@@ -430,8 +441,6 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
{
struct sysctl_oid *oidp;
- ssize_t len;
- char *newname;
/* You have to hook up somewhere.. */
if (parent == NULL)
@@ -458,11 +467,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
SLIST_NEXT(oidp, oid_link) = NULL;
oidp->oid_number = number;
oidp->oid_refcnt = 1;
- len = strlen(name);
- newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
- bcopy(name, newname, len + 1);
- newname[len] = '\0';
- oidp->oid_name = newname;
+ oidp->oid_name = strdup(name, M_SYSCTLOID);
oidp->oid_handler = handler;
oidp->oid_kind = CTLFLAG_DYN | kind;
if ((kind & CTLTYPE) == CTLTYPE_NODE) {
@@ -475,12 +480,8 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
oidp->oid_arg2 = arg2;
}
oidp->oid_fmt = fmt;
- if (descr) {
- int len = strlen(descr) + 1;
- oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK);
- if (oidp->oid_descr)
- strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
- }
+ if (descr)
+ oidp->oid_descr = strdup(descr, M_SYSCTLOID);
/* Update the context, if used */
if (clist != NULL)
sysctl_ctx_entry_add(clist, oidp);
@@ -496,16 +497,12 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
void
sysctl_rename_oid(struct sysctl_oid *oidp, const char *name)
{
- ssize_t len;
char *newname;
- void *oldname;
+ char *oldname;
- len = strlen(name);
- newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
- bcopy(name, newname, len + 1);
- newname[len] = '\0';
+ newname = strdup(name, M_SYSCTLOID);
SYSCTL_XLOCK();
- oldname = (void *)(uintptr_t)(const void *)oidp->oid_name;
+ oldname = __DECONST(char *, oidp->oid_name);
oidp->oid_name = newname;
SYSCTL_XUNLOCK();
free(oldname, M_SYSCTLOID);
@@ -582,7 +579,7 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
int k;
struct sysctl_oid *oidp;
- SYSCTL_ASSERT_LOCKED();
+ SYSCTL_ASSERT_XLOCKED();
SLIST_FOREACH(oidp, l, oid_link) {
for (k=0; k<i; k++)
@@ -623,7 +620,9 @@ sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
error = priv_check(req->td, PRIV_SYSCTL_DEBUG);
if (error)
return (error);
+ SYSCTL_XLOCK();
sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
+ SYSCTL_XUNLOCK();
return (ENOENT);
}
@@ -641,7 +640,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
char buf[10];
- SYSCTL_ASSERT_LOCKED();
+ SYSCTL_XLOCK();
while (namelen) {
if (!lsp) {
snprintf(buf,sizeof(buf),"%d",*name);
@@ -650,7 +649,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
if (!error)
error = SYSCTL_OUT(req, buf, strlen(buf));
if (error)
- return (error);
+ goto out;
namelen--;
name++;
continue;
@@ -666,7 +665,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
error = SYSCTL_OUT(req, oid->oid_name,
strlen(oid->oid_name));
if (error)
- return (error);
+ goto out;
namelen--;
name++;
@@ -677,12 +676,15 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
if (oid->oid_handler)
break;
- lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
+ lsp2 = SYSCTL_CHILDREN(oid);
break;
}
lsp = lsp2;
}
- return (SYSCTL_OUT(req, "", 1));
+ error = SYSCTL_OUT(req, "", 1);
+ out:
+ SYSCTL_XUNLOCK();
+ return (error);
}
static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
@@ -693,7 +695,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
{
struct sysctl_oid *oidp;
- SYSCTL_ASSERT_LOCKED();
+ SYSCTL_ASSERT_XLOCKED();
*len = level;
SLIST_FOREACH(oidp, lsp, oid_link) {
*next = oidp->oid_number;
@@ -708,7 +710,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
if (oidp->oid_handler)
/* We really should call the handler here...*/
return (0);
- lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
+ lsp = SYSCTL_CHILDREN(oidp);
if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
len, level+1, oidpp))
return (0);
@@ -723,7 +725,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
return (0);
if (oidp->oid_handler)
return (0);
- lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
+ lsp = SYSCTL_CHILDREN(oidp);
if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
next+1, len, level+1, oidpp))
return (0);
@@ -735,7 +737,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
if (oidp->oid_handler)
continue;
- lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
+ lsp = SYSCTL_CHILDREN(oidp);
if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
len, level+1, oidpp))
return (0);
@@ -757,7 +759,9 @@ sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
struct sysctl_oid_list *lsp = &sysctl__children;
int newoid[CTL_MAXNAME];
+ SYSCTL_XLOCK();
i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
+ SYSCTL_XUNLOCK();
if (i)
return (ENOENT);
error = SYSCTL_OUT(req, newoid, j * sizeof (int));
@@ -769,39 +773,26 @@ static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
static int
name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp)
{
- int i;
struct sysctl_oid *oidp;
struct sysctl_oid_list *lsp = &sysctl__children;
char *p;
- SYSCTL_ASSERT_LOCKED();
-
- if (!*name)
- return (ENOENT);
-
- p = name + strlen(name) - 1 ;
- if (*p == '.')
- *p = '\0';
-
- *len = 0;
-
- for (p = name; *p && *p != '.'; p++)
- ;
- i = *p;
- if (i == '.')
- *p = '\0';
+ SYSCTL_ASSERT_XLOCKED();
- oidp = SLIST_FIRST(lsp);
+ for (*len = 0; *len < CTL_MAXNAME;) {
+ p = strsep(&name, ".");
- while (oidp && *len < CTL_MAXNAME) {
- if (strcmp(name, oidp->oid_name)) {
- oidp = SLIST_NEXT(oidp, oid_link);
- continue;
+ oidp = SLIST_FIRST(lsp);
+ for (;; oidp = SLIST_NEXT(oidp, oid_link)) {
+ if (oidp == NULL)
+ return (ENOENT);
+ if (strcmp(p, oidp->oid_name) == 0)
+ break;
}
*oid++ = oidp->oid_number;
(*len)++;
- if (!i) {
+ if (name == NULL || *name == '\0') {
if (oidpp)
*oidpp = oidp;
return (0);
@@ -813,14 +804,7 @@ name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp)
if (oidp->oid_handler)
break;
- lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
- oidp = SLIST_FIRST(lsp);
- name = p+1;
- for (p = name; *p && *p != '.'; p++)
- ;
- i = *p;
- if (i == '.')
- *p = '\0';
+ lsp = SYSCTL_CHILDREN(oidp);
}
return (ENOENT);
}
@@ -832,8 +816,6 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
int error, oid[CTL_MAXNAME], len;
struct sysctl_oid *op = 0;
- SYSCTL_ASSERT_LOCKED();
-
if (!req->newlen)
return (ENOENT);
if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
@@ -848,8 +830,10 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
}
p [req->newlen] = '\0';
-
+ len = 0;
+ SYSCTL_XLOCK();
error = name2oid(p, oid, &len, &op);
+ SYSCTL_XUNLOCK();
free(p, M_SYSCTL);
@@ -869,16 +853,21 @@ sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
struct sysctl_oid *oid;
int error;
+ SYSCTL_XLOCK();
error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
if (error)
- return (error);
+ goto out;
- if (!oid->oid_fmt)
- return (ENOENT);
+ if (oid->oid_fmt == NULL) {
+ error = ENOENT;
+ goto out;
+ }
error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
if (error)
- return (error);
+ goto out;
error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
+ out:
+ SYSCTL_XUNLOCK();
return (error);
}
@@ -892,13 +881,18 @@ sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
struct sysctl_oid *oid;
int error;
+ SYSCTL_XLOCK();
error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
if (error)
- return (error);
+ goto out;
- if (!oid->oid_descr)
- return (ENOENT);
+ if (oid->oid_descr == NULL) {
+ error = ENOENT;
+ goto out;
+ }
error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
+ out:
+ SYSCTL_XUNLOCK();
return (error);
}
@@ -966,7 +960,10 @@ sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS)
/*
- * Handle a long, signed or unsigned. arg1 points to it.
+ * Handle a long, signed or unsigned.
+ * Two cases:
+ * a variable: point arg1 at it.
+ * a constant: pass it in arg2.
*/
int
@@ -981,9 +978,10 @@ sysctl_handle_long(SYSCTL_HANDLER_ARGS)
/*
* Attempt to get a coherent snapshot by making a copy of the data.
*/
- if (!arg1)
- return (EINVAL);
- tmplong = *(long *)arg1;
+ if (arg1)
+ tmplong = *(long *)arg1;
+ else
+ tmplong = arg2;
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
tmpint = tmplong;
@@ -995,18 +993,24 @@ sysctl_handle_long(SYSCTL_HANDLER_ARGS)
if (error || !req->newptr)
return (error);
+ if (!arg1)
+ error = EPERM;
#ifdef SCTL_MASK32
- if (req->flags & SCTL_MASK32) {
+ else if (req->flags & SCTL_MASK32) {
error = SYSCTL_IN(req, &tmpint, sizeof(int));
*(long *)arg1 = (long)tmpint;
- } else
+ }
#endif
+ else
error = SYSCTL_IN(req, arg1, sizeof(long));
return (error);
}
/*
- * Handle a 64 bit int, signed or unsigned. arg1 points to it.
+ * Handle a 64 bit int, signed or unsigned.
+ * Two cases:
+ * a variable: point arg1 at it.
+ * a constant: pass it in arg2.
*/
int
@@ -1018,15 +1022,19 @@ sysctl_handle_quad(SYSCTL_HANDLER_ARGS)
/*
* Attempt to get a coherent snapshot by making a copy of the data.
*/
- if (!arg1)
- return (EINVAL);
- tmpout = *(uint64_t *)arg1;
+ if (arg1)
+ tmpout = *(uint64_t *)arg1;
+ else
+ tmpout = arg2;
error = SYSCTL_OUT(req, &tmpout, sizeof(uint64_t));
if (error || !req->newptr)
return (error);
- error = SYSCTL_IN(req, arg1, sizeof(uint64_t));
+ if (!arg1)
+ error = EPERM;
+ else
+ error = SYSCTL_IN(req, arg1, sizeof(uint64_t));
return (error);
}
@@ -1192,9 +1200,9 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
req.newfunc = sysctl_new_kernel;
req.lock = REQ_LOCKED;
- SYSCTL_SLOCK();
+ SYSCTL_XLOCK();
error = sysctl_root(0, name, namelen, &req);
- SYSCTL_SUNLOCK();
+ SYSCTL_XUNLOCK();
if (req.lock == REQ_WIRED && req.validlen > 0)
vsunlock(req.oldptr, req.validlen);
@@ -1241,8 +1249,8 @@ kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
static int
sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
{
- int error = 0;
size_t i, len, origidx;
+ int error;
origidx = req->oldidx;
req->oldidx += l;
@@ -1263,10 +1271,14 @@ sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
else {
if (i > len - origidx)
i = len - origidx;
- error = copyout(p, (char *)req->oldptr + origidx, i);
+ if (req->lock == REQ_WIRED) {
+ error = copyout_nofault(p, (char *)req->oldptr +
+ origidx, i);
+ } else
+ error = copyout(p, (char *)req->oldptr + origidx, i);
+ if (error != 0)
+ return (error);
}
- if (error)
- return (error);
if (i < l)
return (ENOMEM);
return (0);
@@ -1322,37 +1334,43 @@ int
sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
int *nindx, struct sysctl_req *req)
{
+ struct sysctl_oid_list *lsp;
struct sysctl_oid *oid;
int indx;
- SYSCTL_ASSERT_LOCKED();
- oid = SLIST_FIRST(&sysctl__children);
+ SYSCTL_ASSERT_XLOCKED();
+ lsp = &sysctl__children;
indx = 0;
- while (oid && indx < CTL_MAXNAME) {
- if (oid->oid_number == name[indx]) {
- indx++;
- if (oid->oid_kind & CTLFLAG_NOLOCK)
- req->lock = REQ_UNLOCKED;
- if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
- 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) {
+ while (indx < CTL_MAXNAME) {
+ SLIST_FOREACH(oid, lsp, oid_link) {
+ if (oid->oid_number == name[indx])
+ break;
+ }
+ if (oid == NULL)
+ return (ENOENT);
+
+ indx++;
+ if (oid->oid_kind & CTLFLAG_NOLOCK)
+ req->lock = REQ_UNLOCKED;
+ if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
+ if (oid->oid_handler != NULL || indx == namelen) {
*noid = oid;
if (nindx != NULL)
*nindx = indx;
+ KASSERT((oid->oid_kind & CTLFLAG_DYING) == 0,
+ ("%s found DYING node %p", __func__, oid));
return (0);
- } else {
- return (ENOTDIR);
}
+ lsp = SYSCTL_CHILDREN(oid);
+ } else if (indx == namelen) {
+ *noid = oid;
+ if (nindx != NULL)
+ *nindx = indx;
+ KASSERT((oid->oid_kind & CTLFLAG_DYING) == 0,
+ ("%s found DYING node %p", __func__, oid));
+ return (0);
} else {
- oid = SLIST_NEXT(oid, oid_link);
+ return (ENOTDIR);
}
}
return (ENOENT);
@@ -1369,7 +1387,7 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
struct sysctl_oid *oid;
int error, indx, lvl;
- SYSCTL_ASSERT_LOCKED();
+ SYSCTL_ASSERT_XLOCKED();
error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
if (error)
@@ -1437,12 +1455,23 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
if (error != 0)
return (error);
#endif
+ oid->oid_running++;
+ SYSCTL_XUNLOCK();
+
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
mtx_lock(&Giant);
error = oid->oid_handler(oid, arg1, arg2, req);
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
mtx_unlock(&Giant);
+#ifndef __rtems__
+ KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error);
+#endif /* __rtems__ */
+
+ SYSCTL_XLOCK();
+ oid->oid_running--;
+ if (oid->oid_running == 0 && (oid->oid_kind & CTLFLAG_DYING) != 0)
+ wakeup(&oid->oid_running);
return (error);
}
@@ -1543,9 +1572,9 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
for (;;) {
req.oldidx = 0;
req.newidx = 0;
- SYSCTL_SLOCK();
+ SYSCTL_XLOCK();
error = sysctl_root(0, name, namelen, &req);
- SYSCTL_SUNLOCK();
+ SYSCTL_XUNLOCK();
if (error != EAGAIN)
break;
uio_yield();
@@ -1569,4 +1598,29 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
}
return (error);
}
+
+/*
+ * Drain into a sysctl struct. The user buffer should be wired if a page
+ * fault would cause issue.
+ */
+static int
+sbuf_sysctl_drain(void *arg, const char *data, int len)
+{
+ struct sysctl_req *req = arg;
+ int error;
+
+ error = SYSCTL_OUT(req, data, len);
+ KASSERT(error >= 0, ("Got unexpected negative value %d", error));
+ return (error == 0 ? len : -error);
+}
+
+struct sbuf *
+sbuf_new_for_sysctl(struct sbuf *s, char *buf, int length,
+ struct sysctl_req *req)
+{
+
+ s = sbuf_new(s, buf, length, SBUF_FIXEDLEN);
+ sbuf_set_drain(s, sbuf_sysctl_drain, req);
+ return (s);
+}
#endif /* __rtems__ */