The sysctlmibinfo library provides an API to explore the FreeBSD sysctl MIB and to get the info of an object, it is useful to build a sysctl-like tool to get or set the kernel state. This post shows the manual page, for tutorial, examples and extra stuff: gitlab.com/alfix/sysctlmibinfo.
SYSCTLMIBINFO(3) FreeBSD Library Functions Manual SYSCTLMIBINFO(3)
NAME
SYSCTLMIF_VERSION, SYSCTLMIF_MAXIDLEVEL, sysctlmif_nametoid,
sysctlmif_name, SYSCTLMIF_NAMELEN, sysctlmif_desc, SYSCTLMIF_DESCLEN,
sysctlmif_label, SYSCTLMIF_LABELLEN, sysctlmif_info, SYSCTLMIF_INFOKIND,
SYSCTLMIF_INFOTYPE, SYSCTLMIF_INFOFLAGS, SYSCTLMIF_INFOFMT,
sysctlmif_nextnode, sysctlmif_nextleaf, sysctlmif_object,
sysctlmif_freeobject, sysctlmif_filterlist, SYSCTLMIF_LIST,
SYSCTLMIF_MAXDEPTH, sysctlmif_grouplist, sysctlmif_freelist,
sysctlmif_tree, sysctlmif_freetree, sysctlmif_mib, sysctlmif_freemib -
sysctl MIB-Tree API
LIBRARY
library "libsysctlmibinfo"
SYNOPSIS
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <sysctlmibinfo.h>
#define SYSCTLMIF_VERSION
#define SYSCTLMIF_MAXIDLEVEL
int
sysctlmif_nametoid(const char *name, size_t namelen, int *id,
size_t *idlevel);
int
sysctlmif_name(int *id, size_t idlevel, char *name, size_t *namelen);
int
SYSCTLMIF_NAMELEN(int *id, size_t idlevel, size_t *namelen);
int
sysctlmif_desc(int *id, size_t idlevel, char *desc, size_t *desclen);
int
SYSCTLMIF_DESCLEN(int *id, size_t idlevel, size_t *desclen);
int
sysctlmif_label(int *id, size_t idlevel, char *label, size_t *labellen);
int
SYSCTLMIF_LABELLEN(int *id, size_t idlevel, size_t *labellen);
int
sysctlmif_info(int *id, size_t idlevel, void *info, size_t *infolen);
uint32_t
SYSCTLMIF_INFOKIND(info);
uint8_t
SYSCTLMIF_INFOTYPE(info);
uint32_t
SYSCTLMIF_INFOFLAGS(info);
char *
SYSCTLMIF_INFOFMT(info);
int
sysctlmif_nextleaf(int *id, size_t idlevel, int *nextid,
size_t *nextidlevel);
int
sysctlmif_nextnode(int *id, size_t idlevel, int *nextid,
size_t *nextidlevel);
struct sysctlmif_object *
sysctlmif_object(int *id, size_t idlevel, unsigned int flags);
void
sysctlmif_freeobject(struct sysctlmif_object *object);
typedef int
(*sysctlmif_filterfunc_t)(struct sysctlmif_object *object);
struct sysctlmif_list *
sysctlmif_filterlist(sysctlmif_filterfunc_t filterfunc,
unsigned int flags);
struct sysctlmif_list *
SYSCTLMIF_LIST(unsigned int flags);
#define SYSCTLMIF_MAXDEPTH
struct sysctlmif_list *
sysctlmif_grouplist(int *idstart, size_t idstartlen, unsigned int flags,
unsigned int max_depth);
void
sysctlmif_freelist(struct sysctlmif_list *list);
struct sysctlmif_object *
sysctlmif_tree(int *id, size_t idlevel, unsigned int flags,
unsigned int max_depth);
void
sysctlmif_freetree(struct sysctlmif_object *node);
struct sysctlmif_list *
sysctlmif_mib(unsigned int flags);
void
sysctlmif_freemib(struct sysctlmif_list *mib);
DESCRIPTION
The sysctlmibinfo library is an interface to the kernel sysctl MIB-Tree.
It implements wrappers around an undocumented kernel interface to provide
a more easy interface for exploring the sysctl MIB and for getting the
properties of an object, moreover it defines a struct sysctlmif_object
and provides a convenient API to build data structures of
sysctlmif_object; as it is not designed to get and set object values,
anyone wishing to do this should see sysctl(3).
An object is identified by an Object Identifier (OID), it is represented
by a pair int *id and size_t idlevel, the level should be between 1 and
SYSCTLMIF_MAXIDLEVEL, see BUGS.
Please refer to sysctlmibinfo2(3) for an improved and more efficient API
on a new kernel interface.
SYSCTLMIF_VERSION is set to 1 to differentiate between this library and
sysctlmibinfo2(3).
Wrappers
sysctlmif_nametoid() sets id and idlevel like the object with name and
namelen.
sysctlmif_name(), sysctlmif_desc() and sysctlmif_label() set name and
namelen, desc and desclen, label and labellen, like the object with id
and idlevel.
sysctlmif_nextleaf() and sysctlmif_nextnode() set nextid and nextidlevel
like the next leaf or internal node visited in a "Depth First Traversal"
of the object id and idlevel.
sysctlmif_info() sets info and infolen like the object with id and
idlevel, info has the format: 3 bytes for flags, 1 byte for type and a
string for the "format string"; flags and type are defined in
<sys/sysctl.h>. Macros to deal with info:
SYSCTLMIF_INFOFLAGS(info) returns flags;
SYSCTLMIF_INFOTYPE(info) returns the type;
SYSCTLMIF_INFOKIND(info) returns flags following by type;
SYSCTLMIF_INFOFMT(info) returns a pointer to the "format string".
The previous functions seek the object with id and idlevel or name, then
the property is copied into the buffer (e.g., desc, label, idnext, etc.).
Before the call buflen (e.g., desclen, lebellen, idnextlevel, etc.)
gives the size of buffer, after a successful call buflen gives the amount
of data copied; the size of the property can be determined with the NULL
argument for the buffer, the size will be returned in the location
pointed to by buflen. Note, the value of idnextlevel represents the
number of elements of idnext, not its size in byte.
SYSCTLMIF_NAMELEN(), SYSCTLMIF_DESCLEN() and SYSCTLMIF_LABELLEN() set
namelen, desclen, and labellen like the object with id and idlevel.
High-level API
The sysctlmibinfo library defines a struct for the info of an object:
SLIST_HEAD(sysctlmif_list, sysctlmif_object);
struct sysctlmif_object {
SLIST_ENTRY(sysctlmif_object) object_link;
int *id; /* array of idlevel entries */
size_t idlevel; /* between 1 and SYSCTLMIF_MAXIDLEVEL */
char *name; /* name in MIB notation */
char *desc; /* description */
char *label; /* aggregation label */
uint8_t type; /* defined in <sys/sysctl.h> */
uint32_t flags; /* defined in <sys/sysctl.h> */
char *fmt; /* format string */
struct sysctlmif_list *children; /* children list */
};
/*
* OR FLAGS: object fields to set,
* id and idlevel are always set,
* children list is set by sysctlmif_tree() and sysctlmif_mib().
*/
#define SYSCTLMIF_FNAME 0x01 /* name */
#define SYSCTLMIF_FDESC 0x02 /* desc */
#define SYSCTLMIF_FLABEL 0x04 /* label */
#define SYSCTLMIF_FTYPE 0x08 /* type */
#define SYSCTLMIF_FFLAGS 0x10 /* flags */
#define SYSCTLMIF_FFMT 0x20 /* fmt */
#define SYSCTLMIF_FALL /* all */
and a list of objects, struct sysctlmif_list, iterable by the SLIST
macros, see queue(3) and EXAMPLES.
sysctlmif_object() returns a pointer to the allocated memory for a struct
sysctlmif_object, setting flags members, of the object with id and
idlevel. The pointer can be passed to sysctlmif_freeobject() to free the
memory.
sysctlmif_filterlist() allocates memory for a SLIST of sysctlmif_object,
setting flags members, an object is added if filterfunc returns 0 or is
NULL; sysctlmif_filterlist() uses sysctlmif_nextnode() and
object.children is not set.
SYSCTLMIF_LIST() allocates memory and returns a SLIST of
sysctlmif_object, setting flags members, it is an alias for
sysctlmif_filterlist(NULL, flags).
sysctlmif_grouplist() allocates memory and returns a SLIST of
sysctlmif_object, setting flags members, visited in a "Depth First
Traversal" until max_depth, id and idlevel denote the root. Note:
sysctlmif_grouplist() uses sysctlmif_nextnode(), object.children is not
set and max_depth can be set to SYSCTLMIF_MAXDEPTH.
sysctlmif_freelist() frees the allocated memory of list.
sysctlmif_tree() allocates memory for a tree of sysctlmif_object, setting
flags members, until max_depth and returns a pointer to the root denoted
by the entry with id and idlevel. Note: max_depth can be set to
SYSCTLMIF_MAXDEPTH, object.children is set and iterable by SLIST macros.
The pointer can be passed to sysctlmif_freetree() to free the memory.
sysctlmif_mib() allocates memory for a collection of trees, setting flags
members, and returns a list where the entries are the roots representing
the top-level objects, sysctlmif_freemib() frees the allocated memory.
RETURN VALUES
The sysctlmif_nametoid(), SYSCTLMIF_NAMELEN(), sysctlmif_name(),
SYSCTLMIF_DESCLEN(), sysctlmif_desc(), SYSCTLMIF_LABELLEN(),
sysctlmif_label(), sysctlmif_info(), sysctlmif_nextnode(), and
sysctlmif_nextleaf() functions return the value 0 if successful;
otherwise the value -1 is returned and the global variable errno is set
to indicate the error.
The sysctlmif_object(), sysctlmif_filterlist(), SYSCTLMIF_LIST(),
sysctlmif_grouplist(), sysctlmif_tree(), sysctlmif_mib() functions return
NULL upon error or a pointer to allocated memory for success.
EXAMPLES
Complete set of examples:
https://gitlab.com/alfix/sysctlmibinfo/tree/master/examples
If installed:
/usr/local/share/examples/sysctlmibinfo/
Example to print the Sound Driver objects:
struct sysctlmif_list *list;
struct sysctlmif_object *obj;
int id[2], i;
size_t idlevel = 2;
size_t namelen = strlen("hw.snd") + 1;
if ((sysctlmif_nametoid("hw.snd", namelen, id, &idlevel)) != 0)
return (1);
list = sysctlmif_grouplist(id, idlevel, SYSCTLMIF_FALL,
SYSCTLMIF_MAXDEPTH);
if (list == NULL)
return (1);
SLIST_FOREACH(obj, list, object_link) {
printf("OID:");
for(i = 0; i < obj->idlevel; i++)
printf(" %d", obj->id[i]);
printf("\n");
printf("name: %s\n", obj->name);
printf("descr: %s\n", obj->desc ? obj->desc : "");
printf("label: %s\n", obj->label ? obj->label : "");
printf("flags: %u\n", obj->flags);
printf("type: %u\n", obj->type);
printf("fmt: %s\n", obj->fmt);
printf("----------------------\n");
}
sysctlmif_freelist(list);
SEE ALSO
queue(3), sysctl(3), sysctlmibinfo2(3)
HISTORY
The sysctlmibinfo library first appeared in FreeBSD 13.0.
AUTHORS
Alfonso Sabato Siciliano <alf.siciliano@gmail.com>.
CAVEATS
sysctlmif_nextleaf() does not return an object with the CTLFLAG_SKIP.
FreeBSD < 13, sysctlmif_nextnode() does not return an object with the
CTLFLAG_SKIP flag and requires extra computation in userspace because the
kernel returns only the next leaf.
sysctlmif_desc() could set desc to: "" or NULL for an object without
description.
The undocumented interface does not support Capability Mode so the kernel
returns the properties of an object without considering cap_enter(2),
CTLFLAG_CAPRD and CTLFLAG_CAPWR.
sysctlmif_nametoid() cannot manage a name expanded with an input for the
object handler, e.g., "kern.proc.pid.1"; the kernel interface does not
consider if an object is a CTLTYPE_NODE with a defined handler.
sysctlmif_name() could build a fake name up to 10 digits depending on id,
e.g., 1.1.100.500.1000 -> "kern.ostype.100.500.1000", if no object has
the specified OID; properly the kernel interface does not check if an
object is a CTLTYPE_NODE with a defined handler.
sysctlmif_object() is inefficient because the kernel needs to find many
times the same object to get all its properties.
BUGS
The kernel can store an object with an OID of CTL_MAXNAME levels but the
kernel undocumented interface can handle an OID up to CTL_MAXNAME-2;
except sysctlmif_name(), this library could fail with a false negative.
sysctlmif_nametoid() could return a wrong OID if some level name has a
NULL string, e.g., "security.jail.param.allow.mount.".
FreeBSD 13.0-ALPHA1 February 9, 2021 FreeBSD 13.0-ALPHA1