Manual sysctlmibinfo

Posted on 2019-01-25 - Updated on 2021-02-09

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