Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_sysctl.c
Show First 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||||||
/* Root list */ | /* Root list */ | ||||||||
struct sysctl_oid_list sysctl__children = SLIST_HEAD_INITIALIZER(&sysctl__children); | struct sysctl_oid_list sysctl__children = SLIST_HEAD_INITIALIZER(&sysctl__children); | ||||||||
static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, | static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, | ||||||||
int recurse); | int recurse); | ||||||||
static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t); | static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t); | ||||||||
static int sysctl_new_kernel(struct sysctl_req *, void *, size_t); | static int sysctl_new_kernel(struct sysctl_req *, void *, size_t); | ||||||||
static bool sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, | |||||||||
u_int namelen, int *next, int *len, int level, | |||||||||
bool honor_skip); | |||||||||
static struct sysctl_oid * | static struct sysctl_oid * | ||||||||
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list) | sysctl_find_oidname(const char *name, struct sysctl_oid_list *list) | ||||||||
{ | { | ||||||||
struct sysctl_oid *oidp; | struct sysctl_oid *oidp; | ||||||||
SYSCTL_ASSERT_LOCKED(); | SYSCTL_ASSERT_LOCKED(); | ||||||||
SLIST_FOREACH(oidp, list, oid_link) { | SLIST_FOREACH(oidp, list, oid_link) { | ||||||||
if (strcmp(oidp->oid_name, name) == 0) { | if (strcmp(oidp->oid_name, name) == 0) { | ||||||||
▲ Show 20 Lines • Show All 958 Lines • ▼ Show 20 Lines | |||||||||
/* | /* | ||||||||
* XXXRW/JA: Shouldn't return name data for nodes that we don't permit in | * XXXRW/JA: Shouldn't return name data for nodes that we don't permit in | ||||||||
* capability mode. | * capability mode. | ||||||||
*/ | */ | ||||||||
static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NAME, name, CTLFLAG_RD | | static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NAME, name, CTLFLAG_RD | | ||||||||
CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_name, ""); | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_name, ""); | ||||||||
/* | /* | ||||||||
* Walk the sysctl subtree at lsp until we find the given name, | * Recursively tries to find the next node for @name and @namelen. | ||||||||
freqlabsUnsubmitted Not Done Inline Actions
freqlabs: | |||||||||
* and return the next name in order by oid_number. | * | ||||||||
* Returns true if the desired next node was found, filling | |||||||||
* @next and @len. | |||||||||
*/ | */ | ||||||||
static int | static bool | ||||||||
sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, | sysctl_sysctl_next_node(struct sysctl_oid *oidp, int *name, u_int *namelen, | ||||||||
int *next, int *len, int level, bool honor_skip) | int *next, int *len, int level, bool honor_skip) | ||||||||
{ | { | ||||||||
struct sysctl_oid *oidp; | struct sysctl_oid_list *lsp; | ||||||||
SYSCTL_ASSERT_LOCKED(); | |||||||||
*len = level; | |||||||||
SLIST_FOREACH(oidp, lsp, oid_link) { | |||||||||
*next = oidp->oid_number; | *next = oidp->oid_number; | ||||||||
if ((oidp->oid_kind & CTLFLAG_DORMANT) != 0) | if ((oidp->oid_kind & CTLFLAG_DORMANT) != 0) | ||||||||
continue; | return (false); | ||||||||
if (honor_skip && (oidp->oid_kind & CTLFLAG_SKIP) != 0) | if (honor_skip && (oidp->oid_kind & CTLFLAG_SKIP) != 0) | ||||||||
continue; | return (false); | ||||||||
if (namelen == 0) { | if (*namelen == 0) { | ||||||||
/* | /* | ||||||||
* We have reached a node with a full name match and are | * We have reached a node with a full name match and are | ||||||||
* looking for the next oid in its children. | * looking for the next oid in its children. | ||||||||
* | * | ||||||||
* For CTL_SYSCTL_NEXTNOSKIP we are done. | * For CTL_SYSCTL_NEXTNOSKIP we are done. | ||||||||
* | * | ||||||||
* For CTL_SYSCTL_NEXT we skip CTLTYPE_NODE (unless it | * For CTL_SYSCTL_NEXT we skip CTLTYPE_NODE (unless it | ||||||||
* has a handler) and move on to the children. | * has a handler) and move on to the children. | ||||||||
*/ | */ | ||||||||
if (!honor_skip) | if (!honor_skip) | ||||||||
return (0); | return (true); | ||||||||
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | ||||||||
return (0); | return (true); | ||||||||
/* If node does not have an iterator, treat it as leaf */ | |||||||||
if (oidp->oid_handler) | if (oidp->oid_handler) | ||||||||
return (0); | return (true); | ||||||||
lsp = SYSCTL_CHILDREN(oidp); | lsp = SYSCTL_CHILDREN(oidp); | ||||||||
if (!sysctl_sysctl_next_ls(lsp, NULL, 0, next + 1, len, | if (sysctl_sysctl_next_ls(lsp, NULL, 0, next + 1, len, | ||||||||
level + 1, honor_skip)) | level + 1, honor_skip)) | ||||||||
return (0); | return (true); | ||||||||
/* | /* | ||||||||
* There were no useable children in this node. | * There were no useable children in this node. | ||||||||
* Continue searching for the next oid at this level. | * Continue searching for the next oid at this level. | ||||||||
*/ | */ | ||||||||
goto emptynode; | goto emptynode; | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* No match yet. Continue seeking the given name. | * No match yet. Continue seeking the given name. | ||||||||
* | * | ||||||||
* We are iterating in order by oid_number, so skip oids lower | * We are iterating in order by oid_number, so skip oids lower | ||||||||
* than the one we are looking for. | * than the one we are looking for. | ||||||||
* | * | ||||||||
* When the current oid_number is higher than the one we seek, | * When the current oid_number is higher than the one we seek, | ||||||||
* that means we have reached the next oid in the sequence and | * that means we have reached the next oid in the sequence and | ||||||||
* should return it. | * should return it. | ||||||||
* | * | ||||||||
* If the oid_number matches the name at this level then we | * If the oid_number matches the name at this level then we | ||||||||
* have to find a node to continue searching at the next level. | * have to find a node to continue searching at the next level. | ||||||||
*/ | */ | ||||||||
if (oidp->oid_number < *name) | if (oidp->oid_number < *name) | ||||||||
continue; | return (false); | ||||||||
if (oidp->oid_number > *name) { | if (oidp->oid_number > *name) { | ||||||||
/* | /* | ||||||||
* We have reached the next oid. | * We have reached the next oid. | ||||||||
* | * | ||||||||
* For CTL_SYSCTL_NEXTNOSKIP we are done. | * For CTL_SYSCTL_NEXTNOSKIP we are done. | ||||||||
* | * | ||||||||
* For CTL_SYSCTL_NEXT we skip CTLTYPE_NODE (unless it | * For CTL_SYSCTL_NEXT we skip CTLTYPE_NODE (unless it | ||||||||
* has a handler) and move on to the children. | * has a handler) and move on to the children. | ||||||||
*/ | */ | ||||||||
if (!honor_skip) | if (!honor_skip) | ||||||||
return (0); | return (true); | ||||||||
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | ||||||||
return (0); | return (true); | ||||||||
/* If node does not have an iterator, treat it as leaf */ | |||||||||
if (oidp->oid_handler) | if (oidp->oid_handler) | ||||||||
return (0); | return (true); | ||||||||
Not Done Inline ActionsITER_SIBLINGS would be a better fit than ITER_STOP. We aren't stopping iteration, we're continuing to iterate through the siblings of this node. freqlabs: ITER_SIBLINGS would be a better fit than ITER_STOP. We aren't stopping iteration, we're… | |||||||||
lsp = SYSCTL_CHILDREN(oidp); | lsp = SYSCTL_CHILDREN(oidp); | ||||||||
if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1, | if (sysctl_sysctl_next_ls(lsp, name + 1, *namelen - 1, | ||||||||
next + 1, len, level + 1, honor_skip)) | next + 1, len, level + 1, honor_skip)) | ||||||||
Done Inline ActionsIn other words, we have a match at the current level but not a complete match. freqlabs: In other words, we have a match at the current level but not a complete match. | |||||||||
return (0); | return (true); | ||||||||
goto next; | goto next; | ||||||||
Not Done Inline ActionsWorth an assert IMO. freqlabs: Worth an assert IMO. | |||||||||
Done Inline ActionsActually I think this should be ITER_SIBLINGS, and below as well, to match the continues that were previously here. freqlabs: Actually I think this should be `ITER_SIBLINGS`, and below as well, to match the `continue`s… | |||||||||
} | } | ||||||||
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | ||||||||
continue; | return (false); | ||||||||
if (oidp->oid_handler) | if (oidp->oid_handler) | ||||||||
continue; | return (false); | ||||||||
lsp = SYSCTL_CHILDREN(oidp); | lsp = SYSCTL_CHILDREN(oidp); | ||||||||
if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1, | if (sysctl_sysctl_next_ls(lsp, name + 1, *namelen - 1, | ||||||||
next + 1, len, level + 1, honor_skip)) | next + 1, len, level + 1, honor_skip)) | ||||||||
return (0); | return (true); | ||||||||
next: | next: | ||||||||
Done Inline ActionsYou could return (success); to shave off the extra return above. freqlabs: You could `return (success);` to shave off the extra return above. | |||||||||
/* | /* | ||||||||
* There were no useable children in this node. | * There were no useable children in this node. | ||||||||
* Continue searching for the next oid at the root level. | * Continue searching for the next oid at the root level. | ||||||||
*/ | */ | ||||||||
namelen = 1; | *namelen = 1; | ||||||||
emptynode: | emptynode: | ||||||||
/* Reset len in case a failed recursive call changed it. */ | /* Reset len in case a failed recursive call changed it. */ | ||||||||
*len = level; | *len = level; | ||||||||
return (false); | |||||||||
} | } | ||||||||
return (ENOENT); | |||||||||
/* | |||||||||
* Recursively walk the sysctl subtree at lsp until we find the given name. | |||||||||
* Returns true and fills in next oid data in @next and @len if oid is found. | |||||||||
*/ | |||||||||
static bool | |||||||||
sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, | |||||||||
int *next, int *len, int level, bool honor_skip) | |||||||||
{ | |||||||||
struct sysctl_oid *oidp; | |||||||||
SYSCTL_ASSERT_LOCKED(); | |||||||||
*len = level; | |||||||||
SLIST_FOREACH(oidp, lsp, oid_link) { | |||||||||
if (!sysctl_sysctl_next_node(oidp, name, &namelen, | |||||||||
next, len, level, honor_skip)) | |||||||||
continue; | |||||||||
return (true); | |||||||||
} | } | ||||||||
return (false); | |||||||||
} | |||||||||
static int | static int | ||||||||
sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) | sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) | ||||||||
{ | { | ||||||||
int *name = (int *) arg1; | int *name = (int *) arg1; | ||||||||
u_int namelen = arg2; | u_int namelen = arg2; | ||||||||
int len, error; | int len, error; | ||||||||
bool success; | |||||||||
struct sysctl_oid_list *lsp = &sysctl__children; | struct sysctl_oid_list *lsp = &sysctl__children; | ||||||||
struct rm_priotracker tracker; | struct rm_priotracker tracker; | ||||||||
int next[CTL_MAXNAME]; | int next[CTL_MAXNAME]; | ||||||||
SYSCTL_RLOCK(&tracker); | SYSCTL_RLOCK(&tracker); | ||||||||
error = sysctl_sysctl_next_ls(lsp, name, namelen, next, &len, 1, | success = sysctl_sysctl_next_ls(lsp, name, namelen, next, &len, 1, | ||||||||
oidp->oid_number == CTL_SYSCTL_NEXT); | oidp->oid_number == CTL_SYSCTL_NEXT); | ||||||||
SYSCTL_RUNLOCK(&tracker); | SYSCTL_RUNLOCK(&tracker); | ||||||||
if (error) | if (!success) | ||||||||
return (error); | return (ENOENT); | ||||||||
error = SYSCTL_OUT(req, next, len * sizeof (int)); | error = SYSCTL_OUT(req, next, len * sizeof (int)); | ||||||||
return (error); | return (error); | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* XXXRW/JA: Shouldn't return next data for nodes that we don't permit in | * XXXRW/JA: Shouldn't return next data for nodes that we don't permit in | ||||||||
* capability mode. | * capability mode. | ||||||||
*/ | */ | ||||||||
▲ Show 20 Lines • Show All 1,713 Lines • Show Last 20 Lines |