Index: share/man/man3/sysctlinfo.3 =================================================================== --- share/man/man3/sysctlinfo.3 +++ share/man/man3/sysctlinfo.3 @@ -0,0 +1,357 @@ +.\" +.\" Copyright (c) 2019 Alfonso Sabato Siciliano +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 10, 2019 +.Dt SYSCTLINFO 3 +.Os +.Sh NAME +.Nm SYSCTLINFO +.Nm SYSCTLINFO_BYNAME +.Nm SYSCTLINFO_HELPER_ALL +.Nm SYSCTLINFO_HELPER_ALLIWITHNEXT +.Nm SYSCTLINFO_HELPER_ALLWITHNEXTNAME +.Nd Interface for getting info about the sysctl tree +.\" .Sh LIBRARY +.\" For sections 2, 3, and 9 only. +.Sh SYNOPSIS +.In sys/types.h +.In sys/sysctl.h +.In sysctlinfo.h +.Fd #define CTL_SYSCTLMIB +.Fd #define ENTRYFAKENAME +.Fd #define ENTRYNAME +.Fd #define ENTRYDESC +.Fd #define ENTRYLABEL +.Fd #define ENTRYKIND +.Fd #define ENTRYFMT +.Fd #define ENTRYNEXTNODE +.Fd #define ENTRYNEXTLEAF +.Fd #define ENTRYALLINFO +.Fd #define ENTRYALLINFO_WITHNEXTNODE +.Fd #define ENTRYALLINFO_WITHNEXTLEAF +.Fd #define ENTRYIDBYNAME +.Fd #define ENTRYFAKEIDBYNAME +.Fd #define ENTRYDESCBYNAME +.Fd #define ENTRYLABELBYNAME +.Fd #define ENTRYKINDBYNAME +.Fd #define ENTRYFMTBYNAME +.Fd #define ENTRYALLINFOBYNAME +.Fd #define ENTRYALLINFOBYNAME_WITHNEXTNODE +.Fd #define ENTRYALLINFOBYNAME_WITHNEXTLEAF +.Ft "int" +.Fo SYSCTLINFO +.Fa "int *id" +.Fa "size_t idlevel" +.Fa "int prop[2]" +.Fa "void *buf" +.Fa "size_t *buflen" +.Fc +.Ft "int" +.Fn SYSCTLINFO_BYNAME "char *name" "int prop[2]" "void *buf" "size_t *buflen" +.Ft "void" +.Fo SYSCTLINFO_HELPER_ALL +.Fa "void *buf" +.Fa "size_t idlevel" +.Fa "int *id" +.Fa "char *namep" +.Fa "char *descrp" +.Fa "unsigned int kind" +.Fa "char *fmtp" +.Fa "char *labelp" +.Fc +.Ft "void" +.Fo SYSCTLINFO_HELPER_ALLWITHNEXT +.Fa "void *buf" +.Fa "size_t idlevel" +.Fa "int *id" +.Fa "char *namep" +.Fa "char *descrp" +.Fa "unsigned int kind" +.Fa "char *fmtp" +.Fa "char *labelp" +.Fa "size_t idnextlevel" +.Fa "int *idnext" +.Fc +.Ft "void" +.Fo SYSCTLINFO_HELPER_ALLWITHNEXTNAME +.Fa "void *buf" +.Fa "size_t idlevel" +.Fa "int *id" +.Fa "char *namep" +.Fa "char *descrp" +.Fa "unsigned int kind" +.Fa "char *fmtp" +.Fa "char *labelp" +.Fa "char *namenextp" +.Fc +.Sh DESCRIPTION +Macros to wrap the +.Xr sysctlinfo 4 +interface to explore the sysctl tree and to get info about the nodes. +.Fn SYSCTLINFO +and +.Fn SYSCLINFO_BYNAME +seek the node with +.Fa id +/ +.Fa idlevel +or +.Fa name , +then the information specified by +.Fa prop +is copied into the buffer +.Fa buf . +Before the call +.Fa buflen +gives the size of +.Fa buf , +after a successful call +.Fa buflen +gives the amount of data copied; the size of the info can be determined with the +NULL argument for +.Fa buf , +the size will be returned in the location pointed to by +.Fa buflen . +The value of +.Fa prop[0] +should be +.Dv CTL_SYSCTLMIB +and +.Fa prop[1] +can specify the desired info, the possible values are listed later. +.Pp +.Fn SYSCTLINFO +accepts an array +.Fa id +of +.Fa idlevel +elements (between 1 and CTL_MAXNAME) and the following +.Fa prop[1]: +.Bl -tag -width indent +.It Dv ENTRYFAKENAME +if the node exists +.Fa buf +is set like a string with its name, otherwise +.Nm sysctlinfo +build a name depending on the +.Fa id, +e.g., with an +.Fa id +[1.1.100.500.1000] the name is +.Dq kern.ostype.100.500.1000 . +.It Dv ENTRYNAME , Dv ENTRYDESC , Dv ENTRYLABEL and Dv ENTRYFMT +set +.Fa buf +like a string with the name, description, label and format respectively. +.It Dv ENTRYKIND +sets +.Fa buf +like a unsigned int with the kind of the node, its format is: 3 bytes for +flags and 1 byte for type, they are defined in +.In sys/sysctl.h . +.It Dv ENTRYNEXTNODE and Dv ENTRYNEXTLEAF +.Fa buf +is set like an integer array with the id of the next node/leaf of a Depth-First +Traversal, the next level is +.Dq buflen / sizeof(int) +to be consistent with the acceptable level range. +.It Dv ENTRYALLINFO +sets the +.Fa buf +with all the info of the node, it should be passed to the helper macro +.Fn SYSCTLINFO_HELPER_ALL , +if description, format or label is NULL, descp, fmtp or labep is set to +.Dq +respectively. +.It Dv ENTRYALLINFO_WITHNEXTNODE and Dv ENTRYALLINFO_WITHNEXTLEAF +set all the info of the node like +.Dv SYSCTLINFO_ALLINFO +with the next node/leaf, +.Fa buf +should be passed to +.Fn SYSCTLINFO_HELPER_ALLWITHNEXT , +if the node has not a next +.Fa idnextlevel +is set to 0. +.El +.Pp +.Fn SYSCTLINFO_BYNAME +accepts the following +.Fa prop[1]: +.Bl -tag -width indent +.It Dv ENTRYFAKEIDBYNAME and Dv ENTRYIDBYNAME +.Fa buf +is set like an integer array with the id of the node, the level is +.Dq buflen / sizeof(int) . +ENTRYFAKEIDBYNAME does not set the last level if its last level name is +.Dq , +e.g., +.Dq n1.n2.n3. +the id array is set to +[1.2.3]. +.It Dv ENTRYDESCBYNAME , Dv ENTRYLABELBYNAME and Dv ENTRYFMTBYNAME +set +.Fa buf +like a string with the description, label and format respectively. +.It Dv ENTRYKINDBYNAME +kind of an node, see +.Dv ENTRYKIND . +.It Dv ENTRYALLINFOBYNAME +sets the +.Fa buf +with all the info of the node, it should be passed to the helper macro +.Fn SYSCTLINFO_HELPER_ALL , +if description, format or label is NULL, descp, fmtp or labep is set to +.Dq +respectively. +.It Dv ENTRYALLINFOBYNAME_WITHNEXTNODE and Dv ENTRYALLINFOBYNAME_WITHNEXTLEAF +set all the info of the node like +.Dv SYSCTLINFO_ALLINFOBYNAME +with the next node/leaf, +.Fa buf +should be passed to +.Fn SYSCTLINFO_HELPER_ALLWITHNEXTNAME , +if the node has not a next node/leaf +.Fa nextnamep +is set to +.Dq . +.El +.Sh IMPLEMENTATION NOTES +The kernel provides an undocumented interface for the info of the sysctl tree, +obviously +.Nm sysctlinfo +and the kernel interface can coexist. +.Pp +In +.Dq capability mode , +see +.Xr cap_enter 2 , +.Nm sysctlinfo +checks if the node has the +.Dv CTLFLAG_CAPRD +or +.Dv CTLFLAG_CAPWR +flag before to return its info; +.Xr sysctl 3 +will check the +.Dq capability permission +to get or set a value. +.Dv ENTRYFAKENAME +has no capability check for compatibility with the kernel. +.Dv ENTRYNEXTNODE +and +.Dv ENTRYNEXTLEAF +check never the capability flags to traverse the tree also in capability mode. +.Pp +.Fn SYSCTLINFO +and +.Fn SYSCTLINFO_BYNAME +seek the node with the +.Fa id +/ +.Fa idlevel +or with the +.Fa name +then they share the same code. +.Sh RETURN VALUES +.Rv -std SYSCTLINFO SYSCTLINFO_BYNAME +.Sh EXAMPLES +If installed: +.Dl /usr/local/share/examples/sysctlinfo/ +.Pp +Example to visit the sysctl tree: +.Pp +.Bd -literal -offset indent -compact +int id[CTL_MAXNAME], *idp_unused, *idnextp; +size_t idlevel, idnextlevel, buflen, i; +char buf[BUFSIZE], *namep, *descrp, *fmtp, *labelp; +unsigned int kind; +int prop[2] = { CTL_SYSCTLMIB, ENTRYALLINFO_WITHNEXTNODE }; + +id[0]=0; +idlevel=1; + +for (;;) { + for (i = 0; i < idlevel; i++) + printf("%d%c", id[i], i+1 < idlevel ? '.' : '\\n'); + + buflen = BUFSIZE; + if(SYSCTLINFO(id, idlevel, prop, buf, &buflen) != 0) { + err(1, "ENTRYALLINFO_WITHNEXTNODE"); + + SYSCTLINFO_HELPER_ALLWITHNEXT(buf, idlevel, idp_unused, namep, descrp, + kind, fmtp, labelp, idnextlevel, idnextp); + + printf("name: %s\\n", namep); + printf("description: %s\\n", descrp); + printf("label: %s\\n", labelp); + printf("kind: %u\\n", kind ); + printf("\tflags: %u\\n", kind & 0xfffffff0 ); + printf("\ttype: %u\\n", kind & CTLTYPE ); + printf("fmt: %s\\n", fmtp); + printf("--------------------------------------\\n"); + + if (idnextlevel < 1) + break; + + memcpy(id, idnextp, idnextlevel * sizeof(int)); + idlevel = idnextlevel; +} +.Ed +.Sh ERRORS +The following errors may be reported: +.Bl -tag -width Er +.It Bq Er ECAPMODE +The node has not the CTLFLAG_CAPRD or CTLFLAG_CAPWR flag in capability mode. +.It Bq Er EINVAL +.Fa name +has more than CTL_MAXNAME levels. +.It Bq Er EINVAL +.Fa idlevel +is either greater CTL_MAXNAME, equal to zero or is not an integer. +.It Bq Er ENAMETOOLONG +.Fa name +is >= MAXPATHLEN. +.It Bq Er ENOATTR +The node exists but its info is NULL. +.It Bq Er ENOENT +The node does not exist. +.El +.Sh SEE ALSO +.Xr cap_enter 2 , +.Xr sysctl 3 , +.Xr sysctlinfo 4 +.\" .Sh STANDARDS +.Sh HISTORY +The +.Nm sysctlinfo +interface first appeared in +.Fx 13.0 . +.Sh AUTHORS +The +.Nm sysctlinfo +interface was written by +.An Alfonso S. Siciliano Aq Mt alf.siciliano@gmail.com Index: share/man/man4/sysctlinfo.4 =================================================================== --- share/man/man4/sysctlinfo.4 +++ share/man/man4/sysctlinfo.4 @@ -0,0 +1,77 @@ +.\" +.\" Copyright (c) 2019 Alfonso Sabato Siciliano +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd August 2, 2019 +.Dt SYSCTLINFO 4 +.Os +.Sh NAME +.Nm sysctlinfo +.Nd a +.Xr sysctl 3 +MIB for getting info about the sysctl tree +.Sh SYNOPSIS +.Cd sysctl sysctl.entryfakename +.Cd sysctl sysctl.entryname +.Cd sysctl sysctl.entrydesc +.Cd sysctl sysctl.entrylabel +.Cd sysctl sysctl.entrykind +.Cd sysctl sysctl.entryfmt +.Cd sysctl sysctl.entrynextnode +.Cd sysctl sysctl.entrynextleaf +.Cd sysctl sysctl.entryallinfo +.Cd sysctl sysctl.entryallinfo_withnextnode +.Cd sysctl sysctl.entryallinfo_withnextleaf +.Cd sysctl sysctl.entryfakeidbyname +.Cd sysctl sysctl.entryidbyname +.Cd sysctl sysctl.entrydescbyname +.Cd sysctl sysctl.entrylabelbyname +.Cd sysctl sysctl.entrykindbyname +.Cd sysctl sysctl.entryfmtbyname +.Cd sysctl sysctl.entryallinfobyname +.Cd sysctl sysctl.entryallinfobyname_withnextnode +.Cd sysctl sysctl.entryallinfobyname_withnextleaf +.Sh DESCRIPTION +The +.Nm +interface explores the sysctl tree to pass the info of the nodes to userland, +it should be used via +.Xr sysctlinfo 3 . +.\" .Sh IMPLEMENTATION NOTES +.\" .Sh ERRORS +.\" For sections 2, 3, 4, and 9 errno settings only. +.Sh SEE ALSO +.Xr sysctl 3 , +.Xr sysctlinfo 3 +.Sh HISTORY +The +.Nm sysctlinfo +interface first appeared in +.Fx 13.0 . +.Sh AUTHORS +The +.Nm sysctlinfo +interface was written by +.An Alfonso S. Siciliano Aq Mt alf.siciliano@gmail.com Index: sys/kern/kern_sysctl.c =================================================================== --- sys/kern/kern_sysctl.c +++ sys/kern/kern_sysctl.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -2836,3 +2837,399 @@ } #endif /* DDB */ + +/* + * sysctlinfo interface + */ + +/* Util */ +static int +sysctlinfo_next_node(struct sysctl_oid *path[CTL_MAXNAME], int id[CTL_MAXNAME], + size_t *level, int mode) +{ + struct sysctl_oid_list *children; + size_t l = *level; + + SYSCTL_ASSERT_LOCKED(); + + for(;;) { + children = SYSCTL_CHILDREN(path[l-1]); + if(children != NULL && !SLIST_EMPTY(children)) { /* children */ + path[l]=SLIST_FIRST(children); + l++; + } else { /* no children */ + for(;;) { + if(l <= 0) + break; + if(SLIST_NEXT(path[l-1], oid_link) != NULL) { /* brother */ + path[l-1] = SLIST_NEXT(path[l-1], oid_link); + break; + } + else /* no brother */ + l--; + } + } + + if(l <= 0 || l > CTL_MAXNAME) + return (ENOATTR); + + id[l-1]=path[l-1]->oid_number; + if(path[l-1]->oid_kind & (CTLFLAG_SKIP | CTLFLAG_DORMANT)) + continue; + + if(mode == ENTRYNEXTLEAF || mode == ENTRYALLINFO_WITHNEXTLEAF || + mode == ENTRYALLINFOBYNAME_WITHNEXTLEAF) { + if((path[l-1]->oid_kind & CTLTYPE) != CTLTYPE_NODE || + path[l-1]->oid_handler !=NULL) + break; + } else { + break; + } + } + + *level=l; + return 0; +} + +/* handler for the nodes */ +static int +sysctlinfo_interface(SYSCTL_HANDLER_ARGS) +{ + struct rm_priotracker tracker; + int error = 0, id[CTL_MAXNAME], indx = 0, i; + size_t idlevel; + struct sysctl_oid *oid, *path[CTL_MAXNAME]; + struct sysctl_oid_list *lsp = &sysctl__children; + char buf[SYSCTLINFO_MAXFAKE], name_input[MAXPATHLEN], *name_inputp; + bool all_flag, name_flag; + + /* + * Get id or name from userland + */ + name_flag = (arg2 == ENTRYIDBYNAME || arg2 == ENTRYFAKEIDBYNAME || + arg2 == ENTRYDESCBYNAME || arg2 == ENTRYKINDBYNAME || + arg2 == ENTRYFMTBYNAME || arg2 == ENTRYLABELBYNAME || + arg2 == ENTRYALLINFOBYNAME || + arg2 == ENTRYALLINFOBYNAME_WITHNEXTNODE || + arg2 == ENTRYALLINFOBYNAME_WITHNEXTLEAF) ? true : false; + + if(req->newlen == 0) + return (EINVAL); + + if(name_flag) { + if (req->newlen >= MAXPATHLEN) + return (ENAMETOOLONG); + memset(name_input, 0, MAXPATHLEN); + if((error = SYSCTL_IN(req, name_input, req->newlen)) !=0 ) + return (error); + idlevel=1; + for(i=0; inewlen; i++) { + if(name_input[i] == '.') { + name_input[i] = '\0'; + if(name_input[i+1] == '\0' && + arg2 == ENTRYFAKEIDBYNAME) + break; + idlevel++; + if(idlevel > CTL_MAXNAME) + return (EINVAL); + } + } + name_inputp = &name_input[0]; + } else { + if(req->newlen > CTL_MAXNAME * sizeof(int)) + return (EINVAL); + if(req->newlen % sizeof(int) != 0) + return (EINVAL); + if((error = SYSCTL_IN(req, id, req->newlen)) !=0 ) + return (error); + + idlevel = req->newlen / sizeof(int); + } + + /* Get lock */ + SYSCTL_RLOCK(&tracker); + + /* + * Find OID + */ + while (indx < idlevel) { + SLIST_FOREACH(oid, lsp, oid_link) { + if (name_flag) { + if(strcmp(name_inputp, oid->oid_name) == 0) + break; + } else { + if (oid->oid_number == id[indx]) + break; + } + } + if (oid == NULL) { + break; + } + path[indx] = oid; + if(name_flag) + id[indx] = oid->oid_number; + indx++; + + if (indx == idlevel) { + KASSERT((oid->oid_kind & CTLFLAG_DYING) == 0, + ("%s found DYING node %p", __func__, oid)); + + if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE && + (oid->oid_kind & CTLFLAG_DORMANT) != 0) { + error = ENOENT; + } + } else { /* indx < idlevel */ + if(name_flag) + name_inputp += (strlen(name_inputp) + 1); + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE && + oid->oid_handler == NULL) { + lsp = SYSCTL_CHILDREN(oid); + } else { + break; + } + } + } + + if(error || (indx != idlevel && arg2 != ENTRYFAKENAME)) { + error = ENOENT; + goto out; + } + + /* + * Capability check + */ +#ifdef CAPABILITY_MODE + if (IN_CAPABILITY_MODE(req->td)) { + if( !(oid->oid_kind & CTLFLAG_CAPRD) && + !(oid->oid_kind & CTLFLAG_CAPWR) && + arg2 != ENTRYFAKENAME && + arg2 != ENTRYNEXTNODE && + arg2 != ENTRYNEXTLEAF) { + error = ECAPMODE; + goto out; + } + } +#endif + + /* + * Pass info to the userland + */ + all_flag = (arg2 == ENTRYALLINFO || arg2 == ENTRYALLINFO_WITHNEXTNODE || + arg2 == ENTRYALLINFO_WITHNEXTLEAF || arg2 == ENTRYALLINFOBYNAME || + arg2 == ENTRYALLINFOBYNAME_WITHNEXTNODE || + arg2 == ENTRYALLINFOBYNAME_WITHNEXTLEAF) ? true : false; + + if(all_flag) { + if ((error = SYSCTL_OUT(req, &idlevel, sizeof (size_t))) != 0) + goto out; + } + + if(arg2 == ENTRYIDBYNAME || arg2 == ENTRYFAKEIDBYNAME || all_flag) { + if ((error = SYSCTL_OUT(req, id, idlevel * sizeof (int))) != 0) + goto out; + } + + if(arg2 == ENTRYNAME || arg2 == ENTRYFAKENAME || all_flag) { + for(i=0; i < idlevel; i++) { + if (i > 0) + if((error = SYSCTL_OUT(req, ".", 1)) != 0) + goto out; + + if (i < indx) { + error = SYSCTL_OUT(req, path[i]->oid_name, + strlen(path[i]->oid_name)); + } else { + snprintf(buf, sizeof(buf), "%d", id[i]); + error = SYSCTL_OUT(req, buf, strlen(buf)); + } + if (error) + goto out; + } + if((error = SYSCTL_OUT(req, "", 1)) != 0) + goto out; + } + + if (arg2 == ENTRYDESC || arg2 == ENTRYDESCBYNAME || all_flag) { + if (oid->oid_descr != NULL) { + if ((error = SYSCTL_OUT_STR(req, oid->oid_descr)) != 0) + goto out; + } else { + if (all_flag) { + if ((error = SYSCTL_OUT(req, "", 1)) != 0) + goto out; + } else { + error = ENOATTR; + goto out; + } + } + } + + if (arg2 == ENTRYKIND || arg2 == ENTRYKINDBYNAME || all_flag) { + error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind)); + if(error) + goto out; + } + + if (arg2 == ENTRYFMT || arg2 == ENTRYFMTBYNAME || all_flag) { + if (oid->oid_fmt != NULL) { + if ((error = SYSCTL_OUT_STR(req, oid->oid_fmt)) != 0) + goto out; + } else { + if (all_flag) { + if ((error = SYSCTL_OUT(req, "", 1)) != 0) + goto out; + } else { + error = ENOATTR; + goto out; + } + } + } + + if(arg2 == ENTRYLABEL || arg2 == ENTRYLABELBYNAME || all_flag) { + if (oid->oid_label != NULL) { + if ((error = SYSCTL_OUT_STR(req, oid->oid_label)) != 0) + goto out; + } else { + if (all_flag) { + if ((error = SYSCTL_OUT(req, "", 1)) != 0) + goto out; + } else { + error = ENOATTR; + goto out; + } + } + } + + if(arg2 == ENTRYALLINFO_WITHNEXTNODE || + arg2 == ENTRYALLINFO_WITHNEXTLEAF || + arg2 == ENTRYALLINFOBYNAME_WITHNEXTNODE || + arg2 == ENTRYALLINFOBYNAME_WITHNEXTLEAF || + arg2 == ENTRYNEXTNODE || arg2 == ENTRYNEXTLEAF) { + + error = sysctlinfo_next_node(path, id, &idlevel, arg2); + if(error != 0) { + if(all_flag) + idlevel=0; + else + goto out; + } + if(arg2 == ENTRYALLINFO_WITHNEXTNODE || + arg2 == ENTRYALLINFO_WITHNEXTLEAF) { + error = SYSCTL_OUT(req, &idlevel, sizeof (size_t)); + if (error) + goto out; + } + + if(arg2 != ENTRYALLINFOBYNAME_WITHNEXTNODE && + arg2 != ENTRYALLINFOBYNAME_WITHNEXTLEAF) { + error = SYSCTL_OUT(req, id, idlevel * sizeof (int)); + } else { + for(i=0; i < idlevel; i++) { + if (i > 0) + error = SYSCTL_OUT(req, ".", 1); + if (!error) { + error = SYSCTL_OUT(req, path[i]->oid_name, + strlen(path[i]->oid_name)); + } + if (error) + goto out; + } + error = SYSCTL_OUT(req, "", 1); + } + } + + out: + SYSCTL_RUNLOCK(&tracker); + return (error); +} + +/* sysctlinfo nodes */ +SYSCTL_PROC(_sysctl, ENTRYFAKENAME, entryfakename, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYFAKENAME, + sysctlinfo_interface, "A", "fake name of an object"); + +SYSCTL_PROC(_sysctl, ENTRYNAME, entryname, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_ANYBODY |CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYNAME, + sysctlinfo_interface, "A", "name of an object"); + +SYSCTL_PROC(_sysctl, ENTRYDESC, entrydesc, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_ANYBODY |CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYDESC, + sysctlinfo_interface, "A", "description of an object"); + +SYSCTL_PROC(_sysctl, ENTRYLABEL, entrylabel, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYLABEL, + sysctlinfo_interface, "A", "label of an object"); + +SYSCTL_PROC(_sysctl, ENTRYKIND, entrykind, CTLTYPE_UINT | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYKIND, + sysctlinfo_interface, "IU", "kind (flags and type) of an object"); + +SYSCTL_PROC(_sysctl, ENTRYFMT, entryfmt, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYFMT, + sysctlinfo_interface, "A", "format string of an object"); + +SYSCTL_PROC(_sysctl, ENTRYNEXTNODE, entrynextnode, CTLTYPE_INT | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYNEXTNODE, + sysctlinfo_interface, "I", "next mib object (internal node or leaf)"); + +SYSCTL_PROC(_sysctl, ENTRYNEXTLEAF, entrynextleaf, CTLTYPE_INT | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYNEXTLEAF, + sysctlinfo_interface, "I", "next mib object (only leaf)"); + +SYSCTL_PROC(_sysctl, ENTRYALLINFO, entryallinfo, CTLTYPE_OPAQUE | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYALLINFO, + sysctlinfo_interface, "RAW", "all info of an object"); + +SYSCTL_PROC(_sysctl, ENTRYALLINFO_WITHNEXTNODE, entryallinfo_withnextnode, + CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | + CTLFLAG_CAPRW, NULL, ENTRYALLINFO_WITHNEXTNODE, sysctlinfo_interface, + "RAW", "all info of an object with the next node"); + +SYSCTL_PROC(_sysctl, ENTRYALLINFO_WITHNEXTLEAF, entryallinfo_withnextleaf, + CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | + CTLFLAG_CAPRW, NULL, ENTRYALLINFO_WITHNEXTLEAF, sysctlinfo_interface, + "RAW", "all info of an object with next leaf"); + +SYSCTL_PROC(_sysctl, ENTRYIDBYNAME, entryidbyname, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, ENTRYIDBYNAME, + sysctlinfo_interface, "A", "id of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYFAKEIDBYNAME, entryfakeidbyname, CTLTYPE_STRING | + CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYFAKEIDBYNAME, sysctlinfo_interface, "A", + "fake id of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYDESCBYNAME, entrydescbyname, CTLTYPE_STRING | + CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYDESCBYNAME, sysctlinfo_interface, "A", + "description of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYLABELBYNAME, entrylabelbyname, CTLTYPE_STRING | + CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYLABELBYNAME, sysctlinfo_interface, "A", + "label of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYKINDBYNAME, entrykindbyname, CTLTYPE_STRING | + CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYKINDBYNAME, sysctlinfo_interface, "A", "kind of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYFMTBYNAME, entryfmtbyname, CTLTYPE_STRING | + CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYFMTBYNAME, sysctlinfo_interface, "A", "format of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYALLINFOBYNAME, entryallinfobyname, CTLTYPE_STRING | + CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYALLINFOBYNAME, sysctlinfo_interface, "A", + "all info of an object by its name"); + +SYSCTL_PROC(_sysctl, ENTRYALLINFOBYNAME_WITHNEXTNODE, + entryallinfobyname_withnextnode, CTLTYPE_OPAQUE | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYALLINFOBYNAME_WITHNEXTNODE, sysctlinfo_interface, "RAW", + "all info of an object by its name with the next node name"); + +SYSCTL_PROC(_sysctl, ENTRYALLINFOBYNAME_WITHNEXTLEAF, + entryallinfobyname_withnextleaf, CTLTYPE_OPAQUE | CTLFLAG_RW | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE | CTLFLAG_CAPRW, NULL, + ENTRYALLINFOBYNAME_WITHNEXTLEAF, sysctlinfo_interface, "RAW", + "all info of an object by its name with next leaf name"); Index: sys/sys/sysctlinfo.h =================================================================== --- sys/sys/sysctlinfo.h +++ sys/sys/sysctlinfo.h @@ -0,0 +1,92 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Alfonso Sabato Siciliano + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYSCTLINFO_H_ +#define _SYSCTLINFO_H_ + +/* level 1 */ +#define CTL_SYSCTLMIB 0 + +/* level 2 */ +#define ENTRYFAKENAME 7 +#define ENTRYNAME 8 +#define ENTRYDESC 9 +#define ENTRYLABEL 10 +#define ENTRYKIND 11 +#define ENTRYFMT 12 +#define ENTRYNEXTNODE 13 +#define ENTRYNEXTLEAF 14 +#define ENTRYALLINFO 15 +#define ENTRYALLINFO_WITHNEXTNODE 16 +#define ENTRYALLINFO_WITHNEXTLEAF 17 +#define ENTRYIDBYNAME 18 +#define ENTRYFAKEIDBYNAME 19 +#define ENTRYDESCBYNAME 20 +#define ENTRYLABELBYNAME 21 +#define ENTRYKINDBYNAME 22 +#define ENTRYFMTBYNAME 23 +#define ENTRYALLINFOBYNAME 24 +#define ENTRYALLINFOBYNAME_WITHNEXTNODE 25 +#define ENTRYALLINFOBYNAME_WITHNEXTLEAF 26 + +#define SYSCTLINFO_MAXFAKE 64 + +#ifndef _KERNEL + +#define SYSCTLINFO(id, idlevel, prop, buf, buflen) \ + sysctl(prop, 2, buf, buflen, id, idlevel * sizeof(int)) + +#define SYSCTLINFO_BYNAME(name, prop, buf, buflen) \ + sysctl(prop, 2, buf, buflen, name, strlen(name) + 1) + +#define SYSCTLINFO_HELPER_ALL(buf, idlevel, id, name, descr, kind, fmt, label) do { \ + idlevel = *((size_t *)buf); \ + id = (int*)( ((char*)buf) + sizeof(size_t) ); \ + name = ((char *)buf) + (idlevel * sizeof(int) + sizeof(size_t)); \ + descr = strchr(name, '\0') + 1; \ + kind = *((unsigned int *) (strchr(descr, '\0') + 1)); \ + fmt = strchr(descr, '\0') + 1 + sizeof(unsigned int); \ + label = strchr(fmt, '\0') + 1; \ +} while (0) + +#define SYSCTLINFO_HELPER_ALLWITHNEXT(buf, idlevel, id, name, descr, kind, fmt, label, idnextlevel, idnext) do { \ + SYSCTLINFO_HELPER_ALL(buf, idlevel, id, name, descr, kind, fmt, label); \ + idnextlevel = *( (size_t *) ((strchr(label, '\0') + 1)) ); \ + idnext = (int*) (strchr(label, '\0') + 1 + sizeof(size_t) ); \ +} while (0) + +#define SYSCTLINFO_HELPER_ALLWITHNEXTNAME(buf, idlevel, id, name, descr, kind, fmt, label, namenext) do { \ + SYSCTLINFO_HELPER_ALL(buf, idlevel, id, name, descr, kind, fmt, label); \ + namenext = strchr(label, '\0') + 1; \ +} while (0) + +#endif /* end _KERNEL */ + +#endif /* _SYSCTLINFO_H_ */ +