Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_sysctl.c
Show First 20 Lines • Show All 1,093 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, ""); | ||||
static int | static int | ||||
sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, | sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, | ||||
int *next, int *len, int level, struct sysctl_oid **oidpp) | int *next, int *len, int level, struct sysctl_oid **oidpp, bool skip) | ||||
{ | { | ||||
struct sysctl_oid *oidp; | struct sysctl_oid *oidp; | ||||
SYSCTL_ASSERT_LOCKED(); | SYSCTL_ASSERT_LOCKED(); | ||||
*len = level; | *len = level; | ||||
SLIST_FOREACH(oidp, lsp, oid_link) { | SLIST_FOREACH(oidp, lsp, oid_link) { | ||||
*next = oidp->oid_number; | *next = oidp->oid_number; | ||||
*oidpp = oidp; | *oidpp = oidp; | ||||
if ((oidp->oid_kind & (CTLFLAG_SKIP | CTLFLAG_DORMANT)) != 0) | if ((oidp->oid_kind & CTLFLAG_DORMANT) != 0) | ||||
continue; | continue; | ||||
if (skip && (oidp->oid_kind & CTLFLAG_SKIP) != 0) | |||||
continue; | |||||
if (!namelen) { | if (!namelen) { | ||||
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | ||||
return (0); | return (0); | ||||
if (oidp->oid_handler) | if (oidp->oid_handler) | ||||
/* We really should call the handler here...*/ | /* We really should call the handler here...*/ | ||||
return (0); | return (0); | ||||
lsp = SYSCTL_CHILDREN(oidp); | lsp = SYSCTL_CHILDREN(oidp); | ||||
if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, | if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, | ||||
len, level+1, oidpp)) | len, level+1, oidpp, skip)) | ||||
return (0); | return (0); | ||||
goto emptynode; | goto emptynode; | ||||
} | } | ||||
if (oidp->oid_number < *name) | if (oidp->oid_number < *name) | ||||
continue; | continue; | ||||
if (oidp->oid_number > *name) { | if (oidp->oid_number > *name) { | ||||
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | ||||
return (0); | return (0); | ||||
if (oidp->oid_handler) | if (oidp->oid_handler) | ||||
return (0); | return (0); | ||||
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, oidpp)) | next+1, len, level+1, oidpp, skip)) | ||||
return (0); | return (0); | ||||
goto next; | goto next; | ||||
} | } | ||||
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) | ||||
continue; | continue; | ||||
if (oidp->oid_handler) | if (oidp->oid_handler) | ||||
continue; | continue; | ||||
lsp = SYSCTL_CHILDREN(oidp); | lsp = SYSCTL_CHILDREN(oidp); | ||||
if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, | if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, | ||||
len, level+1, oidpp)) | len, level+1, oidpp, skip)) | ||||
return (0); | return (0); | ||||
next: | next: | ||||
namelen = 1; | namelen = 1; | ||||
emptynode: | emptynode: | ||||
*len = level; | *len = level; | ||||
} | } | ||||
return (1); | return (ENOENT); | ||||
} | } | ||||
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 i, j, error; | int len, error; | ||||
struct sysctl_oid *oid; | struct sysctl_oid *oid; | ||||
struct sysctl_oid_list *lsp = &sysctl__children; | struct sysctl_oid_list *lsp = &sysctl__children; | ||||
struct rm_priotracker tracker; | struct rm_priotracker tracker; | ||||
int newoid[CTL_MAXNAME]; | int next[CTL_MAXNAME]; | ||||
SYSCTL_RLOCK(&tracker); | SYSCTL_RLOCK(&tracker); | ||||
i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid); | error = sysctl_sysctl_next_ls(lsp, name, namelen, next, &len, 1, &oid, | ||||
true); | |||||
jhb: You could perhaps reduce some code duplication by replacing `true` with `oidp->oid_number ==… | |||||
SYSCTL_RUNLOCK(&tracker); | SYSCTL_RUNLOCK(&tracker); | ||||
if (i) | if (error) | ||||
return (ENOENT); | |||||
error = SYSCTL_OUT(req, newoid, j * sizeof (int)); | |||||
return (error); | return (error); | ||||
error = SYSCTL_OUT(req, next, len * sizeof (int)); | |||||
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. | ||||
*/ | */ | ||||
static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NEXT, next, CTLFLAG_RD | | static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NEXT, next, CTLFLAG_RD | | ||||
CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_next, ""); | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_next, ""); | ||||
static int | static int | ||||
sysctl_sysctl_allnext(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
int *name = (int *) arg1; | |||||
u_int namelen = arg2; | |||||
int len, error; | |||||
struct sysctl_oid *oid; | |||||
struct sysctl_oid_list *lsp = &sysctl__children; | |||||
struct rm_priotracker tracker; | |||||
int next[CTL_MAXNAME]; | |||||
SYSCTL_RLOCK(&tracker); | |||||
error = sysctl_sysctl_next_ls(lsp, name, namelen, next, &len, 1, &oid, | |||||
false); | |||||
SYSCTL_RUNLOCK(&tracker); | |||||
if (error) | |||||
return (error); | |||||
error = SYSCTL_OUT(req, next, len * sizeof (int)); | |||||
return (error); | |||||
} | |||||
/* | |||||
* XXXRW/JA: Shouldn't return next data for nodes that we don't permit in | |||||
* capability mode. | |||||
*/ | |||||
static SYSCTL_NODE(_sysctl, CTL_SYSCTL_ALLNEXT, allnext, CTLFLAG_RD | | |||||
Done Inline ActionsCould possibly call this "next_noskip" rather than "allnext", but "allnext" is probably fine. jhb: Could possibly call this "next_noskip" rather than "allnext", but "allnext" is probably fine. | |||||
CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_allnext, ""); | |||||
static int | |||||
name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp) | name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp) | ||||
{ | { | ||||
struct sysctl_oid *oidp; | struct sysctl_oid *oidp; | ||||
struct sysctl_oid_list *lsp = &sysctl__children; | struct sysctl_oid_list *lsp = &sysctl__children; | ||||
char *p; | char *p; | ||||
SYSCTL_ASSERT_LOCKED(); | SYSCTL_ASSERT_LOCKED(); | ||||
▲ Show 20 Lines • Show All 1,522 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
db_show_sysctl_all(int *oid, size_t len, int flags) | db_show_sysctl_all(int *oid, size_t len, int flags) | ||||
{ | { | ||||
struct sysctl_oid *oidp; | struct sysctl_oid *oidp; | ||||
int name1[CTL_MAXNAME + 2], name2[CTL_MAXNAME + 2]; | int name1[CTL_MAXNAME + 2], name2[CTL_MAXNAME + 2]; | ||||
size_t l1, l2; | size_t l1, l2; | ||||
name1[0] = CTL_SYSCTL; | name1[0] = CTL_SYSCTL; | ||||
name1[1] = CTL_SYSCTL_NEXT; | name1[1] = CTL_SYSCTL_ALLNEXT; | ||||
freqlabsAuthorUnsubmitted Done Inline ActionsI think this could be useful, but I'm not sure it's actually a good idea freqlabs: I think this could be useful, but I'm not sure it's actually a good idea | |||||
jhbUnsubmitted Done Inline ActionsI would probably not make this change. jhb: I would probably not make this change. | |||||
l1 = 2; | l1 = 2; | ||||
if (len) { | if (len) { | ||||
memcpy(name1+2, oid, len * sizeof(int)); | memcpy(name1 + 2, oid, len * sizeof(int)); | ||||
l1 +=len; | l1 += len; | ||||
} else { | } else { | ||||
name1[2] = 1; | name1[2] = CTL_KERN; | ||||
l1++; | l1++; | ||||
} | } | ||||
for (;;) { | for (;;) { | ||||
int i, error; | int i, error; | ||||
l2 = sizeof(name2); | l2 = sizeof(name2); | ||||
error = kernel_sysctl(kdb_thread, name1, l1, | error = kernel_sysctl(kdb_thread, name1, l1, | ||||
name2, &l2, NULL, 0, &l2, 0); | name2, &l2, NULL, 0, &l2, 0); | ||||
▲ Show 20 Lines • Show All 153 Lines • Show Last 20 Lines |
You could perhaps reduce some code duplication by replacing true with oidp->oid_number == CTL_SYSCTL_ALLNEXT and then reusing this handler function for the ALLNEXT oid.