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/Makefile.PL b/Makefile.PL index 2f6a848..6462481 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -12,56 +12,33 @@ 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"; +open my $out_pl, '>', 'bsd-sysctl.ph' or die "Cannot open Perl header for output: $!\n"; -my $years = (gmtime)[5]+1900; -$years = ($years == 2006) ? $years : "2006-$years"; +open my $in_sys, '<', '/usr/include/sys/sysctl.h' or die "Cannot open sys/sysctl.h: $!\n"; -print $out_h <\n"; +while (<$in_sys>) { + 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; } -print $out_pl < %2d;\n", @{$define{$key}}; } -print $out_pl "\n1;\n"; - close $out_h; close $out_pl; @@ -74,49 +51,40 @@ 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 -T,struct_cdev 25 auto -Q 26 FMT_64 -QU 27 FMT_U64 +# -- bsd-sysctl.ph (use constants for Sysctl.pm) + +clockinfo +devstat +icmpstat +igmpstat +ipstat +loadavg +nfsrvstats +nfsstats +ntptimeval +rip6stat +tcpstat +timeval +udpstat +vmtotal +xinpcb +xvfsconf 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 3394214..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,36 +13,10 @@ use XSLoader; use vars qw($VERSION @ISA %MIB_CACHE %MIB_SKIP @EXPORT_OK); -$VERSION = '0.11'; +$VERSION = '0.12'; @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_STRUCT_CDEV => 25; -use constant FMT_64 => 26; -use constant FMT_U64 => 27; +#include bsd-sysctl.ph push @EXPORT_OK, 'sysctl'; sub sysctl { @@ -85,10 +60,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; } @@ -105,7 +81,9 @@ sub value { sub reset { my $self = shift; - delete $self->{_ctx}; + delete $self->{_next}; + delete $self->{_name}; + delete $self->{_len0}; return $self; } @@ -117,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 @@ -260,6 +237,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 @@ -349,7 +331,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 @@ -359,12 +341,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 54fae78..236be0e 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 */ @@ -7,21 +8,20 @@ #include "perl.h" #include "XSUB.h" -/* define _FreeBSD_version where applicable */ -#if __FreeBSD__ >= 2 -#include -#endif - #include -#include +#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 */ -#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) */ @@ -31,9 +31,6 @@ #include #include #include -#if __FreeBSD_version < 500000 -#include /* struct tcpstat prerequisite */ -#endif #include /* struct icmpstat */ #include /* struct igmpstat */ @@ -48,78 +45,112 @@ #include #include "bsd-sysctl.h" -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 { +void +_iterator_first(HV *self) +{ + SV **headp; + int name[CTL_MAXNAME]; + size_t len; + headp = hv_fetch(self, "head", 4, 0); - if (!(headp && *headp)) { - croak( "failed to get some head in _init_iterator()\n" ); - } + if (headp == NULL || *headp == NULL) + croak( "failed to fetch head in _iterator_first()\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) - ); + /* 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; - } - cmplen = qoidlen; - qoidlen += 2; - } - else { - /* begin at the beginning */ - qoid[2] = 1; - cmplen = 0; - qoidlen = 3; + next = (int *) SvPV(nextp, next_len); + next_len /= sizeof(int); + + namep = hv_delete(self, "_name", 5, 0); + if (namep == NULL) + return 0; + + name1[0] = CTL_SYSCTL; + 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; + + 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"); } - 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; + 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); + + name1[0] = CTL_SYSCTL; + name1[1] = CTL_SYSCTL_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"); } - } - return 1; + + /* 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 +158,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)) { + if (_iterator_next(self) == 0) 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); - + + namep = hv_fetch(self, "_name", 5, 0); + SvREFCNT_inc(*namep); + RETVAL = *namep; OUTPUT: RETVAL @@ -210,6 +192,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; @@ -225,69 +208,38 @@ _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; } - switch (*f) { - case 'A': - fmt_type = FMT_A; - 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 'T': { - if (strcmp(f,"T,struct cdev *") == 0) { - fmt_type = FMT_STRUCT_CDEV; - } - else { - /* bleah */ - } - break; - } - case 'N': - fmt_type = FMT_N; - break; - default: - fmt_type = FMT_A; - break; - } + 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)); @@ -339,6 +291,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: @@ -393,102 +360,46 @@ _mib_lookup(const char *arg) } switch(oid_fmt) { - case FMT_A: + 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; 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); - } + case CTLTYPE_S8: + DECODE(int8_t); 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); - } + case CTLTYPE_U8: + DECODE(uint8_t); 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); - } + case CTLTYPE_INT: + DECODE(int); 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); - } + case CTLTYPE_UINT: + DECODE(unsigned int); 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); - } + case CTLTYPE_S32: + DECODE(int32_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); - } + case CTLTYPE_U32: + DECODE(uint32_t); + break; + case CTLTYPE_LONG: + DECODE(long); break; - case FMT_CLOCKINFO: { + case CTLTYPE_ULONG: + DECODE(unsigned long); + break; + case CTLTYPE_S64: + DECODE(int64_t); + break; + case CTLTYPE_U64: + DECODE(uint64_t); + break; +#undef DECODE + case CTLTYPE_CLOCKINFO: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct clockinfo *inf = (struct clockinfo *)buf; RETVAL = newRV((SV *)c); @@ -498,7 +409,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); @@ -518,7 +429,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; @@ -529,7 +440,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) @@ -537,39 +448,7 @@ _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: { + case CTLTYPE_NTPTIMEVAL: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct ntptimeval *inf = (struct ntptimeval *)buf; RETVAL = newRV((SV *)c); @@ -581,31 +460,53 @@ _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; + 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); -#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); -#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); -#endif - break; - } -#if __FreeBSD_version >= 500000 - case FMT_XVFSCONF: { + 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); + 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); + ++p; + ++inf; + } while (inf < (struct devstat *)(buf + buflen)); + break; + } + case CTLTYPE_XVFSCONF: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct xvfsconf *inf = (struct xvfsconf *)buf; RETVAL = newRV((SV *)c); @@ -615,8 +516,7 @@ _mib_lookup(const char *arg) hv_store(c, "flags", 5, newSViv(inf->vfc_flags), 0); break; } -#endif - case FMT_ICMPSTAT: { + case CTLTYPE_ICMPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct icmpstat *inf = (struct icmpstat *)buf; RETVAL = newRV((SV *)c); @@ -632,21 +532,10 @@ _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); -#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); @@ -667,10 +556,9 @@ _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: { + case CTLTYPE_TCPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct tcpstat *inf = (struct tcpstat *)buf; RETVAL = newRV((SV *)c); @@ -751,26 +639,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); @@ -778,10 +650,9 @@ _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: { + case CTLTYPE_UDPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct udpstat *inf = (struct udpstat *)buf; RETVAL = newRV((SV *)c); @@ -799,7 +670,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); @@ -813,46 +684,11 @@ _mib_lookup(const char *arg) hv_store(c, "outpackets", 10, newSVnv(inf->rip6s_opackets), 0); break; } -#ifdef BOOTINFO_VERSION - case FMT_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) - */ -#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 - case FMT_N: - case FMT_IPSTAT: - case FMT_NFSRVSTATS: - case FMT_NFSSTATS: - case FMT_XINPCB: - case FMT_STRUCT_CDEV: + case CTLTYPE_NODE: + case CTLTYPE_IPSTAT: + case CTLTYPE_NFSRVSTATS: + case CTLTYPE_NFSSTATS: + case CTLTYPE_XINPCB: /* don't know how to interpret the results */ SvREFCNT_dec(sv_buf); XSRETURN_IV(0); @@ -864,7 +700,7 @@ _mib_lookup(const char *arg) break; } - if (oid_fmt != FMT_A) { + if (oid_fmt != CTLTYPE_STRING && oid_fmt != CTLTYPE_OPAQUE) { SvREFCNT_dec(sv_buf); } @@ -878,10 +714,18 @@ _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; + int8_t int8val; + uint8_t uint8val; int oid_fmt; int oid_len; int intval; unsigned int uintval; + int32_t int32val; + uint32_t uint32val; long longval; unsigned long ulongval; void *newval = 0; @@ -911,12 +755,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); @@ -926,7 +770,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); @@ -936,7 +780,47 @@ _mib_set(const char *arg, const char *value) newsize = sizeof(uintval); break; - case FMT_LONG: + 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') { + warn("invalid integer: '%s'", value); + XSRETURN_UNDEF; + } + newval = &int8val; + newsize = sizeof(int8val); + break; + + case CTLTYPE_U8: + 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 CTLTYPE_LONG: longval = strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid long integer: '%s'", value); @@ -946,7 +830,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); @@ -955,6 +839,41 @@ _mib_set(const char *arg, const char *value) newval = &ulongval; newsize = sizeof(ulongval); break; + case CTLTYPE_S64: + 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 CTLTYPE_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..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 @@ -24,5 +21,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. diff --git a/eg/sizeof.c b/eg/sizeof.c index a6ae45a..ab0dd45 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,14 @@ #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,8 +37,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/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 diff --git a/t/01-get.t b/t/01-get.t index a37082f..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 => 23; +use Test::More tests => 29; use BSD::Sysctl qw(sysctl sysctl_exists); @@ -15,18 +15,13 @@ 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'); } { - 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 ); - - # 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 $ostype = sysctl('kern.ostype'); + is($ostype, "FreeBSD"); } { @@ -34,16 +29,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 ); - # 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::CTLTYPE_ULONG, '... display format type ULONG'); is_deeply(\@oid, [1, 30, 1], '... oid 1.30.1'); } @@ -52,12 +38,31 @@ 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'); } +{ + 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'); @@ -82,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), 7, '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 }; 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;