SYSCTL(9)
π SYSCTL π
okay bestie, gather round π«Ά this is the SYSCTL(9) page from the Kernel Developer's Manual, and it is literally the blueprint for every sysctl you'll ever build. it's a long one so we're doing it in parts β buckle up, hydrate, let's go β¨
πΈ NAME πΈ
no cap, this page is a whole friend group. it covers all of these cuties:
SYSCTL_DECL, SYSCTL_ADD_INT, SYSCTL_ADD_LONG, SYSCTL_ADD_NODE, SYSCTL_ADD_NODE_WITH_LABEL, SYSCTL_ADD_OPAQUE, SYSCTL_ADD_PROC, SYSCTL_ADD_QUAD, SYSCTL_ADD_ROOT_NODE, SYSCTL_ADD_S8, SYSCTL_ADD_S16, SYSCTL_ADD_S32, SYSCTL_ADD_S64, SYSCTL_ADD_STRING, SYSCTL_ADD_CONST_STRING, SYSCTL_ADD_STRUCT, SYSCTL_ADD_TIMEVAL_SEC, SYSCTL_ADD_U8, SYSCTL_ADD_U16, SYSCTL_ADD_U32, SYSCTL_ADD_U64, SYSCTL_ADD_UAUTO, SYSCTL_ADD_UINT, SYSCTL_ADD_ULONG, SYSCTL_ADD_UQUAD, SYSCTL_CHILDREN, SYSCTL_STATIC_CHILDREN, SYSCTL_NODE_CHILDREN, SYSCTL_PARENT, SYSCTL_INT, SYSCTL_INT_WITH_LABEL, SYSCTL_LONG, sysctl_msec_to_ticks, SYSCTL_NODE, SYSCTL_NODE_WITH_LABEL, SYSCTL_OPAQUE, SYSCTL_PROC, SYSCTL_QUAD, SYSCTL_ROOT_NODE, SYSCTL_S8, SYSCTL_S16, SYSCTL_S32, SYSCTL_S64, SYSCTL_STRING, SYSCTL_CONST_STRING, SYSCTL_STRUCT, SYSCTL_TIMEVAL_SEC, SYSCTL_U8, SYSCTL_U16, SYSCTL_U32, SYSCTL_U64, SYSCTL_UINT, SYSCTL_ULONG, SYSCTL_UQUAD β Dynamic and static sysctl MIB creation functions π
β¨ SYNOPSIS β¨
first things first, you gotta pull in the headers:
#include <sys/param.h>
#include <sys/sysctl.h>
then here's the whole menu of prototypes, exactly as they come, no edits, no cap π
SYSCTL_DECL(name);
struct sysctl_oid *
SYSCTL_ADD_INT(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int *ptr, int val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_LONG(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, long *ptr, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_NODE(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int (*handler)(SYSCTL_HANDLER_ARGS),
const char *descr);
struct sysctl_oid *
SYSCTL_ADD_NODE_WITH_LABEL(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int (*handler)(SYSCTL_HANDLER_ARGS),
const char *descr, const char *label);
struct sysctl_oid *
SYSCTL_ADD_OPAQUE(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, void *ptr, intptr_t len, const char *format,
const char *descr);
struct sysctl_oid *
SYSCTL_ADD_PROC(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, void *arg1, intptr_t arg2,
int (*handler) (SYSCTL_HANDLER_ARGS), const char *format,
const char *descr);
struct sysctl_oid *
SYSCTL_ADD_QUAD(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int64_t *ptr, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_ROOT_NODE(struct sysctl_ctx_list *ctx, int number,
const char *name, int ctlflags, int (*handler)(SYSCTL_HANDLER_ARGS),
const char *descr);
struct sysctl_oid *
SYSCTL_ADD_S8(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int8_t *ptr, int8_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_S16(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int16_t *ptr, int16_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_S32(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int32_t *ptr, int32_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_S64(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, int64_t *ptr, int64_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_STRING(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, char *ptr, intptr_t len, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_CONST_STRING(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, const char *ptr, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_STRUCT(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, void *ptr, struct_type, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_TIMEVAL_SEC(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, struct timeval *ptr, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_U8(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, uint8_t *ptr, uint8_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_U16(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, uint16_t *ptr, uint16_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_U32(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, uint32_t *ptr, uint32_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_U64(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, uint64_t *ptr, uint64_t val, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_UINT(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, unsigned int *ptr, unsigned int val,
const char *descr);
struct sysctl_oid *
SYSCTL_ADD_ULONG(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, unsigned long *ptr, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_UQUAD(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, uint64_t *ptr, const char *descr);
struct sysctl_oid *
SYSCTL_ADD_UAUTO(struct sysctl_ctx_list *ctx,
struct sysctl_oid_list *parent, int number, const char *name,
int ctlflags, void *ptr, const char *descr);
struct sysctl_oid_list *
SYSCTL_CHILDREN(struct sysctl_oid *oidp);
struct sysctl_oid_list *
SYSCTL_STATIC_CHILDREN(struct sysctl_oid_list OID_NAME);
struct sysctl_oid_list *
SYSCTL_NODE_CHILDREN(parent, name);
struct sysctl_oid *
SYSCTL_PARENT(struct sysctl_oid *oid);
SYSCTL_INT(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_INT_WITH_LABEL(parent, number, name, ctlflags, ptr, val, descr,
label);
SYSCTL_LONG(parent, number, name, ctlflags, ptr, val, descr);
int
sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS);
SYSCTL_NODE(parent, number, name, ctlflags, handler, descr);
SYSCTL_NODE_WITH_LABEL(parent, number, name, ctlflags, handler, descr,
label);
SYSCTL_OPAQUE(parent, number, name, ctlflags, ptr, len, format, descr);
SYSCTL_PROC(parent, number, name, ctlflags, arg1, arg2, handler, format,
descr);
SYSCTL_QUAD(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_ROOT_NODE(number, name, ctlflags, handler, descr);
SYSCTL_S8(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_S16(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_S32(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_S64(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_STRING(parent, number, name, ctlflags, arg, len, descr);
SYSCTL_CONST_STRING(parent, number, name, ctlflags, arg, descr);
SYSCTL_STRUCT(parent, number, name, ctlflags, ptr, struct_type, descr);
SYSCTL_TIMEVAL_SEC(parent, number, name, ctlflags, ptr, descr);
SYSCTL_U8(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_U16(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_U32(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_U64(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_UINT(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_ULONG(parent, number, name, ctlflags, ptr, val, descr);
SYSCTL_UQUAD(parent, number, name, ctlflags, ptr, val, descr);
π¦ DESCRIPTION π¦
so here's the vibe π the SYSCTL kernel interface is what lets you create sysctl(8) MIB entries β either dynamically or statically. it's giving main character energy for kernel config, fr fr.
and the glow-up? β¨ all static sysctls are automatically destroyed when the module which they are part of is unloaded. no cleanup code, no manual teardown, it just handles itself. obsessed. π
also, most top level categories are created statically and are available to all kernel code and its modules β so they're just there for everyone, like the group chat that never dies. π
ok but for real, this is only part 1 and there's so much more coming β we haven't even gotten to the OPTIONS yet bestie, stay tuned π
β¨ DESCRIPTION OF ARGUMENTS β¨
ok so before we touch literally anything, bestie, we gotta meet the cast π every single one of these args shows up all over this page, so let's get acquainted.
ctxβ your pointer to the sysctl context, orNULLif you're rolling with no context at all. Wanna make a fresh one? Go peek atsysctl_ctx_init(9). Now listen closely: programmers are strongly advised to use contexts to keep their dynamic OIDs organized, because the second a context gets destroyed, every sysctl that belongs to it goes down with it. That makes your cleanup code so much simpler. If you skip this, you gotta delete every single OID you created at module unload. no cap. πparentβ a pointer to astruct sysctl_oid_list, which is the head of the parent's list of children. Grab it with theSYSCTL_STATIC_CHILDREN()macro for static sysctls, orSYSCTL_CHILDREN()for dynamic ones. There's alsoSYSCTL_PARENT()if you need to get the parent of an OID β heads up, that macro hands youNULLwhen there's no parent. π¦numberβ the OID number that's getting assigned to this OID. Like, in almost literally every case you want this set toOID_AUTO, which just means "give me the next available OID number." iconic.nameβ the name of the OID. Your shiny new OID keeps a copy of it. πctlflagsβ a bit mask of sysctl control flags. There's a whole section below about all the control flags, so go read that. πarg1β first callback argument for procedure sysctls.arg2β second callback argument for procedure sysctls.lenβ the length of the data thatptrpoints at. Special case alert: for string type OIDs, a length of zero meansstrlen(3)gets used to figure out the string length every single time the OID is accessed. every. single. time. πΈptrβ pointer to your sysctl variable or string data. For sysctl values, this pointer can beSYSCTL_NULL_XXX_PTR, which means the OID is read-only and the returned value comes from thevalargument instead.valβ ifptrisSYSCTL_NULL_XXX_PTR, this gives the constant value this OID returns. Otherwise? Not used. that's it, that's the whole job. πstruct_typeβ name of the structure type.handlerβ a pointer to the function that handles read and write requests for this OID. There's a bunch of standard handlers supporting operations on nodes, integers, strings, and opaque objects. Wanna go custom? Define your own with theSYSCTL_PROC()macro or theSYSCTL_ADD_PROC()function. main character energy. π₯formatβ a pointer to a string that describes the OID's format in a symbolic way. This is a hint thatsysctl(8)uses to apply the right data formatting for display purposes. β¨
Here's the current lineup of formats:
Nβ nodeAβchar *IβintIK[n]β temperature in Kelvin, multiplied by an optional single digit power of ten scaling factor:1(the default) gives deciKelvin,0gives Kelvin, and3gives milliKelvinIUβunsigned intLβlongLUβunsigned longQβquad_tQUβu_quad_tS,TYPEβstruct TYPEstructures
descrβ a pointer to a textual description of the OID.labelβ a pointer to an aggregation label for this component of the OID. Want to export your sysctl data to monitoring systems that do aggregations through labels (hi, Prometheus π)? This argument lets you attach a label name to an OID. The label is a hint that this component's name shouldn't be part of the metric's name β instead it gets attached to the metric as a label.
Only put labels on siblings that are structurally similar and encode the same type of value. If they don't, aggregation is literally of no use. π ββοΈ
π NODE VALUE TYPES π
Most of the macros and functions that build sysctl nodes export either a read-only constant or an in-kernel variable, and the type of that thing matches the type of the node's value. Like, SYSCTL_INT() reports the raw value of an associated variable of type int. simple.
But plot twist π« β nodes can also export a value that's a translation of some internal representation.
The sysctl_msec_to_ticks() handler works with SYSCTL_PROC() or SYSCTL_ADD_PROC() to export a millisecond time interval. When you use this handler, the arg2 parameter points to an in-kernel variable of type int that stores a tick count suitable for functions like tsleep(9). When it's reporting the node's value, sysctl_msec_to_ticks() converts that value into milliseconds. Same deal in reverse, bestie: it accepts new values in milliseconds and stores the equivalent tick value into *arg2. π«Ά
The SYSCTL_ADD_TIMEVAL_SEC() function and the SYSCTL_TIMEVAL_SEC() macro create nodes that export an in-kernel variable of type struct timeval. Heads up though β these nodes do not export the full value of that associated structure. Instead they export a count in seconds as a simple integer, stored in the tv_sec field of the associated variable. These are meant for variables holding a non-negative interval rather than an absolute time. Because of that, they reject any attempt to store a negative value. periodt. π«
π³ CREATING ROOT NODES π³
Sysctl MIBs (aka OIDs) live in a hierarchical tree. The nodes all the way at the bottom of that tree are the root nodes, and they have no parent OID. To build those bottom-of-the-tree nodes you use the SYSCTL_ROOT_NODE() macro or the SYSCTL_ADD_ROOT_NODE() function. π±
By default, all static sysctl node OIDs are global, which means you need a SYSCTL_DECL() statement before their SYSCTL_NODE() definition statement β usually in a so-called header file. iykyk. π
π CREATING SYSCTL STRINGS π
Zero-terminated character string sysctls get created with either the SYSCTL_STRING() macro or the SYSCTL_ADD_STRING() function. If the len argument is zero, the string length gets computed on every access to the OID using strlen(3). Wanna add a sysctl for a constant string? Use the SYSCTL_CONST_STRING() macro or the SYSCTL_ADD_CONST_STRING() function. π
π¦ CREATING OPAQUE SYSCTLS π¦
The SYSCTL_OPAQUE() or SYSCTL_STRUCT() macros β or the SYSCTL_ADD_OPAQUE() or SYSCTL_ADD_STRUCT() functions β create an OID that handles any chunk of data, sized by the len argument and pointed at by the ptr argument. When you use the structure version, the type gets encoded as part of the created sysctl. cute. π«Ά
π CREATING CUSTOM SYSCTLS π
The SYSCTL_PROC() macro and the SYSCTL_ADD_PROC() function create OIDs with whatever handler function you specify. That handler is responsible for handling all read and write requests to the OID. This OID type is especially handy when the kernel data isn't easily accessible, or when it needs to be processed before it gets exported. chef's kiss. π₯
β CREATING A STATIC SYSCTL β
Static sysctls get declared using one of these macros:
SYSCTL_INT(), SYSCTL_INT_WITH_LABEL(), SYSCTL_LONG(), SYSCTL_NODE(), SYSCTL_NODE_WITH_LABEL(), SYSCTL_OPAQUE(), SYSCTL_PROC(), SYSCTL_QUAD(), SYSCTL_ROOT_NODE(), SYSCTL_S8(), SYSCTL_S16(), SYSCTL_S32(), SYSCTL_S64(), SYSCTL_STRING(), SYSCTL_CONST_STRING(), SYSCTL_STRUCT(), SYSCTL_TIMEVAL_SEC(), SYSCTL_U8(), SYSCTL_U16(), SYSCTL_U32(), SYSCTL_U64(), SYSCTL_UINT(), SYSCTL_ULONG() or SYSCTL_UQUAD().
π CREATING A DYNAMIC SYSCTL π
Dynamic nodes get created using one of these functions:
SYSCTL_ADD_INT(), SYSCTL_ADD_LONG(), SYSCTL_ADD_NODE(), SYSCTL_ADD_NODE_WITH_LABEL(), SYSCTL_ADD_OPAQUE(), SYSCTL_ADD_PROC(), SYSCTL_ADD_QUAD(), SYSCTL_ADD_ROOT_NODE(), SYSCTL_ADD_S8(), SYSCTL_ADD_S16(), SYSCTL_ADD_S32(), SYSCTL_ADD_S64(), SYSCTL_ADD_STRING(), SYSCTL_ADD_CONST_STRING(), SYSCTL_ADD_STRUCT(), SYSCTL_ADD_TIMEVAL_SEC(), SYSCTL_ADD_U8(), SYSCTL_ADD_U16(), SYSCTL_ADD_U32(), SYSCTL_ADD_U64(), SYSCTL_ADD_UAUTO(), SYSCTL_ADD_UINT(), SYSCTL_ADD_ULONG(), or SYSCTL_UQUAD().
Wanna destroy a dynamically created OID? Go read sysctl_remove_oid(9) or sysctl_ctx_free(9) for all the deets. β¨
β¨ CONTROL FLAGS β¨
okay so real talk π for most of the functions and macros we've been yapping about up there, you don't have to declare a type as part of the access flags. but β and this is the part that matters β when you're declaring a sysctl that's implemented by a function, putting a type in the access mask is literally required. no type, no service, bestie. π
so here's the type menu:
CTLTYPE_NODEβ this is a node that's meant to be a parent for other nodes. the mom friend of the tree π³CTLTYPE_INTβ a signed integer.CTLTYPE_STRINGβ a nul-terminated string, stored in a character array.CTLTYPE_S8β an 8-bit signed integer.CTLTYPE_S16β a 16-bit signed integer.CTLTYPE_S32β a 32-bit signed integer.CTLTYPE_S64β a 64-bit signed integer.CTLTYPE_OPAQUEβ an opaque data structure. mysterious. iconic. π«₯CTLTYPE_STRUCTβ alias forCTLTYPE_OPAQUE. same vibe, different name.CTLTYPE_U8β an 8-bit unsigned integer.CTLTYPE_U16β a 16-bit unsigned integer.CTLTYPE_U32β a 32-bit unsigned integer.CTLTYPE_U64β a 64-bit unsigned integer.CTLTYPE_UINTβ an unsigned integer.CTLTYPE_LONGβ a signedlong.CTLTYPE_ULONGβ an unsignedlong.
so like, every sysctl type except for new node declarations needs one of these next flags set, because they tell you the read/write disposition of the sysctl. it's giving "pick a lane" energy:
CTLFLAG_RDβ this is a read-only sysctl. look, don't touch. πCTLFLAG_RDTUNβ a read-only sysctl and tunable, and the system tries to fetch it once from the system environment early during module load or system boot.CTLFLAG_WRβ this is a writable sysctl.CTLFLAG_RWβ readable and writable. the full experience β¨CTLFLAG_RWTUNβ a readable and writeable sysctl and tunable, and the system tries to fetch it once from the system environment early during module load or system boot.CTLFLAG_NOFETCHβ if your node got marked as a tunable using theCTLFLAG_[XX]TUN, this flag stops the initial value from being fetched out of the system environment. and ngl, you should basically only reach for this in very early low level system setup code β not in regular drivers and modules, bestie, don't be bold.CTLFLAG_MPSAFEβ thissysctl(9)handler is MP safe, so do not grab Giant around calls to it. this one should only be used forSYSCTL_PROC()entries. π‘οΈ
and on top of all that, any of these optional flags can also be specified:
CTLFLAG_ANYBODYβ any user or process can write to this sysctl.CTLFLAG_CAPRDβ a process in capability mode can read from this sysctl.CTLFLAG_CAPWRβ a process in capability mode can write to this sysctl.CTLFLAG_SECUREβ this sysctl can be written to only if the effective securelevel of the process is β€ 0.CTLFLAG_PRISONβ this sysctl can be written to by processes injail(2).CTLFLAG_SKIPβ when iterating the sysctl name space, do not list this sysctl. stealth mode πCTLFLAG_TUNβ advisory flag that a system tunable also exists for this variable. the initial sysctl value is tried fetched once from the system environment early during module load or system boot.CTLFLAG_DYNβ dynamically created OIDs automatically get this flag set. it's automatic, you don't gotta do anything πCTLFLAG_VNETβ OID references a VIMAGE-enabled variable.
πΈ EXAMPLES πΈ
a lil sample of SYSCTL_DECL() declaring the security sysctl tree so new nodes can use it:
SYSCTL_DECL(_security);
and here come the integer, opaque, string, and procedure sysctl examples. buckle up π
/*
* Example of a constant integer value. Notice that the control
* flags are CTLFLAG_RD, the variable pointer is SYSCTL_NULL_INT_PTR,
* and the value is declared.
*/
SYSCTL_INT(_debug_sizeof, OID_AUTO, bio, CTLFLAG_RD, SYSCTL_NULL_INT_PTR,
sizeof(struct bio), "sizeof(struct bio)");
/*
* Example of a variable integer value. Notice that the control
* flags are CTLFLAG_RW, the variable pointer is set, and the
* value is 0.
*/
static int doingcache = 1; /* 1 => enable the cache */
SYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0,
"Enable name cache");
/*
* Example of a variable string value. Notice that the control
* flags are CTLFLAG_RW, that the variable pointer and string
* size are set. Unlike newer sysctls, this older sysctl uses a
* static oid number.
*/
char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */
SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW,
kernelname, sizeof(kernelname), "Name of kernel file booted");
/*
* Example of an opaque data type exported by sysctl. Notice that
* the variable pointer and size are provided, as well as a format
* string for sysctl(8).
*/
static l_fp pps_freq; /* scaled frequency offset (ns/s) */
SYSCTL_OPAQUE(_kern_ntp_pll, OID_AUTO, pps_freq, CTLFLAG_RD,
&pps_freq, sizeof(pps_freq), "I", "");
/*
* Example of a procedure based sysctl exporting string
* information. Notice that the data type is declared, the NULL
* variable pointer and 0 size, the function pointer, and the
* format string for sysctl(8).
*/
SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING |
CTLFLAG_RW, NULL, 0, sysctl_kern_timecounter_hardware, "A",
"");
and here's how you'd create a brand new top-level category and hook another subtree onto an existing static node. heads up though: this example doesn't use contexts, which means you're stuck doing tedious management of all the intermediate oids, because you have to free them later. it's giving unpaid internship π
#include <sys/sysctl.h>
...
/*
* Need to preserve pointers to newly created subtrees,
* to be able to free them later:
*/
static struct sysctl_oid *root1;
static struct sysctl_oid *root2;
static struct sysctl_oid *oidp;
static int a_int;
static char *string = "dynamic sysctl";
...
root1 = SYSCTL_ADD_ROOT_NODE(NULL,
OID_AUTO, "newtree", CTLFLAG_RW, 0, "new top level tree");
oidp = SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(root1),
OID_AUTO, "newint", CTLFLAG_RW, &a_int, 0, "new int leaf");
...
root2 = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_debug),
OID_AUTO, "newtree", CTLFLAG_RW, 0, "new tree under debug");
oidp = SYSCTL_ADD_STRING(NULL, SYSCTL_CHILDREN(root2),
OID_AUTO, "newstring", CTLFLAG_RD, string, 0, "new string leaf");
this example creates these subtrees right here:
debug.newtree.newstring
newtree.newint
β οΈ bestie, care should be taken to free all OIDs once they are no longer needed! do not leave them lying around, that's not the vibe. π¨
π SYSCTL NAMING π
okay so when you're adding, modifying, or removing sysctl names, you need to understand something: these interfaces may be used by users, libraries, applications, or documentation (yes, like published books π), which means they are implicitly published application interfaces. and just like any other application interface, you have to be careful not to break existing applications β and you gotta think about the future use of new name spaces so you don't end up needing to rename or remove interfaces that people might depend on later. no pressure. π
the semantics you pick for a new sysctl should be as clear as possible, and the name of the sysctl must closely reflect its semantics. so yeah, the name deserves a fair amount of consideration. it should be short, but still representative of what the sysctl actually means. if the name is several words, separate them with underscore characters, like in compute_summary_at_mount. and underscore characters may be omitted only if the name is not more than two words, each being not longer than four characters, like in bootfile.
and for boolean sysctls? negative logic should be totally avoided. like, do not use names like no_foobar or foobar_disable. they're confusing and they lead to configuration errors. use positive logic instead: foobar, foobar_enable. manifest the yes, not the no β¨
a temporary sysctl node OID that should not be relied upon has to be designated as such with a leading underscore character in its name. for example: _dirty_hack. π«£
π SEE ALSO π
π HISTORY π
the sysctl(8) utility first appeared in 4.4BSD. an elder. a legend. π«Ά
π¦ AUTHORS π¦
the sysctl implementation originally found in BSD has been extensively rewritten by Poul-Henning Kamp in order to add support for name lookups, name space iteration, and dynamic addition of MIB nodes. absolute icon behaviour. π
this man page was written by Robert N. M. Watson.
π₯ SECURITY CONSIDERATIONS π₯
when you're creating new sysctls, pay careful attention to the security implications of the monitoring or management interface you're creating. most sysctls present in the kernel are read-only, or writable only by the superuser. and sysctls that export extensive information on system data structures and operation β especially those implemented using procedures β will want to implement access control to limit the undesired exposure of information about other processes, network connections, etc. be mindful, bestie. π
these top level sysctl name spaces are the ones commonly used:
compatβ Compatibility layer information.debugβ Debugging information. Various name spaces exist underdebug.hwβ Hardware and device driver information.kernβ Kernel behavior tuning; generally deprecated in favor of more specific name spaces.machdepβ Machine-dependent configuration parameters.netβ Network subsystem. Various protocols have name spaces undernet.regressionβ Regression test configuration and information.securityβ Security and security-policy configuration and information.sysctlβ Reserved name space for the implementation of sysctl.userβ Configuration settings relating to user application behavior. Generally, configuring applications using kernel sysctls is discouraged.vfsβ Virtual file system configuration and information.vmβ Virtual memory subsystem configuration and information.
and that's the whole page, bestie!! πβ¨ this one came from the Debian folks and it's dated June 11, 2019 β so like, vintage, but in a good way. now go forth and sysctl responsibly, my main character. mwah ππ¦π
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2006 Robert N. M. Watson
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms