From 92e17803cd19bf55d07779e0b56b12e9fa50ec92 Mon Sep 17 00:00:00 2001 From: Ryan Moeller Date: Mon, 5 Oct 2020 20:13:22 +0000 Subject: [PATCH] Enable iterating all sysctls, even ones with CTLFLAG_SKIP Add an "nextnoskip" sysctl that allows for listing of sysctls intended to be normally skipped for cost reasons. This makes it so the names/descriptions of those sysctls can be discovered with sysctl -aN/sysctl -ad/sysctl -at. It also makes it so children are visited when a node flagged with CTLFLAG_SKIP is explicitly requested. The intended use case is to mark the root "kstat" node with CTLFLAG_SKIP so that the extensive and expensive stats are skipped by default but may still be easily obtained without having to know them all (which may not even be possible) and request each one-by-one. Reviewed by: jhb MFC after: 2 weeks Relnotes: yes Sponsored by: iXsystems, Inc. Differential Revision: https://reviews.freebsd.org/D26560 --- sbin/sysctl/sysctl.c | 35 +++++++++++++++++++------------- sys/kern/kern_sysctl.c | 44 ++++++++++++++++++++++++---------------- sys/sys/sysctl.h | 3 ++- usr.bin/truss/syscalls.c | 3 +++ 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c index f83508d216c..b683a4319fe 100644 --- a/sbin/sysctl/sysctl.c +++ b/sbin/sysctl/sysctl.c @@ -81,7 +81,7 @@ static int Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag; static int oidfmt(int *, int, char *, u_int *); static int parsefile(const char *); static int parse(const char *, int); -static int show_var(int *, int); +static int show_var(int *, int, bool); static int sysctl_all(int *oid, int len); static int name2oid(const char *, int *); @@ -428,13 +428,13 @@ parse(const char *string, int lineno) if (newvalstr == NULL || dflag) { if ((kind & CTLTYPE) == CTLTYPE_NODE) { if (dflag) { - i = show_var(mib, len); + i = show_var(mib, len, false); if (!i && !bflag) putchar('\n'); } sysctl_all(mib, len); } else { - i = show_var(mib, len); + i = show_var(mib, len, false); if (!i && !bflag) putchar('\n'); } @@ -504,7 +504,7 @@ parse(const char *string, int lineno) break; } - i = show_var(mib, len); + i = show_var(mib, len, false); if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { free(newbuf); if (!i && !bflag) @@ -532,7 +532,7 @@ parse(const char *string, int lineno) printf(" -> "); i = nflag; nflag = 1; - j = show_var(mib, len); + j = show_var(mib, len, false); if (!j && !bflag) putchar('\n'); nflag = i; @@ -942,7 +942,7 @@ oidfmt(int *oid, int len, char *fmt, u_int *kind) * Return minus one if we had errors. */ static int -show_var(int *oid, int nlen) +show_var(int *oid, int nlen, bool honor_skip) { u_char buf[BUFSIZ], *val, *oval, *p; char name[BUFSIZ], fmt[BUFSIZ]; @@ -976,11 +976,11 @@ show_var(int *oid, int nlen) oidfmt(oid, nlen, fmt, &kind); /* if Wflag then only list sysctls that are writeable and not stats. */ if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0)) - return 1; + return (1); /* if Tflag then only list sysctls that are tuneables. */ if (Tflag && (kind & CTLFLAG_TUN) == 0) - return 1; + return (1); if (Nflag) { printf("%s", name); @@ -1013,6 +1013,10 @@ show_var(int *oid, int nlen) return (0); } + /* bail before fetching the value if we're honoring skip */ + if (honor_skip && (kind & CTLFLAG_SKIP) != 0) + return (1); + /* don't fetch opaques that we don't know how to print */ if (ctltype == CTLTYPE_OPAQUE) { if (strcmp(fmt, "S,clockinfo") == 0) @@ -1195,15 +1199,17 @@ sysctl_all(int *oid, int len) int name1[22], name2[22]; int i, j; size_t l1, l2; + bool honor_skip = false; - name1[0] = 0; - name1[1] = 2; + name1[0] = CTL_SYSCTL; + name1[1] = (oid != NULL || Nflag || dflag || tflag) ? + CTL_SYSCTL_NEXTNOSKIP : CTL_SYSCTL_NEXT; l1 = 2; if (len) { - memcpy(name1+2, oid, len * sizeof(int)); + memcpy(name1 + 2, oid, len * sizeof(int)); l1 += len; } else { - name1[2] = 1; + name1[2] = CTL_KERN; l1++; } for (;;) { @@ -1225,11 +1231,12 @@ sysctl_all(int *oid, int len) if (name2[i] != oid[i]) return (0); - i = show_var(name2, l2); + i = show_var(name2, l2, honor_skip); if (!i && !bflag) putchar('\n'); - memcpy(name1+2, name2, l2 * sizeof(int)); + memcpy(name1 + 2, name2, l2 * sizeof(int)); l1 = 2 + l2; + honor_skip = true; } } diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 5814d147c19..b1c688d2864 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -950,7 +950,8 @@ SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, NULL); * {CTL_SYSCTL, CTL_SYSCTL_DEBUG} printf the entire MIB-tree. * {CTL_SYSCTL, CTL_SYSCTL_NAME, ...} return the name of the "..." * OID. - * {CTL_SYSCTL, CTL_SYSCTL_NEXT, ...} return the next OID. + * {CTL_SYSCTL, CTL_SYSCTL_NEXT, ...} return the next OID, honoring + * CTLFLAG_SKIP. * {CTL_SYSCTL, CTL_SYSCTL_NAME2OID} return the OID of the name in * "new" * {CTL_SYSCTL, CTL_SYSCTL_OIDFMT, ...} return the kind & format info @@ -959,6 +960,8 @@ SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, NULL); * "..." OID. * {CTL_SYSCTL, CTL_SYSCTL_OIDLABEL, ...} return the aggregation label of * the "..." OID. + * {CTL_SYSCTL, CTL_SYSCTL_NEXTNOSKIP, ...} return the next OID, ignoring + * CTLFLAG_SKIP. */ #ifdef SYSCTL_DEBUG @@ -1099,7 +1102,7 @@ static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NAME, name, CTLFLAG_RD | static int 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 honor_skip) { struct sysctl_oid *oidp; @@ -1109,7 +1112,10 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, *next = oidp->oid_number; *oidpp = oidp; - if ((oidp->oid_kind & (CTLFLAG_SKIP | CTLFLAG_DORMANT)) != 0) + if ((oidp->oid_kind & CTLFLAG_DORMANT) != 0) + continue; + + if (honor_skip && (oidp->oid_kind & CTLFLAG_SKIP) != 0) continue; if (!namelen) { @@ -1120,7 +1126,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, return (0); lsp = SYSCTL_CHILDREN(oidp); if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, - len, level+1, oidpp)) + len, level+1, oidpp, honor_skip)) return (0); goto emptynode; } @@ -1135,7 +1141,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, return (0); lsp = SYSCTL_CHILDREN(oidp); if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, - next+1, len, level+1, oidpp)) + next+1, len, level+1, oidpp, honor_skip)) return (0); goto next; } @@ -1147,14 +1153,14 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, lsp = SYSCTL_CHILDREN(oidp); if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, - len, level+1, oidpp)) + len, level+1, oidpp, honor_skip)) return (0); next: namelen = 1; emptynode: *len = level; } - return (1); + return (ENOENT); } static int @@ -1162,18 +1168,19 @@ sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) { int *name = (int *) arg1; u_int namelen = arg2; - int i, j, error; + int len, error; struct sysctl_oid *oid; struct sysctl_oid_list *lsp = &sysctl__children; struct rm_priotracker tracker; - int newoid[CTL_MAXNAME]; + int next[CTL_MAXNAME]; 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, + oidp->oid_number == CTL_SYSCTL_NEXT); SYSCTL_RUNLOCK(&tracker); - if (i) - return (ENOENT); - error = SYSCTL_OUT(req, newoid, j * sizeof (int)); + if (error) + return (error); + error = SYSCTL_OUT(req, next, len * sizeof (int)); return (error); } @@ -1184,6 +1191,9 @@ sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NEXT, next, CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_next, ""); +static SYSCTL_NODE(_sysctl, CTL_SYSCTL_NEXTNOSKIP, nextnoskip, CTLFLAG_RD | + CTLFLAG_MPSAFE | CTLFLAG_CAPRD, sysctl_sysctl_next, ""); + static int name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp) { @@ -2726,10 +2736,10 @@ db_show_sysctl_all(int *oid, size_t len, int flags) name1[1] = CTL_SYSCTL_NEXT; l1 = 2; if (len) { - memcpy(name1+2, oid, len * sizeof(int)); - l1 +=len; + memcpy(name1 + 2, oid, len * sizeof(int)); + l1 += len; } else { - name1[2] = 1; + name1[2] = CTL_KERN; l1++; } for (;;) { @@ -2742,7 +2752,7 @@ db_show_sysctl_all(int *oid, size_t len, int flags) if (error == ENOENT) return (0); else - db_error("sysctl(getnext)"); + db_error("sysctl(next)"); } l2 /= sizeof(int); diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index d0390ac42f4..bc09fa9a778 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -934,11 +934,12 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); */ #define CTL_SYSCTL_DEBUG 0 /* printf all nodes */ #define CTL_SYSCTL_NAME 1 /* string name of OID */ -#define CTL_SYSCTL_NEXT 2 /* next OID */ +#define CTL_SYSCTL_NEXT 2 /* next OID, honoring CTLFLAG_SKIP */ #define CTL_SYSCTL_NAME2OID 3 /* int array of name */ #define CTL_SYSCTL_OIDFMT 4 /* OID's kind and format */ #define CTL_SYSCTL_OIDDESCR 5 /* OID's description */ #define CTL_SYSCTL_OIDLABEL 6 /* aggregation label */ +#define CTL_SYSCTL_NEXTNOSKIP 7 /* next OID, ignoring CTLFLAG_SKIP */ /* * CTL_KERN identifiers diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index 1074ba4c0dc..c32f46b1046 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -2360,6 +2360,9 @@ print_arg(struct syscall_args *sc, unsigned long *args, register_t *retval, fprintf(fp, "oidlabel "); print_sysctl(fp, oid + 2, len - 2); break; + case CTL_SYSCTL_NEXTNOSKIP: + fprintf(fp, "nextnoskip"); + break; default: print_sysctl(fp, oid + 1, len - 1); } -- 2.45.0