From e50c9f9fe93126596d68fb231a4d0770eef51291 Mon Sep 17 00:00:00 2001 From: "Jonathan T. Looney" Date: Sat, 8 Jul 2017 06:45:34 -0700 Subject: [PATCH 01/14] Support setting 64-bit sysctl values --- Sysctl.xs | 278 ++++++++++++++++++++++++++++++------------------------ TODO | 2 - 2 files changed, 153 insertions(+), 127 deletions(-) diff --git a/Sysctl.xs b/Sysctl.xs index 54fae78..d8c5a1b 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -14,6 +14,7 @@ #include #include +#include #include #include /* struct clockinfo */ @@ -48,78 +49,114 @@ #include #include "bsd-sysctl.h" +void +_iterator_first(HV *self) +{ + SV **headp; + int name[CTL_MAXNAME]; + size_t len; + + headp = hv_fetch(self, "head", 4, 0); + if (headp == NULL || *headp == NULL) + croak( "failed to fetch head in _iterator_first()\n" ); + + if (SvPOK(*headp)) { + /* we were given starting node */ + len = sizeof(name); + if (sysctlnametomib(SvPV_nolen(*headp), name, &len) == -1) + croak("sysctlnametomib(head) failed in _iterator_first\n"); + } else { + /* start at the top like sysctl -a */ + name[0] = 1; + len = 1; + } + + hv_store(self, "_next", 5, newSVpvn((char const *) name, len * sizeof(int)), 0); + hv_store(self, "_len0", 5, newSViv(len), 0); + hv_store(self, "_name", 5, newSVpvn("", 0), 0); +} + int -_init_iterator(HV *self, int *mib, int *miblenp, int valid) { - SV **headp; - int qoid[CTL_MAXNAME]; - u_int qoidlen; - SV *clen; - SV **clenp; - int cmplen; - int j; - - qoid[0] = 0; - qoid[1] = 2; - if (valid) { - memcpy(qoid+2, mib, (*miblenp) * sizeof(int)); - qoidlen = *miblenp + 2; - *miblenp = (CTL_MAXNAME+2) * sizeof(int); - clenp = hv_fetch(self, "_len", 4, 0); - cmplen = SvIV(*clenp); - } - else { - headp = hv_fetch(self, "head", 4, 0); - if (!(headp && *headp)) { - croak( "failed to get some head in _init_iterator()\n" ); - } - if (SvPOK(*headp)) { - /* begin where asked */ - qoidlen = sizeof(qoid); - if (sysctlnametomib( SvPV_nolen(*headp), qoid+2, (size_t*)&qoidlen) == -1) { - warn( "_init_iterator(%s): sysctlnametomib lookup failed\n", - SvPV_nolen(*headp) - ); - return 0; - } - cmplen = qoidlen; - qoidlen += 2; - } - else { - /* begin at the beginning */ - qoid[2] = 1; - cmplen = 0; - qoidlen = 3; - } - clen = newSViv(cmplen); - SvREFCNT_inc(clen); - hv_store(self, "_len", 4, clen, 0); - } - - /* - printf( "next: " ); - for (j = 0; j < qoidlen; ++j) { - if (j) printf("."); printf("%d", qoid[j]); - } - printf("\n"); - */ - - /* load the mib */ - if (sysctl(qoid, qoidlen, mib, (size_t*)miblenp, 0, 0) == -1) { - return 0; - } - *miblenp /= sizeof(int); - if (*miblenp < cmplen) { - return 0 ; - } - - for (j = 0; j < cmplen; ++j) { - if (mib[j] != qoid[j+2]) { - return 0; - } - } - return 1; +_iterator_next(HV *self) +{ + SV *nextp, **len0p, *namep; + int *next, name1[CTL_MAXNAME + 2], name2[CTL_MAXNAME + 2]; + size_t len0, next_len, len1, len2; + + if (! hv_exists(self, "_len0", 5)) + _iterator_first(self); + + len0p = hv_fetch(self, "_len0", 5, 0); + if (len0p == NULL || *len0p == NULL) + croak("hv_fetch(_len0) failed in _iterator_next\n"); + len0 = SvIV(*len0p); + + nextp = hv_delete(self, "_next", 5, 0); + if (nextp == NULL) + return 0; + next = (int *) SvPV(nextp, next_len); + next_len /= sizeof(int); + + namep = hv_delete(self, "_name", 5, 0); + if (namep == NULL) + return 0; + + /* + * Get next (after _next): name1 = [ 0, 2, next ] + */ + + name1[0] = 0; + name1[1] = 2; /* get next */ + memcpy((name1 + 2), next, next_len * sizeof(int)); + len1 = next_len + 2; + + len2 = sizeof(name2); + if (sysctl(name1, len1, name2, &len2, 0, 0) < 0) { + if (errno == ENOENT) + return (0); + + croak("sysctl(next) failed in _iterator_next()\n"); + } + len2 /= sizeof(int); + + if (len2 < len0) + return 0; /* shorter than first */ + if (memcmp(name2, next, len0 * sizeof(int)) != 0) + return 0; /* does not match anymore */ + + /* at this point, name2/len2 has next iterator, update _next here */ + hv_store(self, "_next", 5, newSVpvn((char const *) name2, len2 * sizeof(int)), 0); + + /* + * Get name (from name2): name1 = [ 0, 1, name2 ] + */ + + name1[0] = 0; + name1[1] = 1; /* get name */ + memcpy((name1 + 2), name2, len2 * sizeof(int)); + len1 = len2 + 2; + + len2 = sizeof(name2); + if (sysctl(name1, len1, name2, &len2, 0, 0) < 0) { + if (errno == ENOENT) + return (0); + + croak("sysctl(name) failed in _iterator_next()\n"); + } + + /* at this point, name2/len2 has name, update _name here */ + hv_store(self, "_name", 5, newSVpvn((char const *) name2, len2 - 1), 0); + + return 1; } +/* + * The below two comparisons must be true for the 64-bit setting code to + * work correctly. + */ +_Static_assert(LLONG_MAX >= INT64_MAX, "compile-time assertion failed"); +_Static_assert(ULLONG_MAX >= UINT64_MAX, "compile-time assertion failed"); + MODULE = BSD::Sysctl PACKAGE = BSD::Sysctl PROTOTYPES: ENABLE @@ -127,67 +164,18 @@ PROTOTYPES: ENABLE SV * next (SV *refself) INIT: - int mib[CTL_MAXNAME+2]; - size_t miblen; - int qoid[CTL_MAXNAME+2]; - size_t qoidlen; - char name[BUFSIZ]; - size_t namelen; HV *self; - SV **ctxp; - SV *ctx; - SV *cname; - int j; - int *p; + SV **namep; CODE: self = (HV *)SvRV(refself); - if ((ctxp = hv_fetch(self, "_ctx", 4, 0))) { - p = (int *)SvPVX(*ctxp); - miblen = *p++; - memcpy(mib, p, miblen * sizeof(int)); - - if (!_init_iterator(self, mib, (int*)&miblen, 1)) { - XSRETURN_UNDEF; - } - } - else { - miblen = sizeof(mib)/sizeof(mib[0]); - if (!_init_iterator(self, mib, (int*)&miblen, 0)) { - XSRETURN_UNDEF; - } - } - - qoid[0] = 0; - qoid[1] = 1; - memcpy(qoid+2, mib, miblen * sizeof(int)); - qoidlen = miblen + 2; - - bzero(name, BUFSIZ); - namelen = sizeof(name); - j = sysctl(qoid, qoidlen, name, &namelen, 0, 0); - if (j || !namelen) { - warn("next(): sysctl name failure %d %zu %d", j, namelen, errno); - XSRETURN_UNDEF; - } - cname = newSVpvn(name, namelen-1); - SvREFCNT_inc(cname); - hv_store(self, "_name", 5, cname, 0); - RETVAL = cname; - - /* reuse qoid to build context store - * - the length of the mib - * - followed by the mib values - * and copy to an SV to save in the self hash - */ - p = qoid; - memcpy(p++, (const void *)&miblen, sizeof(int)); - memcpy(p, (const void *)mib, miblen * sizeof(int)); - - ctx = newSVpvn((const char *)qoid, (miblen+1) * sizeof(int)); - SvREFCNT_inc(ctx); - hv_store(self, "_ctx", 4, ctx, 0); + if (_iterator_next(self) == 0) + XSRETURN_UNDEF; + + namep = hv_fetch(self, "_name", 5, 0); + SvREFCNT_inc(*namep); + RETVAL = *namep; OUTPUT: RETVAL @@ -878,6 +866,10 @@ _mib_set(const char *arg, const char *value) SV **oidp; SV *oid; char *oid_data; + int64_t int64val; + long long llval; + uint64_t uint64val; + unsigned long long ullval; int oid_fmt; int oid_len; int intval; @@ -955,6 +947,42 @@ _mib_set(const char *arg, const char *value) newval = &ulongval; newsize = sizeof(ulongval); break; + + case FMT_64: + llval = strtoll(value, &endconvptr, 0); + if (endconvptr == value || *endconvptr != '\0' || + (llval == 0 && errno == EINVAL)) { + warn("invalid 64-bit integer: '%s'", value); + XSRETURN_UNDEF; + } +#if (LLONG_MAX > INT64_MAX) + if (llval < INT64_MIN) + int64val = INT64_MIN; + else if (llval > INT64_MAX) + int64val = INT64_MAX; + else +#endif + int64val = (int64_t)llval; + newval = &int64val; + newsize = sizeof(int64val); + break; + + case FMT_U64: + ullval = strtoull(value, &endconvptr, 0); + if (endconvptr == value || *endconvptr != '\0' || + (ullval == 0 && errno == EINVAL)) { + warn("invalid unsigned 64-bit integer: '%s'", value); + XSRETURN_UNDEF; + } +#if (ULLONG_MAX > UINT64_MAX) + if (ullval > UINT64_MAX) + uint64val = UINT64_MAX; + else +#endif + uint64val = (uint64_t)ullval; + newval = &uint64val; + newsize = sizeof(uint64val); + break; } if (sysctl((int *)oid_data, oid_len, 0, 0, newval, newsize) == -1) { diff --git a/TODO b/TODO index d897228..18b133a 100644 --- a/TODO +++ b/TODO @@ -24,5 +24,3 @@ to be diagnosed. 11. Remember to tweak the kern.ipc.maxsockbuf test when support for other platforms is added. - -12. Cannot set quad values. From edcfc5b6ad0d1e87796a97350b51d77e3019d011 Mon Sep 17 00:00:00 2001 From: Helge Oldach Date: Fri, 11 May 2018 04:50:16 -0700 Subject: [PATCH 02/14] Fix access to kern.devstat. --- Sysctl.xs | 84 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/Sysctl.xs b/Sysctl.xs index d8c5a1b..36375e7 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -571,25 +571,79 @@ _mib_lookup(const char *arg) } case FMT_DEVSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); - struct devstat *inf = (struct devstat *)buf; + struct devstat *inf = (struct devstat *)(buf + sizeof(buf)); RETVAL = newRV((SV *)c); - hv_store(c, "devno", 5, newSViv(inf->device_number), 0); - hv_store(c, "unitno", 6, newSViv(inf->unit_number), 0); + char *p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + do { + char name[BUFSIZ]; + strcpy(name, "#.devno"); name[0] = *p; + hv_store(c, name, strlen(name), newSViv(inf->device_number), 0); + strcpy(name, "#.device_name"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn(inf->device_name, strlen(inf->device_name)), 0); + strcpy(name, "#.unitno"); name[0] = *p; + hv_store(c, name, strlen(name), newSViv(inf->unit_number), 0); #if __FreeBSD_version < 500000 - hv_store(c, "sequence", 8, newSVpvn("", 0), 0); - hv_store(c, "allocated", 9, newSVpvn("", 0), 0); - hv_store(c, "startcount", 10, newSVpvn("", 0), 0); - hv_store(c, "endcount", 8, newSVpvn("", 0), 0); - hv_store(c, "busyfromsec", 11, newSVpvn("", 0), 0); - hv_store(c, "busyfromfrac", 12, newSVpvn("", 0), 0); + strcpy(name, "#.sequence"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.allocated"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.startcount"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.endcount"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.busyfromsec"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.busyfromfrac"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.bytes_no_data"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.bytes_read"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.bytes_write"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.bytes_free"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.operations_no_data"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.operations_read"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.operations_write"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); + strcpy(name, "#.operations_free"); name[0] = *p; + hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); #else - hv_store(c, "sequence", 8, newSVuv(inf->sequence0), 0); - hv_store(c, "allocated", 9, newSViv(inf->allocated), 0); - hv_store(c, "startcount", 10, newSViv(inf->start_count), 0); - hv_store(c, "endcount", 8, newSViv(inf->end_count), 0); - hv_store(c, "busyfromsec", 11, newSViv(inf->busy_from.sec), 0); - hv_store(c, "busyfromfrac", 12, newSVuv(inf->busy_from.frac), 0); + strcpy(name, "#.sequence"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->sequence0), 0); + strcpy(name, "#.allocated"); name[0] = *p; + hv_store(c, name, strlen(name), newSViv(inf->allocated), 0); + strcpy(name, "#.startcount"); name[0] = *p; + hv_store(c, name, strlen(name), newSViv(inf->start_count), 0); + strcpy(name, "#.endcount"); name[0] = *p; + hv_store(c, name, strlen(name), newSViv(inf->end_count), 0); + strcpy(name, "#.busyfromsec"); name[0] = *p; + hv_store(c, name, strlen(name), newSViv(inf->busy_from.sec), 0); + strcpy(name, "#.busyfromfrac"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->busy_from.frac), 0); + strcpy(name, "#.bytes_no_data"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->bytes[DEVSTAT_NO_DATA]), 0); + strcpy(name, "#.bytes_read"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->bytes[DEVSTAT_READ]), 0); + strcpy(name, "#.bytes_write"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->bytes[DEVSTAT_WRITE]), 0); + strcpy(name, "#.bytes_free"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->bytes[DEVSTAT_FREE]), 0); + strcpy(name, "#.operations_no_data"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->operations[DEVSTAT_NO_DATA]), 0); + strcpy(name, "#.operations_read"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->operations[DEVSTAT_READ]), 0); + strcpy(name, "#.operations_write"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->operations[DEVSTAT_WRITE]), 0); + strcpy(name, "#.operations_free"); name[0] = *p; + hv_store(c, name, strlen(name), newSVuv(inf->operations[DEVSTAT_FREE]), 0); #endif + ++p; + ++inf; + } while (inf < (struct devstat *)(buf + buflen)); break; } #if __FreeBSD_version >= 500000 From 712917f100617f78e88d19bb51cefe01f5cb9c2a Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 24 Jun 2020 16:59:50 -0700 Subject: [PATCH 03/14] - Update to run on most recent -current. - Update to support the latest bool type. --- Makefile.PL | 2 + Sysctl.pm | 6 +- Sysctl.xs | 327 ++++++++++++++++++++++++---------------------------- 3 files changed, 158 insertions(+), 177 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 2f6a848..6ec8e35 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -120,3 +120,5 @@ S,xvfsconf 24 auto T,struct_cdev 25 auto Q 26 FMT_64 QU 27 FMT_U64 +C 28 FMT_INT8 +CU 29 FMT_UINT8 diff --git a/Sysctl.pm b/Sysctl.pm index 3394214..c7d7713 100644 --- a/Sysctl.pm +++ b/Sysctl.pm @@ -42,6 +42,8 @@ use constant FMT_XVFSCONF => 24; use constant FMT_STRUCT_CDEV => 25; use constant FMT_64 => 26; use constant FMT_U64 => 27; +use constant FMT_UINT8 => 28; +use constant FMT_INT8 => 29; push @EXPORT_OK, 'sysctl'; sub sysctl { @@ -105,7 +107,9 @@ sub value { sub reset { my $self = shift; - delete $self->{_ctx}; + delete $self->{_next}; + delete $self->{_name}; + delete $self->{_len0}; return $self; } diff --git a/Sysctl.xs b/Sysctl.xs index 36375e7..964f5a0 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -52,102 +52,102 @@ void _iterator_first(HV *self) { - SV **headp; - int name[CTL_MAXNAME]; - size_t len; - - headp = hv_fetch(self, "head", 4, 0); - if (headp == NULL || *headp == NULL) - croak( "failed to fetch head in _iterator_first()\n" ); - - if (SvPOK(*headp)) { - /* we were given starting node */ - len = sizeof(name); - if (sysctlnametomib(SvPV_nolen(*headp), name, &len) == -1) - croak("sysctlnametomib(head) failed in _iterator_first\n"); - } else { - /* start at the top like sysctl -a */ - name[0] = 1; - len = 1; - } - - hv_store(self, "_next", 5, newSVpvn((char const *) name, len * sizeof(int)), 0); - hv_store(self, "_len0", 5, newSViv(len), 0); - hv_store(self, "_name", 5, newSVpvn("", 0), 0); + SV **headp; + int name[CTL_MAXNAME]; + size_t len; + + headp = hv_fetch(self, "head", 4, 0); + if (headp == NULL || *headp == NULL) + croak( "failed to fetch head in _iterator_first()\n" ); + + if (SvPOK(*headp)) { + /* we were given starting node */ + len = sizeof(name); + if (sysctlnametomib(SvPV_nolen(*headp), name, &len) == -1) + croak("sysctlnametomib(head) failed in _iterator_first\n"); + } else { + /* start at the top like sysctl -a */ + name[0] = 1; + len = 1; + } + + hv_store(self, "_next", 5, newSVpvn((char const *) name, len * sizeof(int)), 0); + hv_store(self, "_len0", 5, newSViv(len), 0); + hv_store(self, "_name", 5, newSVpvn("", 0), 0); } int _iterator_next(HV *self) { - SV *nextp, **len0p, *namep; - int *next, name1[CTL_MAXNAME + 2], name2[CTL_MAXNAME + 2]; - size_t len0, next_len, len1, len2; - - if (! hv_exists(self, "_len0", 5)) - _iterator_first(self); - - len0p = hv_fetch(self, "_len0", 5, 0); - if (len0p == NULL || *len0p == NULL) - croak("hv_fetch(_len0) failed in _iterator_next\n"); - len0 = SvIV(*len0p); - - nextp = hv_delete(self, "_next", 5, 0); - if (nextp == NULL) - return 0; - next = (int *) SvPV(nextp, next_len); - next_len /= sizeof(int); - - namep = hv_delete(self, "_name", 5, 0); - if (namep == NULL) - return 0; - - /* - * Get next (after _next): name1 = [ 0, 2, next ] - */ - - name1[0] = 0; - name1[1] = 2; /* get next */ - memcpy((name1 + 2), next, next_len * sizeof(int)); - len1 = next_len + 2; - - len2 = sizeof(name2); - if (sysctl(name1, len1, name2, &len2, 0, 0) < 0) { - if (errno == ENOENT) - return (0); - - croak("sysctl(next) failed in _iterator_next()\n"); - } - len2 /= sizeof(int); - - if (len2 < len0) - return 0; /* shorter than first */ - if (memcmp(name2, next, len0 * sizeof(int)) != 0) - return 0; /* does not match anymore */ - - /* at this point, name2/len2 has next iterator, update _next here */ - hv_store(self, "_next", 5, newSVpvn((char const *) name2, len2 * sizeof(int)), 0); - - /* - * Get name (from name2): name1 = [ 0, 1, name2 ] - */ - - name1[0] = 0; - name1[1] = 1; /* get name */ - memcpy((name1 + 2), name2, len2 * sizeof(int)); - len1 = len2 + 2; - - len2 = sizeof(name2); - if (sysctl(name1, len1, name2, &len2, 0, 0) < 0) { - if (errno == ENOENT) - return (0); - - croak("sysctl(name) failed in _iterator_next()\n"); - } - - /* at this point, name2/len2 has name, update _name here */ - hv_store(self, "_name", 5, newSVpvn((char const *) name2, len2 - 1), 0); - - return 1; + SV *nextp, **len0p, *namep; + int *next, name1[CTL_MAXNAME + 2], name2[CTL_MAXNAME + 2]; + size_t len0, next_len, len1, len2; + + if (! hv_exists(self, "_len0", 5)) + _iterator_first(self); + + len0p = hv_fetch(self, "_len0", 5, 0); + if (len0p == NULL || *len0p == NULL) + croak("hv_fetch(_len0) failed in _iterator_next\n"); + len0 = SvIV(*len0p); + + nextp = hv_delete(self, "_next", 5, 0); + if (nextp == NULL) + return 0; + next = (int *) SvPV(nextp, next_len); + next_len /= sizeof(int); + + namep = hv_delete(self, "_name", 5, 0); + if (namep == NULL) + return 0; + + /* + * Get next (after _next): name1 = [ 0, 2, next ] + */ + + name1[0] = 0; + name1[1] = 2; /* get next */ + memcpy((name1 + 2), next, next_len * sizeof(int)); + len1 = next_len + 2; + + len2 = sizeof(name2); + if (sysctl(name1, len1, name2, &len2, 0, 0) < 0) { + if (errno == ENOENT) + return (0); + + croak("sysctl(next) failed in _iterator_next()\n"); + } + len2 /= sizeof(int); + + if (len2 < len0) + return 0; /* shorter than first */ + if (memcmp(name2, next, len0 * sizeof(int)) != 0) + return 0; /* does not match anymore */ + + /* at this point, name2/len2 has next iterator, update _next here */ + hv_store(self, "_next", 5, newSVpvn((char const *) name2, len2 * sizeof(int)), 0); + + /* + * Get name (from name2): name1 = [ 0, 1, name2 ] + */ + + name1[0] = 0; + name1[1] = 1; /* get name */ + memcpy((name1 + 2), name2, len2 * sizeof(int)); + len1 = len2 + 2; + + len2 = sizeof(name2); + if (sysctl(name1, len1, name2, &len2, 0, 0) < 0) { + if (errno == ENOENT) + return (0); + + croak("sysctl(name) failed in _iterator_next()\n"); + } + + /* at this point, name2/len2 has name, update _name here */ + hv_store(self, "_name", 5, newSVpvn((char const *) name2, len2 - 1), 0); + + return 1; } /* @@ -170,12 +170,12 @@ next (SV *refself) CODE: self = (HV *)SvRV(refself); - if (_iterator_next(self) == 0) - XSRETURN_UNDEF; - - namep = hv_fetch(self, "_name", 5, 0); - SvREFCNT_inc(*namep); - RETVAL = *namep; + if (_iterator_next(self) == 0) + XSRETURN_UNDEF; + + namep = hv_fetch(self, "_name", 5, 0); + SvREFCNT_inc(*namep); + RETVAL = *namep; OUTPUT: RETVAL @@ -223,6 +223,10 @@ _mib_info(const char *arg) case 'A': fmt_type = FMT_A; break; + case 'C': + ++f; + fmt_type = *f == 'U' ? FMT_UINT8 : FMT_INT8; + break; case 'I': ++f; fmt_type = *f == 'U' ? FMT_UINT : FMT_INT; @@ -327,6 +331,21 @@ _mib_description(const char *arg) OUTPUT: RETVAL +#define DECODE(T) \ + if (buflen == sizeof(T)) { \ + RETVAL = newSViv(*(T *)buf); \ + } \ + else { \ + AV *c = (AV *)sv_2mortal((SV *)newAV()); \ + char *bptr = buf; \ + while (buflen >= sizeof(T)) { \ + av_push(c, newSViv(*(T *)bptr)); \ + buflen -= sizeof(T); \ + bptr += sizeof(T); \ + } \ + RETVAL = newRV((SV *)c); \ + } + SV * _mib_lookup(const char *arg) INIT: @@ -386,96 +405,31 @@ _mib_lookup(const char *arg) SvCUR_set(sv_buf, buflen); RETVAL = sv_buf; break; + case FMT_INT8: + DECODE(int8_t); + break; + case FMT_UINT8: + DECODE(uint8_t); + break; case FMT_INT: - if (buflen == sizeof(int)) { - RETVAL = newSViv(*(int *)buf); - } - else { - AV *c = (AV *)sv_2mortal((SV *)newAV()); - char *bptr = buf; - while (buflen >= sizeof(int)) { - av_push(c, newSViv(*(int *)bptr)); - buflen -= sizeof(int); - bptr += sizeof(int); - } - RETVAL = newRV((SV *)c); - } + DECODE(int); break; case FMT_UINT: - if (buflen == sizeof(unsigned int)) { - RETVAL = newSViv(*(unsigned int *)buf); - } - else { - AV *c = (AV *)sv_2mortal((SV *)newAV()); - char *bptr = buf; - while (buflen >= sizeof(unsigned int)) { - av_push(c, newSViv(*(unsigned int *)bptr)); - buflen -= sizeof(unsigned int); - bptr += sizeof(unsigned int); - } - RETVAL = newRV((SV *)c); - } + DECODE(unsigned int); break; case FMT_LONG: - if (buflen == sizeof(long)) { - RETVAL = newSVuv(*(long *)buf); - } - else { - AV *c = (AV *)sv_2mortal((SV *)newAV()); - char *bptr = buf; - while (buflen >= sizeof(long)) { - av_push(c, newSVuv(*(long *)bptr)); - buflen -= sizeof(long); - bptr += sizeof(long); - } - RETVAL = newRV((SV *)c); - } + DECODE(long); break; case FMT_ULONG: - if (buflen == sizeof(unsigned long)) { - RETVAL = newSVuv(*(unsigned long *)buf); - } - else { - AV *c = (AV *)sv_2mortal((SV *)newAV()); - char *bptr = buf; - while (buflen >= sizeof(unsigned long)) { - av_push(c, newSVuv(*(unsigned long *)bptr)); - buflen -= sizeof(unsigned long); - bptr += sizeof(unsigned long); - } - RETVAL = newRV((SV *)c); - } + DECODE(unsigned long); break; case FMT_64: - if (buflen == sizeof(int64_t)) { - RETVAL = newSVuv(*(int64_t *)buf); - } - else { - AV *c = (AV *)sv_2mortal((SV *)newAV()); - char *bptr = buf; - while (buflen >= sizeof(int64_t)) { - av_push(c, newSVuv(*(int64_t *)bptr)); - buflen -= sizeof(int64_t); - bptr += sizeof(int64_t); - } - RETVAL = newRV((SV *)c); - } + DECODE(int64_t); break; case FMT_U64: - if (buflen == sizeof(uint64_t)) { - RETVAL = newSVuv(*(uint64_t *)buf); - } - else { - AV *c = (AV *)sv_2mortal((SV *)newAV()); - char *bptr = buf; - while (buflen >= sizeof(uint64_t)) { - av_push(c, newSVuv(*(uint64_t *)bptr)); - buflen -= sizeof(uint64_t); - bptr += sizeof(uint64_t); - } - RETVAL = newRV((SV *)c); - } + DECODE(uint64_t); break; +#undef DECODE case FMT_CLOCKINFO: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct clockinfo *inf = (struct clockinfo *)buf; @@ -924,6 +878,8 @@ _mib_set(const char *arg, const char *value) long long llval; uint64_t uint64val; unsigned long long ullval; + int8_t int8val; + uint8_t uint8val; int oid_fmt; int oid_len; int intval; @@ -982,6 +938,26 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(uintval); break; + case FMT_INT8: + int8val = (int8_t)strtol(value, &endconvptr, 0); + if (endconvptr == value || *endconvptr != '\0') { + warn("invalid integer: '%s'", value); + XSRETURN_UNDEF; + } + newval = &int8val; + newsize = sizeof(int8val); + break; + + case FMT_UINT8: + uint8val = (uint8_t)strtoul(value, &endconvptr, 0); + if (endconvptr == value || *endconvptr != '\0') { + warn("invalid unsigned integer: '%s'", value); + XSRETURN_UNDEF; + } + newval = &uint8val; + newsize = sizeof(uint8val); + break; + case FMT_LONG: longval = strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { @@ -1001,7 +977,6 @@ _mib_set(const char *arg, const char *value) newval = &ulongval; newsize = sizeof(ulongval); break; - case FMT_64: llval = strtoll(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0' || From 23e964968a18e15035afad97134215f474cacd2d Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 10:13:08 -0800 Subject: [PATCH 04/14] Remove code for unsupported versions of FreeBSD. --- Sysctl.pm | 8 +--- Sysctl.xs | 114 ---------------------------------------------------- eg/sizeof.c | 7 +--- t/01-get.t | 25 ++---------- 4 files changed, 6 insertions(+), 148 deletions(-) diff --git a/Sysctl.pm b/Sysctl.pm index c7d7713..22ddcc8 100644 --- a/Sysctl.pm +++ b/Sysctl.pm @@ -353,7 +353,7 @@ at least for the time being. This is a bug that should be reported. =head1 LIMITATIONS -At the current time, FreeBSD versions 4.x through 8.x are +At the current time only officially supported FreeBSD versions are supported. I am looking for volunteers to help port this module to NetBSD and @@ -363,12 +363,6 @@ for more information. =head1 BUGS -Some branches are not iterated on FreeBSD 4 (and perl 5.6.1). Most -notably, the C branch. I am not sure of the reason, but -it's a failure in a C system call, so it could be related -to that release. As FreeBSD 4.x reached the end of its supported -life in 2007, I'm not particularly fussed. - Please report all bugs at L. diff --git a/Sysctl.xs b/Sysctl.xs index 964f5a0..ecf831f 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -7,11 +7,6 @@ #include "perl.h" #include "XSUB.h" -/* define _FreeBSD_version where applicable */ -#if __FreeBSD__ >= 2 -#include -#endif - #include #include #include @@ -20,9 +15,6 @@ #include /* struct clockinfo */ #include /* struct vmtotal */ #include /* struct loadavg */ -#if __FreeBSD_version < 1000000 -#include /* struct mbstat (opaque mib) */ -#endif #include /* struct ntptimeval (opaque mib) */ #include /* struct devstat (opaque mib) */ #include /* struct xvfsconf (opaque mib) */ @@ -32,9 +24,6 @@ #include #include #include -#if __FreeBSD_version < 500000 -#include /* struct tcpstat prerequisite */ -#endif #include /* struct icmpstat */ #include /* struct igmpstat */ @@ -479,38 +468,6 @@ _mib_lookup(const char *arg) break; } /* the remaining custom formats are for opaque mibs */ -#if __FreeBSD_version < 1000000 - case FMT_MBSTAT: { - HV *c = (HV *)sv_2mortal((SV *)newHV()); - struct mbstat *inf = (struct mbstat *)buf; - RETVAL = newRV((SV *)c); - hv_store(c, "copymfail", 9, newSVuv(inf->m_mcfail), 0); - hv_store(c, "pullupfail", 10, newSVuv(inf->m_mpfail), 0); - hv_store(c, "mbufsize", 8, newSVuv(inf->m_msize), 0); - hv_store(c, "mclustsize", 10, newSVuv(inf->m_mclbytes), 0); - hv_store(c, "minclsize", 9, newSVuv(inf->m_minclsize), 0); - hv_store(c, "mbuflen", 7, newSVuv(inf->m_mlen), 0); - hv_store(c, "mbufhead", 8, newSVuv(inf->m_mhlen), 0); - hv_store(c, "drain", 5, newSVuv(inf->m_drain), 0); -#if __FreeBSD_version < 500000 - hv_store(c, "numtypes", 8, newSVpvn("", 0), 0); -#else - hv_store(c, "numtypes", 8, newSViv(inf->m_numtypes), 0); -#endif -#if __FreeBSD_version < 600000 - hv_store(c, "mbufs", 5, newSVpvn("", 0), 0); - hv_store(c, "mclusts", 7, newSVpvn("", 0), 0); - hv_store(c, "sfallocwait", 11, newSVpvn("", 0), 0); - hv_store(c, "sfiocnt", 7, newSVpvn("", 0), 0); -#else - hv_store(c, "mbufs", 5, newSVuv(inf->m_mbufs), 0); - hv_store(c, "mclusts", 7, newSVuv(inf->m_mclusts), 0); - hv_store(c, "sfallocwait", 11, newSVuv(inf->sf_allocwait), 0); - hv_store(c, "sfiocnt", 7, newSVuv(inf->sf_iocnt), 0); -#endif - break; - } -#endif case FMT_NTPTIMEVAL: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct ntptimeval *inf = (struct ntptimeval *)buf; @@ -536,36 +493,6 @@ _mib_lookup(const char *arg) hv_store(c, name, strlen(name), newSVpvn(inf->device_name, strlen(inf->device_name)), 0); strcpy(name, "#.unitno"); name[0] = *p; hv_store(c, name, strlen(name), newSViv(inf->unit_number), 0); -#if __FreeBSD_version < 500000 - strcpy(name, "#.sequence"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.allocated"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.startcount"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.endcount"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.busyfromsec"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.busyfromfrac"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.bytes_no_data"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.bytes_read"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.bytes_write"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.bytes_free"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.operations_no_data"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.operations_read"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.operations_write"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); - strcpy(name, "#.operations_free"); name[0] = *p; - hv_store(c, name, strlen(name), newSVpvn("", 0)), 0); -#else strcpy(name, "#.sequence"); name[0] = *p; hv_store(c, name, strlen(name), newSVuv(inf->sequence0), 0); strcpy(name, "#.allocated"); name[0] = *p; @@ -594,13 +521,11 @@ _mib_lookup(const char *arg) hv_store(c, name, strlen(name), newSVuv(inf->operations[DEVSTAT_WRITE]), 0); strcpy(name, "#.operations_free"); name[0] = *p; hv_store(c, name, strlen(name), newSVuv(inf->operations[DEVSTAT_FREE]), 0); -#endif ++p; ++inf; } while (inf < (struct devstat *)(buf + buflen)); break; } -#if __FreeBSD_version >= 500000 case FMT_XVFSCONF: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct xvfsconf *inf = (struct xvfsconf *)buf; @@ -611,7 +536,6 @@ _mib_lookup(const char *arg) hv_store(c, "flags", 5, newSViv(inf->vfc_flags), 0); break; } -#endif case FMT_ICMPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct icmpstat *inf = (struct icmpstat *)buf; @@ -632,17 +556,6 @@ _mib_lookup(const char *arg) HV *c = (HV *)sv_2mortal((SV *)newHV()); struct igmpstat *inf = (struct igmpstat *)buf; RETVAL = newRV((SV *)c); -#if __FreeBSD_version < 800070 - hv_store(c, "total", 5, newSVuv(inf->igps_rcv_total), 0); - hv_store(c, "tooshort", 8, newSVuv(inf->igps_rcv_tooshort), 0); - hv_store(c, "badsum", 6, newSVuv(inf->igps_rcv_badsum), 0); - hv_store(c, "queries", 7, newSVuv(inf->igps_rcv_queries), 0); - hv_store(c, "badqueries", 10, newSVuv(inf->igps_rcv_badqueries), 0); - hv_store(c, "reports", 7, newSVuv(inf->igps_rcv_reports), 0); - hv_store(c, "badreports", 10, newSVuv(inf->igps_rcv_badreports), 0); - hv_store(c, "ourreports", 10, newSVuv(inf->igps_rcv_ourreports), 0); - hv_store(c, "sent", 4, newSVuv(inf->igps_snd_reports), 0); -#else /* Message statistics */ hv_store(c, "total", 5, newSVuv(inf->igps_rcv_total), 0); hv_store(c, "tooshort", 8, newSVuv(inf->igps_rcv_tooshort), 0); @@ -663,7 +576,6 @@ _mib_lookup(const char *arg) hv_store(c, "ourreports", 10, newSVuv(inf->igps_rcv_ourreports), 0); hv_store(c, "nore", 4, newSVuv(inf->igps_rcv_nora), 0); hv_store(c, "sent", 4, newSVuv(inf->igps_snd_reports), 0); -#endif break; } case FMT_TCPSTAT: { @@ -747,26 +659,10 @@ _mib_lookup(const char *arg) hv_store(c, "zonefail", 8, newSVuv(inf->tcps_sc_zonefail), 0); hv_store(c, "sendcookie", 10, newSVuv(inf->tcps_sc_sendcookie), 0); hv_store(c, "recvcookie", 10, newSVuv(inf->tcps_sc_recvcookie), 0); -#if __FreeBSD_version < 500000 - hv_store(c, "minmssdrops", 11, newSVpvn("", 0), 0); - hv_store(c, "sendrexmitbad", 13, newSVpvn("", 0), 0); - hv_store(c, "hostcacheadd", 12, newSVpvn("", 0), 0); - hv_store(c, "hostcacheover", 13, newSVpvn("", 0), 0); -#else hv_store(c, "minmssdrops", 11, newSVuv(inf->tcps_minmssdrops), 0); hv_store(c, "sendrexmitbad", 13, newSVuv(inf->tcps_sndrexmitbad), 0); hv_store(c, "hostcacheadd", 12, newSVuv(inf->tcps_hc_added), 0); hv_store(c, "hostcacheover", 13, newSVuv(inf->tcps_hc_bucketoverflow), 0); -#endif -#if __FreeBSD_version < 600000 - hv_store(c, "badrst", 6, newSVpvn("", 0), 0); - hv_store(c, "sackrecover", 11, newSVpvn("", 0), 0); - hv_store(c, "sackrexmitsegs", 14, newSVpvn("", 0), 0); - hv_store(c, "sackrexmitbytes", 15, newSVpvn("", 0), 0); - hv_store(c, "sackrecv", 8, newSVpvn("", 0), 0); - hv_store(c, "sacksend", 8, newSVpvn("", 0), 0); - hv_store(c, "sackscorebover", 14, newSVpvn("", 0), 0); -#else hv_store(c, "badrst", 6, newSVuv(inf->tcps_badrst), 0); hv_store(c, "sackrecover", 11, newSVuv(inf->tcps_sack_recovery_episode), 0); hv_store(c, "sackrexmitsegs", 14, newSVuv(inf->tcps_sack_rexmits), 0); @@ -774,7 +670,6 @@ _mib_lookup(const char *arg) hv_store(c, "sackrecv", 8, newSVuv(inf->tcps_sack_rcv_blocks), 0); hv_store(c, "sacksend", 8, newSVuv(inf->tcps_sack_send_blocks), 0); hv_store(c, "sackscorebover", 14, newSVuv(inf->tcps_sack_sboverflow), 0); -#endif break; } case FMT_UDPSTAT: { @@ -825,21 +720,12 @@ _mib_lookup(const char *arg) /* don't know if any IA64 fields are useful, * (as per /usr/src/sys/ia64/include/bootinfo.h) */ -#ifdef __ia64 - hv_store(c, "biosused", 8, newSVpvn("", 0), 0); - hv_store(c, "size", 4, newSVpvn("", 0), 0); - hv_store(c, "msizevalid", 10, newSVpvn("", 0), 0); - hv_store(c, "biosdev", 7, newSVpvn("", 0), 0); - hv_store(c, "basemem", 7, newSVpvn("", 0), 0); - hv_store(c, "extmem", 6, newSVpvn("", 0), 0); -#else hv_store(c, "biosused", 8, newSVuv(inf->bi_n_bios_used), 0); hv_store(c, "size", 4, newSVuv(inf->bi_size), 0); hv_store(c, "msizevalid", 10, newSVuv(inf->bi_memsizes_valid), 0); hv_store(c, "biosdev", 7, newSVuv(inf->bi_bios_dev), 0); hv_store(c, "basemem", 7, newSVuv(inf->bi_basemem), 0); hv_store(c, "extmem", 6, newSVuv(inf->bi_extmem), 0); -#endif break; } #endif diff --git a/eg/sizeof.c b/eg/sizeof.c index a6ae45a..2cbda92 100644 --- a/eg/sizeof.c +++ b/eg/sizeof.c @@ -6,7 +6,6 @@ #include #include -#include /* struct mbstat */ #include /* struct ntptimeval */ #include /* struct devstat */ #include /* struct xvfsconf */ @@ -21,17 +20,15 @@ #include /* struct udpstat prerequisite */ #include /* struct udpstat prerequisite */ #include /* struct udpstat */ -#ifdef NEVER #include /* struct xinpcb */ +#include /* struct xinpcb */ #include /* struct xinpcb */ -#endif #include /* struct rip6stat */ #include /* struct bootinfo */ int main(int argc, char **argv) { printf( "sizeof(int) = %d\n", sizeof(int) ); - printf( "sizeof(struct mbstat) = %d\n", sizeof(struct mbstat) ); printf( "sizeof(struct ntptimeval) = %d\n", sizeof(struct ntptimeval) ); printf( "sizeof(struct timespec) = %d\n", sizeof(struct timespec) ); printf( "sizeof(struct devstat) = %d\n", sizeof(struct devstat) ); @@ -41,7 +38,7 @@ main(int argc, char **argv) { printf( "sizeof(struct igmpstat) = %d\n", sizeof(struct igmpstat) ); printf( "sizeof(struct tcpstat) = %d\n", sizeof(struct tcpstat) ); printf( "sizeof(struct udpstat) = %d\n", sizeof(struct udpstat) ); - /* printf( "sizeof(struct xinpcb) = %d\n", sizeof(struct xinpcb) ); */ + printf( "sizeof(struct xinpcb) = %d\n", sizeof(struct xinpcb) ); printf( "sizeof(struct rip6stat) = %d\n", sizeof(struct rip6stat) ); printf( "sizeof(struct bootinfo) = %d\n", sizeof(struct bootinfo) ); return 0; diff --git a/t/01-get.t b/t/01-get.t index a37082f..fa3a032 100644 --- a/t/01-get.t +++ b/t/01-get.t @@ -4,7 +4,7 @@ # Copyright (C) 2006, 2009 David Landgren use strict; -use Test::More tests => 23; +use Test::More tests => 20; use BSD::Sysctl qw(sysctl sysctl_exists); @@ -24,26 +24,7 @@ ok(BSD::Sysctl::_mib_exists('kern.maxproc'), 'mib exists'); ok($sysctl_info, 'mib lookup kern.ipc.maxsockbuf'); my ($fmt, @oid) = unpack( 'i i/i', $sysctl_info ); - # This is FMT_INT for FreeBSD 4.x, deal with it - # is($fmt, BSD::Sysctl::FMT_ULONG, '... display format type ULONG'); - is_deeply(\@oid, [1, 30, 1], '... oid 1.30.1'); -} - -{ - my $sysctl_info = BSD::Sysctl::_mib_info('kern.ipc.maxsockbuf'); - ok($sysctl_info, 'mib lookup kern.ipc.maxsockbuf'); - my ($fmt, @oid) = unpack( 'i i/i', $sysctl_info ); - - # TODO: this will require a revision when OpenBSD or NetBSD support is added - my $osrelease = sysctl('kern.osrelease'); - ok($osrelease, "sysctl('kern.osrelease')"); - if ($osrelease =~ /^4\./) { - # FreeBSD 4.x stores this in a smaller data type - is($fmt, BSD::Sysctl::FMT_INT, '... display format type INT (on 4.x)'); - } - else { - is($fmt, BSD::Sysctl::FMT_ULONG, '... display format type ULONG'); - } + is($fmt, BSD::Sysctl::FMT_ULONG, '... display format type ULONG'); is_deeply(\@oid, [1, 30, 1], '... oid 1.30.1'); } @@ -82,5 +63,5 @@ ok(!sysctl_exists('kern.maxbananas'), 'kern.maxbananas does not exist'); cmp_ok($nr_files, '>', 0, "got the number of open files again (now $nr_files)"); } -is(scalar(keys %BSD::Sysctl::MIB_CACHE), 7, 'cached mib count') +is(scalar(keys %BSD::Sysctl::MIB_CACHE), 6, 'cached mib count') or do { diag("cached: [$_]") for sort keys %BSD::Sysctl::MIB_CACHE }; From 5863353dbceb8f853c1e7fc93c748a1f96cbd700 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 10:14:13 -0800 Subject: [PATCH 05/14] Use constants instead of numbers. Makes code more readable without additional comments. --- Sysctl.xs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Sysctl.xs b/Sysctl.xs index ecf831f..f037e0e 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -12,6 +12,13 @@ #include #include +#if __FreeBSD_version <= 1201500 +#define CTL_SYSCTL 0 /* "magic" numbers */ +#define CTL_SYSCTL_NAME 1 /* string name of OID */ +#define CTL_SYSCTL_NEXT 2 /* next OID */ +#define CTL_SYSCTL_OIDFMT 4 /* OID's kind and format */ +#endif + #include /* struct clockinfo */ #include /* struct vmtotal */ #include /* struct loadavg */ @@ -90,12 +97,8 @@ _iterator_next(HV *self) if (namep == NULL) return 0; - /* - * Get next (after _next): name1 = [ 0, 2, next ] - */ - - name1[0] = 0; - name1[1] = 2; /* get next */ + name1[0] = CTL_SYSCTL; + name1[1] = CTL_SYSCTL_NEXT; memcpy((name1 + 2), next, next_len * sizeof(int)); len1 = next_len + 2; @@ -116,12 +119,8 @@ _iterator_next(HV *self) /* at this point, name2/len2 has next iterator, update _next here */ hv_store(self, "_next", 5, newSVpvn((char const *) name2, len2 * sizeof(int)), 0); - /* - * Get name (from name2): name1 = [ 0, 1, name2 ] - */ - - name1[0] = 0; - name1[1] = 1; /* get name */ + name1[0] = CTL_SYSCTL; + name1[1] = CTL_SYSCTL_NAME; memcpy((name1 + 2), name2, len2 * sizeof(int)); len1 = len2 + 2; @@ -202,8 +201,8 @@ _mib_info(const char *arg) nr_octets = miblen; /* determine how to format the results */ - mib[0] = 0; - mib[1] = 4; + mib[0] = CTL_SYSCTL; + mib[1] = CTL_SYSCTL_OIDFMT; if (sysctl(mib, nr_octets+2, fmt, &len, NULL, 0) == -1) { XSRETURN_UNDEF; } From 795613aa27fe12b241abb976cf65fbafd4c3fce6 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 10:50:58 -0800 Subject: [PATCH 06/14] Add support for CTL_SYSCTL_NEXTNOSKIP. Now all tests pass! --- Sysctl.pm | 10 ++++++++-- Sysctl.xs | 11 ++++++++--- t/03-iterator.t | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Sysctl.pm b/Sysctl.pm index 22ddcc8..8f9ca79 100644 --- a/Sysctl.pm +++ b/Sysctl.pm @@ -87,10 +87,11 @@ sub set { } sub iterator { - my $class = shift; - my $name = shift; + my ($class, $name, %args) = @_; my $self; + $self->{head} = $name || undef; + $self->{noskip} = 1 if (defined($args{noskip})); return bless $self, $class; } @@ -264,6 +265,11 @@ fails, undef is returned. print $k->name, '=', $k->value, "\n"; } +To force iteration through variables that are marked with CTLFLAG_SKIP +use 'noskip' argument: + + my $k = BSD::Sysctl->iterator( 'kern', ( noskip => 1 )); + =item next Moves the iterator to the next sysctl variable and loads the diff --git a/Sysctl.xs b/Sysctl.xs index f037e0e..7c82fee 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -8,8 +8,7 @@ #include "XSUB.h" #include -#include -#include +#include #include #if __FreeBSD_version <= 1201500 @@ -98,7 +97,13 @@ _iterator_next(HV *self) return 0; name1[0] = CTL_SYSCTL; - name1[1] = CTL_SYSCTL_NEXT; + name1[1] = hv_exists(self, "noskip", 6) ? +#if __FreeBSD_version >= 1300120 + CTL_SYSCTL_NEXTNOSKIP +#else + CTL_SYSCTL_NEXT +#endif + : CTL_SYSCTL_NEXT; memcpy((name1 + 2), next, next_len * sizeof(int)); len1 = next_len + 2; diff --git a/t/03-iterator.t b/t/03-iterator.t index b575ca7..834ed63 100644 --- a/t/03-iterator.t +++ b/t/03-iterator.t @@ -8,7 +8,7 @@ use Test::More tests => 15; use BSD::Sysctl; -my $it = BSD::Sysctl->iterator('kern.ipc'); +my $it = BSD::Sysctl->iterator('kern.ipc', ( noskip => 1 )); ok( defined($it), 'defined a BSD::Sysctl iterator' ); my $sysctl_binary; From 817f08a58819f39f0a6998ed6f91a5a02aa7e361 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 11:12:07 -0800 Subject: [PATCH 07/14] Remove strange references to "T,struct cdev" format. In modern FreeBSD there are no declarations of sysctl format that start with "T". --- Makefile.PL | 1 - Sysctl.pm | 1 - Sysctl.xs | 10 ---------- 3 files changed, 12 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 6ec8e35..813650d 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -117,7 +117,6 @@ S,udpstat 21 auto S,vmtotal 22 auto S,xinpcb 23 auto S,xvfsconf 24 auto -T,struct_cdev 25 auto Q 26 FMT_64 QU 27 FMT_U64 C 28 FMT_INT8 diff --git a/Sysctl.pm b/Sysctl.pm index 8f9ca79..bf7336f 100644 --- a/Sysctl.pm +++ b/Sysctl.pm @@ -39,7 +39,6 @@ use constant FMT_UDPSTAT => 21; use constant FMT_VMTOTAL => 22; use constant FMT_XINPCB => 23; use constant FMT_XVFSCONF => 24; -use constant FMT_STRUCT_CDEV => 25; use constant FMT_64 => 26; use constant FMT_U64 => 27; use constant FMT_UINT8 => 28; diff --git a/Sysctl.xs b/Sysctl.xs index 7c82fee..bcb793d 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -257,15 +257,6 @@ _mib_info(const char *arg) } break; } - case 'T': { - if (strcmp(f,"T,struct cdev *") == 0) { - fmt_type = FMT_STRUCT_CDEV; - } - else { - /* bleah */ - } - break; - } case 'N': fmt_type = FMT_N; break; @@ -738,7 +729,6 @@ _mib_lookup(const char *arg) case FMT_NFSRVSTATS: case FMT_NFSSTATS: case FMT_XINPCB: - case FMT_STRUCT_CDEV: /* don't know how to interpret the results */ SvREFCNT_dec(sv_buf); XSRETURN_IV(0); From 1bfc60453abc790ea0e09e1e560f60c16e4609b5 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 13:48:58 -0800 Subject: [PATCH 08/14] Rewrite how we generate and store mib types: - Use the same namespace that sys/sysctl.h uses. - For real types (e.g. string, int, long) use directly values from sys/sysctl.h. Generate bsd-sysctl.ph from sys/sysctl.h. - For structures that we know add more types in the same namespace and valuespace. - In _mib_info() prefer digital kind marker over format string. Parse the format string only for CTLTYPE_OPAQUE in search of known structures. While here: - Include bsd-sysctl.ph into Sysctl.pm during build, a TODO item. - Don't put copyright into generated files. - Add support for CTLTYPE_S32 and CTLTYPE_U32 --- Makefile.PL | 109 ++++++++++++++--------------------- Sysctl.pm | 29 +--------- Sysctl.xs | 159 +++++++++++++++++++++++----------------------------- TODO | 3 - t/01-get.t | 6 +- 5 files changed, 116 insertions(+), 190 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 813650d..db33f3c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -12,56 +12,38 @@ if ($Config{osname} ne 'freebsd') { my %define; my $maxlen = 0; +my $num = 16; # numbers below 16 are reserved for CTLTYPE_* while () { chomp; - next unless my ($key, $num, $str) = ($_ =~ /^(\S+)\t(\S+)\t(\S+)/); - if ($str eq 'auto') { - if ($key =~ /^[ST],(.*)/) { - $str = 'FMT_' . uc($1); - } - else { - die "$0: cannot resolve auto name from $key\n"; - } - } + next if /^#/ || /^\s*$/; + my $key = 'S,' . $_; + my $str = 'CTLTYPE_' . uc($_); $maxlen = length($str) if $maxlen < length($str); - $define{$key} = [$str, $num]; + $define{$key} = [$str, $num++]; } open my $out_h, '>', 'bsd-sysctl.h' or die "Cannot open C header for output: $!\n"; -open my $out_pl, '>', 'bsd-sysctl.pl' or die "Cannot open Perl header for output: $!\n"; - -my $years = (gmtime)[5]+1900; -$years = ($years == 2006) ? $years : "2006-$years"; - -print $out_h <', 'bsd-sysctl.ph' or die "Cannot open Perl header for output: $!\n"; # bootinfo.h header file not available on the AMD64 platform if (-r '/usr/include/machine/bootinfo.h') { print $out_h "#include \n"; } -print $out_pl <) { + next unless (/^#define (CTLTYPE_[A-Z0-9]+)\s+(0x[0-9a-f]+|[0-9]+)/); + printf $out_pl "use constant %-${maxlen}s => %s;\n", $1, $2; +} + +close $in_sys; for my $key (sort keys %define) { printf $out_h "#define %-${maxlen}s %2d\n", @{$define{$key}}; printf $out_pl "use constant %-${maxlen}s => %2d;\n", @{$define{$key}}; } -print $out_pl "\n1;\n"; - close $out_h; close $out_pl; @@ -74,50 +56,41 @@ WriteMakefile( PREREQ_PM => { 'XSLoader' => 0 }, + PM_FILTER => 'perl -pe "if (/^\#include (.+)$$/) { \ + open FILE, \\$$1 or \ + die \"open \\$$1\"; \ + while () { print; }; \ + close FILE; \ + next; \ + };"', clean => { - FILES => 'bsd-sysctl.h bsd-sysctl.pl', + FILES => 'bsd-sysctl.h bsd-sysctl.ph', }, MIN_PERL_VERSION => '5.8.0', ); __DATA__ # -# List of constant definitions. +# List of structures we are able to parse. # # This produces # -- bsd-sysctl.h (#defines for Sysctl.xs) -# -- bsd-sysctl.pl (use constants for Sysctl.pm) -# -# auto string definitions are derived from the first -# field, for instance, S,bootinfo => FMT_BOOTINFO -# (This eliminates a chance to introduce typos). -# _key numeric string - -A 1 FMT_A -I 2 FMT_INT -IU 3 FMT_UINT -L 4 FMT_LONG -LU 5 FMT_ULONG -N 6 FMT_N -S,bootinfo 7 auto -S,clockinfo 8 auto -S,devstat 9 auto -S,icmpstat 10 auto -S,igmpstat 11 auto -S,ipstat 12 auto -S,loadavg 13 auto -S,mbstat 14 auto -S,nfsrvstats 15 auto -S,nfsstats 16 auto -S,ntptimeval 17 auto -S,rip6stat 18 auto -S,tcpstat 19 auto -S,timeval 20 auto -S,udpstat 21 auto -S,vmtotal 22 auto -S,xinpcb 23 auto -S,xvfsconf 24 auto -Q 26 FMT_64 -QU 27 FMT_U64 -C 28 FMT_INT8 -CU 29 FMT_UINT8 +# -- bsd-sysctl.ph (use constants for Sysctl.pm) + +bootinfo +clockinfo +devstat +icmpstat +igmpstat +ipstat +loadavg +nfsrvstats +nfsstats +ntptimeval +rip6stat +tcpstat +timeval +udpstat +vmtotal +xinpcb +xvfsconf diff --git a/Sysctl.pm b/Sysctl.pm index bf7336f..cb2e8b1 100644 --- a/Sysctl.pm +++ b/Sysctl.pm @@ -15,34 +15,7 @@ use vars qw($VERSION @ISA %MIB_CACHE %MIB_SKIP @EXPORT_OK); $VERSION = '0.11'; @ISA = qw(Exporter); -use constant FMT_A => 1; -use constant FMT_INT => 2; -use constant FMT_UINT => 3; -use constant FMT_LONG => 4; -use constant FMT_ULONG => 5; -use constant FMT_N => 6; -use constant FMT_BOOTINFO => 7; -use constant FMT_CLOCKINFO => 8; -use constant FMT_DEVSTAT => 9; -use constant FMT_ICMPSTAT => 10; -use constant FMT_IGMPSTAT => 11; -use constant FMT_IPSTAT => 12; -use constant FMT_LOADAVG => 13; -use constant FMT_MBSTAT => 14; -use constant FMT_NFSRVSTATS => 15; -use constant FMT_NFSSTATS => 16; -use constant FMT_NTPTIMEVAL => 17; -use constant FMT_RIP6STAT => 18; -use constant FMT_TCPSTAT => 19; -use constant FMT_TIMEVAL => 20; -use constant FMT_UDPSTAT => 21; -use constant FMT_VMTOTAL => 22; -use constant FMT_XINPCB => 23; -use constant FMT_XVFSCONF => 24; -use constant FMT_64 => 26; -use constant FMT_U64 => 27; -use constant FMT_UINT8 => 28; -use constant FMT_INT8 => 29; +#include bsd-sysctl.ph push @EXPORT_OK, 'sysctl'; sub sysctl { diff --git a/Sysctl.xs b/Sysctl.xs index bcb793d..2e59300 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -191,6 +191,7 @@ _mib_info(const char *arg) char fmt[BUFSIZ]; size_t len = sizeof(fmt); int fmt_type; + u_int *kind = (u_int *)fmt; char *f = fmt + sizeof(int); char res[BUFSIZ]; char *resp = res; @@ -212,58 +213,33 @@ _mib_info(const char *arg) XSRETURN_UNDEF; } - switch (*f) { - case 'A': - fmt_type = FMT_A; - break; - case 'C': - ++f; - fmt_type = *f == 'U' ? FMT_UINT8 : FMT_INT8; - break; - case 'I': - ++f; - fmt_type = *f == 'U' ? FMT_UINT : FMT_INT; - break; - case 'L': - ++f; - fmt_type = *f == 'U' ? FMT_ULONG : FMT_LONG; - break; - case 'Q': - ++f; - fmt_type = *f == 'U' ? FMT_U64 : FMT_64; - break; - case 'S': { - if (strcmp(f,"S,clockinfo") == 0) { fmt_type = FMT_CLOCKINFO; } - else if (strcmp(f,"S,loadavg") == 0) { fmt_type = FMT_LOADAVG; } - else if (strcmp(f,"S,timeval") == 0) { fmt_type = FMT_TIMEVAL; } - else if (strcmp(f,"S,vmtotal") == 0) { fmt_type = FMT_VMTOTAL; } + /* + * Trust what digital kind marker says rather than string format. + * Parse the format only in search for the structs that we know. + */ + *kind &= CTLTYPE; + if (*kind == CTLTYPE_OPAQUE) { + if (strcmp(f,"S,clockinfo") == 0) { fmt_type = CTLTYPE_CLOCKINFO; } + else if (strcmp(f,"S,loadavg") == 0) { fmt_type = CTLTYPE_LOADAVG; } + else if (strcmp(f,"S,timeval") == 0) { fmt_type = CTLTYPE_TIMEVAL; } + else if (strcmp(f,"S,vmtotal") == 0) { fmt_type = CTLTYPE_VMTOTAL; } /* now the opaque OIDs */ - else if (strcmp(f,"S,bootinfo") == 0) { fmt_type = FMT_BOOTINFO; } - else if (strcmp(f,"S,devstat") == 0) { fmt_type = FMT_DEVSTAT; } - else if (strcmp(f,"S,icmpstat") == 0) { fmt_type = FMT_ICMPSTAT; } - else if (strcmp(f,"S,igmpstat") == 0) { fmt_type = FMT_IGMPSTAT; } - else if (strcmp(f,"S,ipstat") == 0) { fmt_type = FMT_IPSTAT; } - else if (strcmp(f,"S,mbstat") == 0) { fmt_type = FMT_MBSTAT; } /* removed in FreeBSD 10 */ - else if (strcmp(f,"S,nfsrvstats") == 0) { fmt_type = FMT_NFSRVSTATS; } - else if (strcmp(f,"S,nfsstats") == 0) { fmt_type = FMT_NFSSTATS; } - else if (strcmp(f,"S,ntptimeval") == 0) { fmt_type = FMT_NTPTIMEVAL; } - else if (strcmp(f,"S,rip6stat") == 0) { fmt_type = FMT_RIP6STAT; } - else if (strcmp(f,"S,tcpstat") == 0) { fmt_type = FMT_TCPSTAT; } - else if (strcmp(f,"S,udpstat") == 0) { fmt_type = FMT_UDPSTAT; } - else if (strcmp(f,"S,xinpcb") == 0) { fmt_type = FMT_XINPCB; } - else if (strcmp(f,"S,xvfsconf") == 0) { fmt_type = FMT_XVFSCONF; } - else { - /* bleah */ - } - break; - } - case 'N': - fmt_type = FMT_N; - break; - default: - fmt_type = FMT_A; - break; - } + else if (strcmp(f,"S,bootinfo") == 0) { fmt_type = CTLTYPE_BOOTINFO; } + else if (strcmp(f,"S,devstat") == 0) { fmt_type = CTLTYPE_DEVSTAT; } + else if (strcmp(f,"S,icmpstat") == 0) { fmt_type = CTLTYPE_ICMPSTAT; } + else if (strcmp(f,"S,igmpstat") == 0) { fmt_type = CTLTYPE_IGMPSTAT; } + else if (strcmp(f,"S,ipstat") == 0) { fmt_type = CTLTYPE_IPSTAT; } + else if (strcmp(f,"S,nfsrvstats") == 0) { fmt_type = CTLTYPE_NFSRVSTATS; } + else if (strcmp(f,"S,nfsstats") == 0) { fmt_type = CTLTYPE_NFSSTATS; } + else if (strcmp(f,"S,ntptimeval") == 0) { fmt_type = CTLTYPE_NTPTIMEVAL; } + else if (strcmp(f,"S,rip6stat") == 0) { fmt_type = CTLTYPE_RIP6STAT; } + else if (strcmp(f,"S,tcpstat") == 0) { fmt_type = CTLTYPE_TCPSTAT; } + else if (strcmp(f,"S,udpstat") == 0) { fmt_type = CTLTYPE_UDPSTAT; } + else if (strcmp(f,"S,xinpcb") == 0) { fmt_type = CTLTYPE_XINPCB; } + else if (strcmp(f,"S,xvfsconf") == 0) { fmt_type = CTLTYPE_XVFSCONF; } + else { fmt_type = CTLTYPE_OPAQUE; } + } else + fmt_type = *kind; /* first two bytes indicate format type */ memcpy(resp, (void *)&fmt_type, sizeof(int)); @@ -384,37 +360,43 @@ _mib_lookup(const char *arg) } switch(oid_fmt) { - case FMT_A: + case CTLTYPE_STRING: SvPOK_on(sv_buf); SvCUR_set(sv_buf, buflen); RETVAL = sv_buf; break; - case FMT_INT8: + case CTLTYPE_S8: DECODE(int8_t); break; - case FMT_UINT8: + case CTLTYPE_U8: DECODE(uint8_t); break; - case FMT_INT: + case CTLTYPE_INT: DECODE(int); break; - case FMT_UINT: + case CTLTYPE_UINT: DECODE(unsigned int); break; - case FMT_LONG: + case CTLTYPE_S32: + DECODE(int32_t); + break; + case CTLTYPE_U32: + DECODE(uint32_t); + break; + case CTLTYPE_LONG: DECODE(long); break; - case FMT_ULONG: + case CTLTYPE_ULONG: DECODE(unsigned long); break; - case FMT_64: + case CTLTYPE_S64: DECODE(int64_t); break; - case FMT_U64: + case CTLTYPE_U64: DECODE(uint64_t); break; #undef DECODE - case FMT_CLOCKINFO: { + case CTLTYPE_CLOCKINFO: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct clockinfo *inf = (struct clockinfo *)buf; RETVAL = newRV((SV *)c); @@ -424,7 +406,7 @@ _mib_lookup(const char *arg) hv_store(c, "stathz", 6, newSViv(inf->stathz), 0); break; } - case FMT_VMTOTAL: { + case CTLTYPE_VMTOTAL: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct vmtotal *inf = (struct vmtotal *)buf; RETVAL = newRV((SV *)c); @@ -444,7 +426,7 @@ _mib_lookup(const char *arg) hv_store(c, "pagefree", 8, newSViv(inf->t_free), 0); break; } - case FMT_LOADAVG: { + case CTLTYPE_LOADAVG: { AV *c = (AV *)sv_2mortal((SV *)newAV()); struct loadavg *inf = (struct loadavg *)buf; double scale = inf->fscale; @@ -455,7 +437,7 @@ _mib_lookup(const char *arg) av_store(c, 2, newSVnv((double)inf->ldavg[2]/scale)); break; } - case FMT_TIMEVAL: { + case CTLTYPE_TIMEVAL: { struct timeval *inf = (struct timeval *)buf; RETVAL = newSVnv( (double)inf->tv_sec + ((double)inf->tv_usec/1000000) @@ -463,7 +445,7 @@ _mib_lookup(const char *arg) break; } /* the remaining custom formats are for opaque mibs */ - case FMT_NTPTIMEVAL: { + case CTLTYPE_NTPTIMEVAL: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct ntptimeval *inf = (struct ntptimeval *)buf; RETVAL = newRV((SV *)c); @@ -475,7 +457,7 @@ _mib_lookup(const char *arg) hv_store(c, "timestate", 9, newSViv(inf->time_state), 0); break; } - case FMT_DEVSTAT: { + case CTLTYPE_DEVSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct devstat *inf = (struct devstat *)(buf + sizeof(buf)); RETVAL = newRV((SV *)c); @@ -521,7 +503,7 @@ _mib_lookup(const char *arg) } while (inf < (struct devstat *)(buf + buflen)); break; } - case FMT_XVFSCONF: { + case CTLTYPE_XVFSCONF: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct xvfsconf *inf = (struct xvfsconf *)buf; RETVAL = newRV((SV *)c); @@ -531,7 +513,7 @@ _mib_lookup(const char *arg) hv_store(c, "flags", 5, newSViv(inf->vfc_flags), 0); break; } - case FMT_ICMPSTAT: { + case CTLTYPE_ICMPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct icmpstat *inf = (struct icmpstat *)buf; RETVAL = newRV((SV *)c); @@ -547,7 +529,7 @@ _mib_lookup(const char *arg) hv_store(c, "noroute", 7, newSViv(inf->icps_noroute), 0); break; } - case FMT_IGMPSTAT: { + case CTLTYPE_IGMPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct igmpstat *inf = (struct igmpstat *)buf; RETVAL = newRV((SV *)c); @@ -573,7 +555,7 @@ _mib_lookup(const char *arg) hv_store(c, "sent", 4, newSVuv(inf->igps_snd_reports), 0); break; } - case FMT_TCPSTAT: { + case CTLTYPE_TCPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct tcpstat *inf = (struct tcpstat *)buf; RETVAL = newRV((SV *)c); @@ -667,7 +649,7 @@ _mib_lookup(const char *arg) hv_store(c, "sackscorebover", 14, newSVuv(inf->tcps_sack_sboverflow), 0); break; } - case FMT_UDPSTAT: { + case CTLTYPE_UDPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct udpstat *inf = (struct udpstat *)buf; RETVAL = newRV((SV *)c); @@ -685,7 +667,7 @@ _mib_lookup(const char *arg) hv_store(c, "noportmcast", 11, newSVuv(inf->udps_noportmcast), 0); break; } - case FMT_RIP6STAT: { + case CTLTYPE_RIP6STAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct rip6stat *inf = (struct rip6stat *)buf; RETVAL = newRV((SV *)c); @@ -700,7 +682,7 @@ _mib_lookup(const char *arg) break; } #ifdef BOOTINFO_VERSION - case FMT_BOOTINFO: { + case CTLTYPE_BOOTINFO: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct bootinfo *inf = (struct bootinfo *)buf; RETVAL = newRV((SV *)c); @@ -724,11 +706,12 @@ _mib_lookup(const char *arg) break; } #endif - case FMT_N: - case FMT_IPSTAT: - case FMT_NFSRVSTATS: - case FMT_NFSSTATS: - case FMT_XINPCB: + case CTLTYPE_NODE: + case CTLTYPE_IPSTAT: + case CTLTYPE_NFSRVSTATS: + case CTLTYPE_NFSSTATS: + case CTLTYPE_XINPCB: + case CTLTYPE_OPAQUE: /* don't know how to interpret the results */ SvREFCNT_dec(sv_buf); XSRETURN_IV(0); @@ -740,7 +723,7 @@ _mib_lookup(const char *arg) break; } - if (oid_fmt != FMT_A) { + if (oid_fmt != CTLTYPE_STRING) { SvREFCNT_dec(sv_buf); } @@ -793,12 +776,12 @@ _mib_set(const char *arg, const char *value) oid_data += sizeof(int); switch(oid_fmt) { - case FMT_A: + case CTLTYPE_STRING: newval = (void *)value; newsize = strlen(value); break; - case FMT_INT: + case CTLTYPE_INT: intval = (int)strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid integer: '%s'", value); @@ -808,7 +791,7 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(intval); break; - case FMT_UINT: + case CTLTYPE_UINT: uintval = (unsigned int)strtoul(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid unsigned integer: '%s'", value); @@ -818,7 +801,7 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(uintval); break; - case FMT_INT8: + case CTLTYPE_S8: int8val = (int8_t)strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid integer: '%s'", value); @@ -828,7 +811,7 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(int8val); break; - case FMT_UINT8: + case CTLTYPE_U8: uint8val = (uint8_t)strtoul(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid unsigned integer: '%s'", value); @@ -838,7 +821,7 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(uint8val); break; - case FMT_LONG: + case CTLTYPE_LONG: longval = strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid long integer: '%s'", value); @@ -848,7 +831,7 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(longval); break; - case FMT_ULONG: + case CTLTYPE_ULONG: ulongval = strtoul(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid unsigned long integer: '%s'", value); @@ -857,7 +840,7 @@ _mib_set(const char *arg, const char *value) newval = &ulongval; newsize = sizeof(ulongval); break; - case FMT_64: + case CTLTYPE_S64: llval = strtoll(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0' || (llval == 0 && errno == EINVAL)) { @@ -876,7 +859,7 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(int64val); break; - case FMT_U64: + case CTLTYPE_U64: ullval = strtoull(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0' || (ullval == 0 && errno == EINVAL)) { diff --git a/TODO b/TODO index 18b133a..6db07f5 100644 --- a/TODO +++ b/TODO @@ -11,9 +11,6 @@ TODO list for BSD::Sysctl pagefree(), representing vm.vmtotal's "number of vm pages free" value. -7. Deal with bsd-sysctl.pl in a cleverer way (insert the -contents into Sysctl.pm when copying to blib/lib. - 8. Add Makefile rules to deal with changes to mibfmt.map 9. eg/mib_scan.pl reports that a number of more obscure diff --git a/t/01-get.t b/t/01-get.t index fa3a032..42f0fe3 100644 --- a/t/01-get.t +++ b/t/01-get.t @@ -15,7 +15,7 @@ ok(BSD::Sysctl::_mib_exists('kern.maxproc'), 'mib exists'); ok($sysctl_info, 'mib lookup kern.ostype'); my ($fmt, @oid) = unpack( 'i i/i', $sysctl_info ); - is($fmt, BSD::Sysctl::FMT_A, '... display format type A'); + is($fmt, BSD::Sysctl::CTLTYPE_STRING, '... display format type STRING'); is_deeply(\@oid, [1, 1], '... oid 1.1'); } @@ -24,7 +24,7 @@ ok(BSD::Sysctl::_mib_exists('kern.maxproc'), 'mib exists'); ok($sysctl_info, 'mib lookup kern.ipc.maxsockbuf'); my ($fmt, @oid) = unpack( 'i i/i', $sysctl_info ); - is($fmt, BSD::Sysctl::FMT_ULONG, '... display format type ULONG'); + is($fmt, BSD::Sysctl::CTLTYPE_ULONG, '... display format type ULONG'); is_deeply(\@oid, [1, 30, 1], '... oid 1.30.1'); } @@ -33,7 +33,7 @@ ok(BSD::Sysctl::_mib_exists('kern.maxproc'), 'mib exists'); ok($sysctl_info, 'mib lookup kern.geom.confxml'); my ($fmt, @oid) = unpack( 'i i/i', $sysctl_info ); - is($fmt, BSD::Sysctl::FMT_A, '... display format type A'); + is($fmt, BSD::Sysctl::CTLTYPE_STRING, '... display format type STRING'); my $confxml = sysctl('kern.geom.confxml'); ok($confxml, 'value of "kern.geom.confxml" is defined'); like($confxml, qr(^\s*<([^>]+)>.*\s*$)m, 'value of "kern.geom.confxml" is XML'); From d21690cdb866f5678e4d81b1ce756fad4c021418 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 14:28:14 -0800 Subject: [PATCH 09/14] For ASCII string values do not leak NULL terminating character, which is a C thing, into perl. Add a test. --- Sysctl.xs | 2 ++ t/01-get.t | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Sysctl.xs b/Sysctl.xs index 2e59300..68ab6d4 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -361,6 +361,8 @@ _mib_lookup(const char *arg) switch(oid_fmt) { case CTLTYPE_STRING: + if (buf[buflen - 1] == '\0') /* Shall always be true. */ + buflen--; SvPOK_on(sv_buf); SvCUR_set(sv_buf, buflen); RETVAL = sv_buf; diff --git a/t/01-get.t b/t/01-get.t index 42f0fe3..a22e05f 100644 --- a/t/01-get.t +++ b/t/01-get.t @@ -4,7 +4,7 @@ # Copyright (C) 2006, 2009 David Landgren use strict; -use Test::More tests => 20; +use Test::More tests => 21; use BSD::Sysctl qw(sysctl sysctl_exists); @@ -19,6 +19,11 @@ ok(BSD::Sysctl::_mib_exists('kern.maxproc'), 'mib exists'); is_deeply(\@oid, [1, 1], '... oid 1.1'); } +{ + my $ostype = sysctl('kern.ostype'); + is($ostype, "FreeBSD"); +} + { my $sysctl_info = BSD::Sysctl::_mib_info('kern.ipc.maxsockbuf'); ok($sysctl_info, 'mib lookup kern.ipc.maxsockbuf'); From b1ffd7a5b9092cc395dd3fdffd01a4c52d8569ec Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 15:05:44 -0800 Subject: [PATCH 10/14] Allow to retrieve unknown structures. Add test that fetches UMA stats and checks that header looks sane. --- Sysctl.xs | 4 ++-- t/01-get.t | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Sysctl.xs b/Sysctl.xs index 68ab6d4..9ab4d76 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -363,6 +363,7 @@ _mib_lookup(const char *arg) case CTLTYPE_STRING: if (buf[buflen - 1] == '\0') /* Shall always be true. */ buflen--; + case CTLTYPE_OPAQUE: SvPOK_on(sv_buf); SvCUR_set(sv_buf, buflen); RETVAL = sv_buf; @@ -713,7 +714,6 @@ _mib_lookup(const char *arg) case CTLTYPE_NFSRVSTATS: case CTLTYPE_NFSSTATS: case CTLTYPE_XINPCB: - case CTLTYPE_OPAQUE: /* don't know how to interpret the results */ SvREFCNT_dec(sv_buf); XSRETURN_IV(0); @@ -725,7 +725,7 @@ _mib_lookup(const char *arg) break; } - if (oid_fmt != CTLTYPE_STRING) { + if (oid_fmt != CTLTYPE_STRING && oid_fmt != CTLTYPE_OPAQUE) { SvREFCNT_dec(sv_buf); } diff --git a/t/01-get.t b/t/01-get.t index a22e05f..321a520 100644 --- a/t/01-get.t +++ b/t/01-get.t @@ -4,7 +4,7 @@ # Copyright (C) 2006, 2009 David Landgren use strict; -use Test::More tests => 21; +use Test::More tests => 29; use BSD::Sysctl qw(sysctl sysctl_exists); @@ -44,6 +44,25 @@ ok(BSD::Sysctl::_mib_exists('kern.maxproc'), 'mib exists'); like($confxml, qr(^\s*<([^>]+)>.*\s*$)m, 'value of "kern.geom.confxml" is XML'); } +{ + my $sysctl_info = BSD::Sysctl::_mib_info('vm.zone_stats'); + ok($sysctl_info, 'mib lookup vm.zone_stats'); + my ($fmt, @oid) = unpack( 'i i/i', $sysctl_info ); + + is($fmt, BSD::Sysctl::CTLTYPE_OPAQUE, '... display format type OPAQUE'); + my $zst = sysctl('vm.zone_stats'); + ok($zst, 'value of "vm.zone_stats" is defined'); + my $maxid = sysctl('kern.smp.maxid'); + cmp_ok($maxid, '>', 1, "max CPU id is meaningful"); + + # struct uma_stream_header + my ($version, $maxcpus, $count, $pad) = unpack('L4', $zst); + is ($version, 1, 'uma stream version'); + is ($maxcpus, $maxid + 1, 'uma max cpus'); + cmp_ok($count, '>', 10, 'uma keg/zone count'); + is ($pad, 0, 'uma pad'); +} + { my $sysctl_info = BSD::Sysctl::_mib_info('net.inet.ip.portrange.last'); my $portrange_last = BSD::Sysctl::_mib_lookup('net.inet.ip.portrange.last'); @@ -68,5 +87,5 @@ ok(!sysctl_exists('kern.maxbananas'), 'kern.maxbananas does not exist'); cmp_ok($nr_files, '>', 0, "got the number of open files again (now $nr_files)"); } -is(scalar(keys %BSD::Sysctl::MIB_CACHE), 6, 'cached mib count') +is(scalar(keys %BSD::Sysctl::MIB_CACHE), 8, 'cached mib count') or do { diag("cached: [$_]") for sort keys %BSD::Sysctl::MIB_CACHE }; From f3d70687c9078f5676c2af96292afc78cff9e260 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 18:02:26 -0800 Subject: [PATCH 11/14] Create ignore.txt instead of MANIFEST.SKIP. This is what modern module-starter does. While here create .gitignore. --- .gitignore | 21 +++++++++++++++++++++ MANIFEST | 2 -- MANIFEST.SKIP | 4 ---- ignore.txt | 21 +++++++++++++++++++++ 4 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 .gitignore delete mode 100644 MANIFEST.SKIP create mode 100644 ignore.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98d9301 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +Makefile +Makefile.old +Build +Build.bat +META.* +MYMETA.* +.build/ +_build/ +cover_db/ +blib/ +inc/ +.lwpcookies +.last_cover_stats +nytprof.out +pod2htm*.tmp +pm_to_blib +Sysctl.bs +Sysctl.c +Sysctl.o +bsd-sysctl.h +bsd-sysctl.ph diff --git a/MANIFEST b/MANIFEST index 315f49b..838728c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,8 +1,6 @@ Changes -LICENSE Makefile.PL MANIFEST -MANIFEST.SKIP META.yml Module meta-data (added by MakeMaker) README Sysctl.pm diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP deleted file mode 100644 index f40e88d..0000000 --- a/MANIFEST.SKIP +++ /dev/null @@ -1,4 +0,0 @@ -\B\.svn\b -\B\.git\b -bsd-sysctl.h -bsd-sysctl.pl diff --git a/ignore.txt b/ignore.txt new file mode 100644 index 0000000..98d9301 --- /dev/null +++ b/ignore.txt @@ -0,0 +1,21 @@ +Makefile +Makefile.old +Build +Build.bat +META.* +MYMETA.* +.build/ +_build/ +cover_db/ +blib/ +inc/ +.lwpcookies +.last_cover_stats +nytprof.out +pod2htm*.tmp +pm_to_blib +Sysctl.bs +Sysctl.c +Sysctl.o +bsd-sysctl.h +bsd-sysctl.ph From eaedcb212d004fabaf4a3a6a399a45f57216ffe9 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Thu, 25 Feb 2021 18:06:45 -0800 Subject: [PATCH 12/14] Let's call this 0.12.1 --- README | 2 +- Sysctl.pm | 6 +++--- Sysctl.xs | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README b/README index d456807..54829c4 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This file is the README for BSD::Sysctl version 0.11 +This file is the README for BSD::Sysctl INSTALLATION diff --git a/Sysctl.pm b/Sysctl.pm index cb2e8b1..041c8d3 100644 --- a/Sysctl.pm +++ b/Sysctl.pm @@ -1,5 +1,6 @@ # BSD::Sysctl.pm - Access BSD sysctl(8) information directly # +# Copyright (C) 2021 Gleb Smirnoff, all rights reserved. # Copyright (C) 2006-2014 David Landgren, all rights reserved. package BSD::Sysctl; @@ -12,7 +13,7 @@ use XSLoader; use vars qw($VERSION @ISA %MIB_CACHE %MIB_SKIP @EXPORT_OK); -$VERSION = '0.11'; +$VERSION = '0.12'; @ISA = qw(Exporter); #include bsd-sysctl.ph @@ -94,8 +95,7 @@ BSD::Sysctl - Manipulate kernel sysctl variables on BSD-like systems =head1 VERSION -This document describes version 0.11 of BSD::Sysctl, released -2014-01-22. +This document describes version 0.12 of BSD::Sysctl =head1 SYNOPSIS diff --git a/Sysctl.xs b/Sysctl.xs index 9ab4d76..9bf5aaa 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -1,5 +1,6 @@ /* Sysctl.xs -- XS component of BSD-Sysctl * + * Copyright (C) 2021 Gleb Smirnoff * Copyright (C) 2006-2014 David Landgren */ From 27b7820a11ec757ff16badaa80a07599ec49d749 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Fri, 5 Nov 2021 11:03:59 -0700 Subject: [PATCH 13/14] Allow to set CTLTYPE_S32 and CTLTYPE_U32. This should have been done in 1bfc604. --- Sysctl.xs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Sysctl.xs b/Sysctl.xs index 9bf5aaa..f049f0d 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -750,6 +750,8 @@ _mib_set(const char *arg, const char *value) int oid_len; int intval; unsigned int uintval; + int32_t int32val; + uint32_t uint32val; long longval; unsigned long ulongval; void *newval = 0; @@ -804,6 +806,26 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(uintval); break; + case CTLTYPE_S32: + int32val = (int32_t)strtol(value, &endconvptr, 0); + if (endconvptr == value || *endconvptr != '\0') { + warn("invalid 32-bit integer: '%s'", value); + XSRETURN_UNDEF; + } + newval = &int32val; + newsize = sizeof(int32val); + break; + + case CTLTYPE_U32: + uint32val = (uint32_t)strtoul(value, &endconvptr, 0); + if (endconvptr == value || *endconvptr != '\0') { + warn("invalid unsigned 32-bit integer: '%s'", value); + XSRETURN_UNDEF; + } + newval = &uint32val; + newsize = sizeof(uint32val); + break; + case CTLTYPE_S8: int8val = (int8_t)strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { From 1cf04f4aeae356cf09086e6de2fbca60111e8b71 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Tue, 20 Sep 2022 14:32:30 -0700 Subject: [PATCH 14/14] Retire the dead code that read the bootinfo sysctl. The sysctl was removed in c29ba5fe6e3aa26e4fa68b1efa16703b55ac8c05 in 2006. Recently the dead code started to fail to compile. NB: very likely many (or most) of the recognized structures defined in the __DATA__ part of the Makefile.PL are also a dead code. --- Makefile.PL | 6 ------ Sysctl.xs | 26 -------------------------- eg/sizeof.c | 2 -- 3 files changed, 34 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index db33f3c..6462481 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -25,11 +25,6 @@ while () { open my $out_h, '>', 'bsd-sysctl.h' or die "Cannot open C header for output: $!\n"; open my $out_pl, '>', 'bsd-sysctl.ph' or die "Cannot open Perl header for output: $!\n"; -# bootinfo.h header file not available on the AMD64 platform -if (-r '/usr/include/machine/bootinfo.h') { - print $out_h "#include \n"; -} - open my $in_sys, '<', '/usr/include/sys/sysctl.h' or die "Cannot open sys/sysctl.h: $!\n"; while (<$in_sys>) { @@ -77,7 +72,6 @@ __DATA__ # -- bsd-sysctl.h (#defines for Sysctl.xs) # -- bsd-sysctl.ph (use constants for Sysctl.pm) -bootinfo clockinfo devstat icmpstat diff --git a/Sysctl.xs b/Sysctl.xs index f049f0d..236be0e 100644 --- a/Sysctl.xs +++ b/Sysctl.xs @@ -225,7 +225,6 @@ _mib_info(const char *arg) else if (strcmp(f,"S,timeval") == 0) { fmt_type = CTLTYPE_TIMEVAL; } else if (strcmp(f,"S,vmtotal") == 0) { fmt_type = CTLTYPE_VMTOTAL; } /* now the opaque OIDs */ - else if (strcmp(f,"S,bootinfo") == 0) { fmt_type = CTLTYPE_BOOTINFO; } else if (strcmp(f,"S,devstat") == 0) { fmt_type = CTLTYPE_DEVSTAT; } else if (strcmp(f,"S,icmpstat") == 0) { fmt_type = CTLTYPE_ICMPSTAT; } else if (strcmp(f,"S,igmpstat") == 0) { fmt_type = CTLTYPE_IGMPSTAT; } @@ -685,31 +684,6 @@ _mib_lookup(const char *arg) hv_store(c, "outpackets", 10, newSVnv(inf->rip6s_opackets), 0); break; } -#ifdef BOOTINFO_VERSION - case CTLTYPE_BOOTINFO: { - HV *c = (HV *)sv_2mortal((SV *)newHV()); - struct bootinfo *inf = (struct bootinfo *)buf; - RETVAL = newRV((SV *)c); - /* ignore the following fields for the time being: - * bi_bios_geom - * bi_kernelname - * bi_nfs_diskless - * bi_symtab - * bi_esymtab - */ - hv_store(c, "version", 7, newSVuv(inf->bi_version), 0); - /* don't know if any IA64 fields are useful, - * (as per /usr/src/sys/ia64/include/bootinfo.h) - */ - hv_store(c, "biosused", 8, newSVuv(inf->bi_n_bios_used), 0); - hv_store(c, "size", 4, newSVuv(inf->bi_size), 0); - hv_store(c, "msizevalid", 10, newSVuv(inf->bi_memsizes_valid), 0); - hv_store(c, "biosdev", 7, newSVuv(inf->bi_bios_dev), 0); - hv_store(c, "basemem", 7, newSVuv(inf->bi_basemem), 0); - hv_store(c, "extmem", 6, newSVuv(inf->bi_extmem), 0); - break; - } -#endif case CTLTYPE_NODE: case CTLTYPE_IPSTAT: case CTLTYPE_NFSRVSTATS: diff --git a/eg/sizeof.c b/eg/sizeof.c index 2cbda92..ab0dd45 100644 --- a/eg/sizeof.c +++ b/eg/sizeof.c @@ -24,7 +24,6 @@ #include /* struct xinpcb */ #include /* struct xinpcb */ #include /* struct rip6stat */ -#include /* struct bootinfo */ int main(int argc, char **argv) { @@ -40,6 +39,5 @@ main(int argc, char **argv) { printf( "sizeof(struct udpstat) = %d\n", sizeof(struct udpstat) ); printf( "sizeof(struct xinpcb) = %d\n", sizeof(struct xinpcb) ); printf( "sizeof(struct rip6stat) = %d\n", sizeof(struct rip6stat) ); - printf( "sizeof(struct bootinfo) = %d\n", sizeof(struct bootinfo) ); return 0; }