Primary external interfaces:
void
sysctl_init(void
)
int
sysctl_lock(struct lwp *l
, void *oldp
, size_t savelen
)
int
sysctl_dispatch(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
void
sysctl_unlock(struct lwp *l
)
int
sysctl_createv(struct sysctllog **log
, int cflags
, const struct sysctlnode **rnode
, const struct sysctlnode **cnode
, int flags
, int type
, const char *namep
, const char *desc
, sysctlfn func
, u_quad_t qv
, void *newp
, size_t newlen
, ...
)
int
sysctl_destroyv(struct sysctlnode *rnode
, ...
)
void
sysctl_free(struct sysctlnode *rnode
)
void
sysctl_teardown(struct sysctllog **
)
int
old_sysctl(int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
, struct lwp *l
)
Core internal functions:
int
sysctl_locate(struct lwp *l
, const int *name
, u_int namelen
, const struct sysctlnode **rnode
, int *nip
)
int
sysctl_lookup(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
int
sysctl_create(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
int
sysctl_destroy(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
int
sysctl_query(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
Simple
``helper''
functions:
int
sysctl_needfunc(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
int
sysctl_notavail(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
int
sysctl_null(const int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, const void *newp
, size_t newlen
, const int *oname
, struct lwp *l
, const struct sysctlnode *rnode
)
),
sysctl_createv(
),
sysctl_destroyv(
),
and
old_sysctl(
).
All other functions require the tree to be locked.
This is to prevent other users of the tree from moving nodes around
during an add operation, or from destroying nodes or subtrees that are
actively being used.
The lock is acquired by calling
sysctl_lock(
)
with a pointer to the process's lwp
l
(NULL
may be passed to all functions as the lwp pointer if no lwp is
appropriate, though any changes made via
sysctl_create(
),
sysctl_destroy(
),
sysctl_lookup(
),
or by any helper function will be done with effective superuser
privileges).
The
oldp
and
savelen
arguments are a pointer to and the size of the memory region the
caller will be using to collect data from SYSCTL.
These may also be
NULL
and 0, respectively.
The memory region will be locked via
uvm_vslock()
if it is a region in userspace.
The address and size of the region are recorded so that when the
SYSCTL lock is to be released via
sysctl_unlock(
),
only the lwp pointer
l
is required.
)
to handle the request.
sysctl_dispatch(
)
will examine the contents of
name
,
an array of integers at least
namelen
long, which is to be located in kernel space, in order to determine
which function to call to handle the specific request.
sysctl_dispatch()
uses the following algorithm to determine the function to call:
)
)
name
specifies one of
sysctl_query(
),
sysctl_create(
),
or
sysctl_destroy(
),
call the appropriate function
EOPNOTSUPP
oldp
and
oldlenp
arguments to
sysctl_dispatch(
),
as with all the other core functions, describe an area into which the
current or requested value may be copied.
oldp
may or may not be a pointer into userspace (as dictated by whether
l
is
NULL
or not).
oldlenp
is a
non-
NULL
pointer to a size_t.
newp
and
newlen
describe an area where the new value for the request may be found;
newp
may also be a pointer into userspace.
The
oname
argument is a
non-
NULL
pointer to the base of the request currently
being processed.
By simple arithmetic on
name
,
namelen
,
and
oname
,
one can easily determine the entire original request and
namelen
values, if needed.
The
rnode
value, as passed to
sysctl_dispatch(
)
represents the root of the tree into which the current request is to
be dispatched.
If
NULL
,
the main tree will be used.
sysctl_locate()
scans a tree for the node most specific to a request.
If the pointer referenced by
rnode
is not
NULL
,
the tree indicated is searched, otherwise the main tree
will be used.
The address of the most relevant node will be returned via
rnode
and the number of MIB entries consumed will be returned via
nip
,
if it is not
NULL
.
The
sysctl_lookup()
function takes the same arguments as
sysctl_dispatch(
)
with the caveat that the value for
namelen
must be zero in order to indicate that the node referenced by the
rnode
argument is the one to which the lookup is being applied.
)
and
sysctl_destroy(
)
functions.
These functions take the same arguments as
sysctl_dispatch(
)
with the additional requirement that the
namelen
argument must be 1 and the
name
argument must point to an integer valued either
CTL_CREATE
or
CTL_CREATESYM
when creating a new node, or
CTL_DESTROY
when destroying
a node.
The
newp
and
newlen
arguments should point to a copy of the node to be created or
destroyed.
If the create or destroy operation was successful, a copy of the node
created or destroyed will be placed in the space indicated by
oldp
and
oldlenp
.
If the create operation fails because of a conflict with an existing
node, a copy of that node will be returned instead.
In order to facilitate the creation and destruction of nodes from a
given tree by kernel subsystems, the functions
sysctl_createv()
and
sysctl_destroyv(
)
are provided.
These functions take care of the overhead of filling in the contents
of the create or destroy request, dealing with locking, locating the
appropriate parent node, etc.
The arguments to
sysctl_createv()
are used to construct the new node.
If the
log
argument is not
NULL
,
a sysctllog structure will be allocated and the pointer referenced
will be changed to address it.
The same log may be used for any number of nodes, provided they are
all inserted into the same tree.
This allows for a series of nodes to be created and later removed from
the tree in a single transaction (via
sysctl_teardown())
without the need for any record
keeping on the caller's part.
The
cflags
argument is currently unused and must be zero.
The
rnode
argument must either be
NULL
or a valid pointer to a reference to the root of the tree into which
the new node must be placed.
If it is
NULL
,
the main tree will be used.
It is illegal for
rnode
to refer to a
NULL
pointer.
If the
cnode
argument is not
NULL
,
on return it will be adjusted to point to the address of the new node.
The
flags
and
type
arguments are combined into the
sysctl_flags
field, and the current value for
SYSCTL_VERSION
is added in.
Note: the
CTLFLAG_PERMANENT
flag can only be set from SYSCTL setup routines (see
SETUP FUNCTIONS)
as called by
sysctl_init().
The
namep
argument is copied into the
sysctl_name
field and must be less than
SYSCTL_NAMELEN
characters in length.
The string indicated by
desc
will be copied if the
CTLFLAG_OWNDESC
flag is set, and will be used as the node's description.
Note: if
sysctl_destroyv()
attempts to delete a node that does not own its own description (and
is not marked as permanent), but the deletion fails, the description
will be copied and
sysctl_destroyv(
)
will set the
CTLFLAG_OWNDESC
flag.
The
func
argument is the name of a
``helper''
function (see
HELPER FUNCTIONS AND MACROS).
If the
CTLFLAG_IMMEDIATE
flag is set, the
qv
argument will be interpreted as the initial value for the new
``int''
or
``quad''
node.
This flag does not apply to any other type of node.
The
newp
and
newlen
arguments describe the data external to SYSCTL that is to be
instrumented.
One of
func
,
qv
and the
CTLFLAG_IMMEDIATE
flag, or
newp
and
newlen
must be given for nodes that instrument data, otherwise an error is
returned.
The remaining arguments are a list of integers specifying the path
through the MIB to the node being created.
The list must be terminated by the
CTL_EOL
value.
The penultimate value in the list may be
CTL_CREATE
if a dynamic MIB entry is to be made for this node.
sysctl_createv()
specifically does not support
CTL_CREATESYM
,
since setup routines are
expected to be able to use the in-kernel
ksyms(4)
interface to discover the location of the data to be instrumented.
If the node to be created matches a node that already exists, a return
code of 0 is given, indicating success.
When using
sysctl_destroyv()
to destroy a given node, the
rnode
argument, if not
NULL
,
is taken to be the root of the tree from which
the node is to be destroyed, otherwise the main tree is used.
The rest of the arguments are a list of integers specifying the path
through the MIB to the node being destroyed.
If the node being destroyed does not exist, a successful return code
is given.
Nodes marked with the
CTLFLAG_PERMANENT
flag cannot be destroyed.
)
except that the
rnode
argument will never be
NULL
.
It will be set to point to the node that corresponds most closely to
the current request.
Helpers are forbidden from modifying the node they are passed; they
should instead copy the structure if changes are required in order to
effect access control or other checks.
The
``helper''
prototype and function that needs to ensure that a newly assigned
value is within a certain range (presuming external data) would look
like the following:
static int sysctl_helper(SYSCTLFN_PROTO);
static int
sysctl_helper(SYSCTLFN_ARGS)
{
struct sysctlnode node;
int t, error;
node = *rnode;
node.sysctl_data = &t;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return (error);
if (t < 0 || t > 20)
return (EINVAL);
*(int*)rnode->sysctl_data = t;
return (0);
}
The use of the
SYSCTLFN_PROTO
,
SYSCTLFN_ARGS,
and
SYSCTLFN_CALL
macros ensure that all arguments are passed properly.
The single argument to the
SYSCTLFN_CALL
macro is the pointer to the node being examined.
Three basic helper functions are available for use.
sysctl_needfunc()
will emit a warning to the system console whenever it is invoked and
provides a simplistic read-only interface to the given node.
sysctl_notavail(
)
will forward
``queries''
to
sysctl_query(
)
so that subtrees can be discovered, but will return
EOPNOTSUPP
for any other condition.
sysctl_null()
specifically ignores any arguments given, sets the value indicated by
oldlenp
to zero, and returns success.
SYSCTL_SETUP
macro, which takes the name of the function and a short string
description of the function as arguments.
figuration in options(4).
(See the
SYSCTL_DEBUG_SETUP
kernel con-)
The address of the function is added to a list of functions that
sysctl_init(
)
traverses during initialization.
Setup functions do not have to add nodes to the main tree, but can set
up their own trees for emulation or other purposes.
Emulations that require use of a main tree but with some nodes changed
to suit their own purposes can arrange to overlay a sparse private
tree onto their main tree by making the
e_sysctlovly
member of their struct emul definition point to the overlaid tree.
Setup functions should take care to create all nodes from the root down to the subtree they are creating, since the order in which setup functions are called is arbitrary (the order in which setup functions are called is only determined by the ordering of the object files as passed to the linker when the kernel is built).
)
is called early in the kernel bootstrap process.
It initializes the SYSCTL lock, calls all the registered setup
functions, and marks the tree as permanent.
sysctl_free()
will unconditionally delete any and all nodes below the given node.
Its intended use is for the deletion of entire trees, not subtrees.
If a subtree is to be removed,
sysctl_destroy(
)
or
sysctl_destroyv(
)
should be used to ensure that nodes not owned by the sub-system being
deactivated are not mistakenly destroyed.
The SYSCTL lock must be held when calling this function.
sysctl_teardown()
unwinds a sysctllog and deletes the nodes in the opposite order in
which they were created.
old_sysctl()
provides an interface similar to the old SYSCTL implementation, with
the exception that access checks on a per-node basis are performed if
the
l
argument is
non-NULL
.
If called with a
NULL
argument, the values for
newp
and
oldp
are interpreted as kernel addresses, and access is performed as for
the superuser.
Nodes marked with
CTLFLAG_PERMANENT
can only be added to a tree during the first or initialization phase,
and can never be removed.
The initialization phase terminates when the main tree's root is
marked with the
CTLFLAG_PERMANENT
flag.
Once the main tree is marked in this manner, no nodes can be added to
any tree that is marked with
CTLFLAG_READONLY
at its root, and no nodes can be added at all if the main tree's root
is so marked.
Nodes added by device drivers, LKMs, and at device insertion time can be added to (and removed from) ``read-only'' parent nodes.
Nodes created by processes can only be added to ``writable'' parent nodes. See sysctl(3) for a description of the flags that are allowed to be used by when creating nodes.