Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_mib.c
Show First 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/random.h> | #include <sys/random.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/sysctlinfo.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
SYSCTL_ROOT_NODE(0, sysctl, CTLFLAG_RW, 0, | SYSCTL_ROOT_NODE(0, sysctl, CTLFLAG_RW, 0, | ||||
"Sysctl internal magic"); | "Sysctl internal magic"); | ||||
SYSCTL_ROOT_NODE(CTL_KERN, kern, CTLFLAG_RW|CTLFLAG_CAPRD, 0, | SYSCTL_ROOT_NODE(CTL_KERN, kern, CTLFLAG_RW|CTLFLAG_CAPRD, 0, | ||||
"High kernel, proc, limits &c"); | "High kernel, proc, limits &c"); | ||||
SYSCTL_ROOT_NODE(CTL_VM, vm, CTLFLAG_RW, 0, | SYSCTL_ROOT_NODE(CTL_VM, vm, CTLFLAG_RW, 0, | ||||
Show All 18 Lines | |||||
SYSCTL_ROOT_NODE(OID_AUTO, compat, CTLFLAG_RW, 0, | SYSCTL_ROOT_NODE(OID_AUTO, compat, CTLFLAG_RW, 0, | ||||
"Compatibility code"); | "Compatibility code"); | ||||
SYSCTL_ROOT_NODE(OID_AUTO, security, CTLFLAG_RW, 0, | SYSCTL_ROOT_NODE(OID_AUTO, security, CTLFLAG_RW, 0, | ||||
"Security"); | "Security"); | ||||
#ifdef REGRESSION | #ifdef REGRESSION | ||||
SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0, | SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0, | ||||
"Regression test MIB"); | "Regression test MIB"); | ||||
#endif | #endif | ||||
/* | |||||
*sysctlinfo interface to pass MIB info to the userland | |||||
*/ | |||||
/* util */ | |||||
static int | |||||
sysctlinfo_nextnode_locked(struct sysctl_oid *path[CTL_MAXNAME], | |||||
int id[CTL_MAXNAME], size_t *level, int mode) | |||||
{ | |||||
struct sysctl_oid_list *children; | |||||
size_t l = *level; | |||||
/* the caller has to hold a lock */ | |||||
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 sysctlinfo interface 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_MAXFAKENAME], 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; i<req->newlen; 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); | |||||
} | |||||
/* | |||||
* The MIB-Tree is a critical section, sysctl() gets the lock but | |||||
* sysctl_root_handler_locked() unlock before to call this handler | |||||
*/ | |||||
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; | |||||
goto out; | |||||
} | |||||
} 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 (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_nextnode_locked(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)); | |||||
if (error) | |||||
goto out; | |||||
} 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; | |||||
} | |||||
if ((error = SYSCTL_OUT(req, "", 1)) !=0) | |||||
goto out; | |||||
} | |||||
} | |||||
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"); | |||||
/* end sysctlinfo */ | |||||
SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE, | SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE, | ||||
kern_ident, 0, "Kernel identifier"); | kern_ident, 0, "Kernel identifier"); | ||||
SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD, | SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD, | ||||
SYSCTL_NULL_INT_PTR, BSD, "Operating system revision"); | SYSCTL_NULL_INT_PTR, BSD, "Operating system revision"); | ||||
SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD|CTLFLAG_MPSAFE, | SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD|CTLFLAG_MPSAFE, | ||||
▲ Show 20 Lines • Show All 555 Lines • Show Last 20 Lines |