/* Sysctl.xs -- XS component of BSD-Sysctl * * Copyright (C) 2006-2009 David Landgren */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" /* define _FreeBSD_version where applicable */ #if __FreeBSD__ >= 2 #include #endif #include #include #include #include /* struct clockinfo */ #include /* struct vmtotal */ #include /* struct loadavg */ #include /* struct mbstat (opaque mib) */ #include /* struct ntptimeval (opaque mib) */ #include /* struct devstat (opaque mib) */ #include /* struct xvfsconf (opaque mib) */ /* prerequisites for TCP/IP-related structs */ #include #include #include #include #if __FreeBSD_version < 500000 #include /* struct tcpstat prerequisite */ #endif #include /* struct icmpstat */ #include /* struct igmpstat */ #include /* struct tcpstat */ /* prerequisites for struct udpstat */ #include #include #include #include #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 { 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; } MODULE = BSD::Sysctl PACKAGE = BSD::Sysctl 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; 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 %d %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); OUTPUT: RETVAL int _mib_exists(const char *arg) CODE: int mib[CTL_MAXNAME]; size_t miblen = (sizeof(mib)/sizeof(mib[0])); RETVAL = (sysctlnametomib(arg, mib, &miblen) != -1); OUTPUT: RETVAL SV * _mib_info(const char *arg) INIT: int mib[CTL_MAXNAME+2]; size_t miblen; int nr_octets; int size; char fmt[BUFSIZ]; size_t len = sizeof(fmt); int fmt_type; char *f = fmt + sizeof(int); char res[BUFSIZ]; char *resp = res; SV *cache; SV **store; CODE: /* see if the mib exists */ miblen = (sizeof(mib) / sizeof(mib[0])) - 2; if (sysctlnametomib(arg, mib+2, &miblen) == -1) { XSRETURN_UNDEF; } nr_octets = miblen; /* determine how to format the results */ mib[0] = 0; mib[1] = 4; 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; } /* 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; } 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; } /* first two bytes indicate format type */ memcpy(resp, (void *)&fmt_type, sizeof(int)); resp += sizeof(int); len = sizeof(int); /* reuse len to measure cached info */ /* next two bytes indicate the length of the oid */ memcpy(resp, (void *)&nr_octets, sizeof(int)); resp += sizeof(int); len += sizeof(int); /* following bytes are the numeric oid (step past 0, 4) */ size = (nr_octets) * sizeof(int); memcpy(resp, (void *)(mib+2), size); len += size; cache = newSVpvn(res, len); store = hv_store( get_hv("BSD::Sysctl::MIB_CACHE", 0), arg, strlen(arg), cache, 0 ); SvREFCNT_inc(cache); RETVAL = cache; OUTPUT: RETVAL SV * _mib_description(const char *arg) INIT: int mib[CTL_MAXNAME]; size_t miblen = (sizeof(mib)/sizeof(mib[0])); int qmib[CTL_MAXNAME+2]; char desc[BUFSIZ]; size_t len = sizeof(desc); CODE: /* see if the mib exists */ if (sysctlnametomib(arg, mib, &miblen) == -1) { XSRETURN_UNDEF; } /* fetch the description */ qmib[0] = 0; qmib[1] = 5; memcpy(qmib+2, mib, miblen * sizeof(int)); if (sysctl(qmib, miblen+2, desc, &len, NULL, 0) == -1) { XSRETURN_UNDEF; } RETVAL = newSVpvn(desc, len-1); OUTPUT: RETVAL SV * _mib_lookup(const char *arg) INIT: HV *cache; SV **oidp; SV *oid; int mib[CTL_MAXNAME]; size_t miblen = (sizeof(mib)/sizeof(mib[0])); char *oid_data; int oid_fmt; int oid_len; SV *sv_buf; char *buf; size_t buflen = sizeof(buf); CODE: /* see if the mib exists */ cache = get_hv("BSD::Sysctl::MIB_CACHE", 0); if(oidp = hv_fetch(cache, arg, strlen(arg), 0)) { oid = *oidp; } else { /* else use the cache * How do you call an XS sub from C? */ warn("uncached mib: %s\n", arg); XSRETURN_UNDEF; } oid_data = SvPVX(oid); oid_fmt = (int)(*oid_data); oid_data += sizeof(int); oid_len = (int)(*oid_data); oid_data += sizeof(int); memcpy(mib, oid_data, oid_len * sizeof(int)); /* determine buffer size */ if (sysctl(mib, oid_len, NULL, &buflen, NULL, 0) == -1) { XSRETURN_UNDEF; } if (0 == buflen) { XSRETURN_UNDEF; } sv_buf = newSV(buflen); buf = SvPVX(sv_buf); if (sysctl(mib, oid_len, buf, &buflen, NULL, 0) == -1) { XSRETURN_UNDEF; } switch(oid_fmt) { case FMT_A: 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); } 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); } 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); } 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); } 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); } 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); } break; case FMT_CLOCKINFO: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct clockinfo *inf = (struct clockinfo *)buf; RETVAL = newRV((SV *)c); hv_store(c, "hz", 2, newSViv(inf->hz), 0); hv_store(c, "tick", 4, newSViv(inf->tick), 0); hv_store(c, "profhz", 6, newSViv(inf->profhz), 0); hv_store(c, "stathz", 6, newSViv(inf->stathz), 0); break; } case FMT_VMTOTAL: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct vmtotal *inf = (struct vmtotal *)buf; RETVAL = newRV((SV *)c); hv_store(c, "runqueue", 8, newSViv(inf->t_rq), 0); hv_store(c, "diskwait", 8, newSViv(inf->t_dw), 0); hv_store(c, "pagewait", 8, newSViv(inf->t_pw), 0); hv_store(c, "sleeping", 8, newSViv(inf->t_sl), 0); hv_store(c, "pagesize", 8, newSViv(getpagesize()), 0); hv_store(c, "vmtotal", 7, newSVuv(inf->t_vm), 0); hv_store(c, "vmactive", 8, newSVuv(inf->t_avm), 0); hv_store(c, "realtotal", 9, newSVuv(inf->t_rm), 0); hv_store(c, "realactive", 10, newSVuv(inf->t_arm), 0); hv_store(c, "vmshared", 8, newSVuv(inf->t_vmshr), 0); hv_store(c, "vmsharedactive", 14, newSVuv(inf->t_avmshr), 0); hv_store(c, "realshared", 10, newSVuv(inf->t_rmshr), 0); hv_store(c, "realsharedactive", 16, newSVuv(inf->t_armshr), 0); hv_store(c, "pagefree", 8, newSViv(inf->t_free), 0); break; } case FMT_LOADAVG: { AV *c = (AV *)sv_2mortal((SV *)newAV()); struct loadavg *inf = (struct loadavg *)buf; double scale = inf->fscale; RETVAL = newRV((SV *)c); av_extend(c, 3); av_store(c, 0, newSVnv((double)inf->ldavg[0]/scale)); av_store(c, 1, newSVnv((double)inf->ldavg[1]/scale)); av_store(c, 2, newSVnv((double)inf->ldavg[2]/scale)); break; } case FMT_TIMEVAL: { struct timeval *inf = (struct timeval *)buf; RETVAL = newSVnv( (double)inf->tv_sec + ((double)inf->tv_usec/1000000) ); break; } /* the remaining custom formats are for opaque mibs */ 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; } case FMT_NTPTIMEVAL: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct ntptimeval *inf = (struct ntptimeval *)buf; RETVAL = newRV((SV *)c); hv_store(c, "sec", 3, newSVuv(inf->time.tv_sec), 0); hv_store(c, "nanosec", 7, newSViv(inf->time.tv_nsec), 0); hv_store(c, "maxerror", 8, newSViv(inf->maxerror), 0); hv_store(c, "esterror", 8, newSViv(inf->esterror), 0); hv_store(c, "taioffset", 9, newSViv(inf->tai), 0); hv_store(c, "timestate", 9, newSViv(inf->time_state), 0); break; } case FMT_DEVSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct devstat *inf = (struct devstat *)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: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct xvfsconf *inf = (struct xvfsconf *)buf; RETVAL = newRV((SV *)c); hv_store(c, "name", 4, newSVpv(inf->vfc_name, 0), 0); hv_store(c, "typenum", 7, newSViv(inf->vfc_typenum), 0); hv_store(c, "refcount", 8, newSViv(inf->vfc_refcount), 0); 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; RETVAL = newRV((SV *)c); hv_store(c, "error", 5, newSViv(inf->icps_error), 0); hv_store(c, "badcode", 7, newSViv(inf->icps_badcode), 0); hv_store(c, "tooshort", 8, newSViv(inf->icps_tooshort), 0); hv_store(c, "checksum", 8, newSViv(inf->icps_checksum), 0); hv_store(c, "badlen", 6, newSViv(inf->icps_badlen), 0); hv_store(c, "reflect", 7, newSViv(inf->icps_reflect), 0); hv_store(c, "bmcastecho", 10, newSViv(inf->icps_bmcastecho), 0); hv_store(c, "bmcasttstamp", 12, newSViv(inf->icps_bmcasttstamp), 0); hv_store(c, "badaddr", 7, newSViv(inf->icps_badaddr), 0); hv_store(c, "noroute", 7, newSViv(inf->icps_noroute), 0); break; } case FMT_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); hv_store(c, "badttl", 6, newSVuv(inf->igps_rcv_badttl), 0); hv_store(c, "badsum", 6, newSVuv(inf->igps_rcv_badsum), 0); /* Query statistics */ hv_store(c, "queries", 7, newSVuv(inf->igps_rcv_v1v2_queries + inf->igps_rcv_v3_queries), 0); hv_store(c, "v1v2_queries", 12, newSVuv(inf->igps_rcv_v1v2_queries), 0); hv_store(c, "v3_queries", 10, newSVuv(inf->igps_rcv_v3_queries), 0); hv_store(c, "badqueries", 10, newSVuv(inf->igps_rcv_badqueries), 0); hv_store(c, "gen_queries", 11, newSVuv(inf->igps_rcv_gen_queries), 0); hv_store(c, "group_queries", 13, newSVuv(inf->igps_rcv_group_queries), 0); hv_store(c, "gsr_queries", 11, newSVuv(inf->igps_rcv_gsr_queries), 0); hv_store(c, "drop_gsr_queries", 16, newSVuv(inf->igps_drop_gsr_queries), 0); /* Report statistics */ 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, "nore", 4, newSVuv(inf->igps_rcv_nora), 0); hv_store(c, "sent", 4, newSVuv(inf->igps_snd_reports), 0); #endif break; } case FMT_TCPSTAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct tcpstat *inf = (struct tcpstat *)buf; RETVAL = newRV((SV *)c); hv_store(c, "connattempt", 11, newSVuv(inf->tcps_connattempt), 0); hv_store(c, "accepts", 7, newSVuv(inf->tcps_accepts), 0); hv_store(c, "connects", 8, newSVuv(inf->tcps_connects), 0); hv_store(c, "drops", 5, newSVuv(inf->tcps_drops), 0); hv_store(c, "conndrops", 9, newSVuv(inf->tcps_conndrops), 0); hv_store(c, "closed", 6, newSVuv(inf->tcps_closed), 0); hv_store(c, "segstimed", 9, newSVuv(inf->tcps_segstimed), 0); hv_store(c, "rttupdated", 10, newSVuv(inf->tcps_rttupdated), 0); hv_store(c, "delack", 6, newSVuv(inf->tcps_delack), 0); hv_store(c, "timeoutdrop", 11, newSVuv(inf->tcps_timeoutdrop), 0); hv_store(c, "rexmttimeo", 10, newSVuv(inf->tcps_rexmttimeo), 0); hv_store(c, "persisttimeo", 12, newSVuv(inf->tcps_persisttimeo), 0); hv_store(c, "keeptimeo", 9, newSVuv(inf->tcps_keeptimeo), 0); hv_store(c, "keepprobe", 9, newSVuv(inf->tcps_keepprobe), 0); hv_store(c, "keepdrops", 9, newSVuv(inf->tcps_keepdrops), 0); hv_store(c, "sendtotal", 9, newSVuv(inf->tcps_sndtotal), 0); hv_store(c, "sendpack", 8, newSVuv(inf->tcps_sndpack), 0); hv_store(c, "sendbyte", 8, newSVuv(inf->tcps_sndbyte), 0); hv_store(c, "sendrexmitpack", 14, newSVuv(inf->tcps_sndrexmitpack), 0); hv_store(c, "sendrexmitbyte", 14, newSVuv(inf->tcps_sndrexmitbyte), 0); hv_store(c, "sendacks", 8, newSVuv(inf->tcps_sndacks), 0); hv_store(c, "sendprobe", 9, newSVuv(inf->tcps_sndprobe), 0); hv_store(c, "sendurgent", 10, newSVuv(inf->tcps_sndurg), 0); hv_store(c, "sendwinup", 9, newSVuv(inf->tcps_sndwinup), 0); hv_store(c, "sendctrl", 8, newSVuv(inf->tcps_sndctrl), 0); hv_store(c, "recvtotal", 9, newSVuv(inf->tcps_rcvtotal), 0); hv_store(c, "recvpack", 8, newSVuv(inf->tcps_rcvpack), 0); hv_store(c, "recvbyte", 8, newSVuv(inf->tcps_rcvbyte), 0); hv_store(c, "recvbadsum", 10, newSVuv(inf->tcps_rcvbadsum), 0); hv_store(c, "recvbadoff", 10, newSVuv(inf->tcps_rcvbadoff), 0); hv_store(c, "recvmemdrop", 11, newSVuv(inf->tcps_rcvmemdrop), 0); hv_store(c, "recvshort", 9, newSVuv(inf->tcps_rcvshort), 0); hv_store(c, "recvduppack", 11, newSVuv(inf->tcps_rcvduppack), 0); hv_store(c, "recvdupbyte", 11, newSVuv(inf->tcps_rcvdupbyte), 0); hv_store(c, "recvpartduppack", 15, newSVuv(inf->tcps_rcvduppack), 0); hv_store(c, "recvpartdupbyte", 15, newSVuv(inf->tcps_rcvdupbyte), 0); hv_store(c, "recvoopack", 10, newSVuv(inf->tcps_rcvoopack), 0); hv_store(c, "recvoobyte", 10, newSVuv(inf->tcps_rcvoobyte), 0); hv_store(c, "recvpackafterwin", 16, newSVuv(inf->tcps_rcvpackafterwin), 0); hv_store(c, "recvbyteafterwin", 16, newSVuv(inf->tcps_rcvbyteafterwin), 0); hv_store(c, "recvafterclose", 14, newSVuv(inf->tcps_rcvafterclose), 0); hv_store(c, "recvwinprobe", 12, newSVuv(inf->tcps_rcvwinprobe), 0); hv_store(c, "recvdupack", 10, newSVuv(inf->tcps_rcvdupack), 0); hv_store(c, "recvacktoomuch", 14, newSVuv(inf->tcps_rcvacktoomuch), 0); hv_store(c, "recvackpack", 11, newSVuv(inf->tcps_rcvackpack), 0); hv_store(c, "recvackbyte", 11, newSVuv(inf->tcps_rcvackbyte), 0); hv_store(c, "recvwinupd", 10, newSVuv(inf->tcps_rcvwinupd), 0); hv_store(c, "pawsdrop", 8, newSVuv(inf->tcps_pawsdrop), 0); hv_store(c, "predack", 7, newSVuv(inf->tcps_predack), 0); hv_store(c, "preddat", 7, newSVuv(inf->tcps_preddat), 0); hv_store(c, "pcbcachemiss", 12, newSVuv(inf->tcps_pcbcachemiss), 0); hv_store(c, "cachedrtt", 9, newSVuv(inf->tcps_cachedrtt), 0); hv_store(c, "cachedrttvar", 12, newSVuv(inf->tcps_cachedrttvar), 0); hv_store(c, "cachedssthresh", 14, newSVuv(inf->tcps_cachedssthresh), 0); hv_store(c, "usedrtt", 7, newSVuv(inf->tcps_usedrtt), 0); hv_store(c, "usedrttvar", 10, newSVuv(inf->tcps_usedrttvar), 0); hv_store(c, "usedssthresh", 12, newSVuv(inf->tcps_usedssthresh), 0); hv_store(c, "persistdrop", 11, newSVuv(inf->tcps_persistdrop), 0); hv_store(c, "badsyn", 6, newSVuv(inf->tcps_badsyn), 0); hv_store(c, "mturesent", 9, newSVuv(inf->tcps_mturesent), 0); hv_store(c, "listendrop", 10, newSVuv(inf->tcps_listendrop), 0); hv_store(c, "listendrop", 10, newSVuv(inf->tcps_listendrop), 0); hv_store(c, "added", 5, newSVuv(inf->tcps_sc_added), 0); hv_store(c, "rexmit", 6, newSVuv(inf->tcps_sc_retransmitted), 0); hv_store(c, "dupsyn", 6, newSVuv(inf->tcps_sc_dupsyn), 0); hv_store(c, "dropped", 7, newSVuv(inf->tcps_sc_dropped), 0); hv_store(c, "completed", 9, newSVuv(inf->tcps_sc_completed), 0); hv_store(c, "bucketoverflow", 14, newSVuv(inf->tcps_sc_bucketoverflow), 0); hv_store(c, "cacheoverflow", 13, newSVuv(inf->tcps_sc_cacheoverflow), 0); hv_store(c, "reset", 5, newSVuv(inf->tcps_sc_reset), 0); hv_store(c, "stale", 5, newSVuv(inf->tcps_sc_stale), 0); hv_store(c, "aborted", 7, newSVuv(inf->tcps_sc_aborted), 0); hv_store(c, "badack", 6, newSVuv(inf->tcps_sc_badack), 0); hv_store(c, "unreach", 7, newSVuv(inf->tcps_sc_unreach), 0); 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); hv_store(c, "sackrexmitbytes", 15, newSVuv(inf->tcps_sack_rexmit_bytes), 0); 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: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct udpstat *inf = (struct udpstat *)buf; RETVAL = newRV((SV *)c); hv_store(c, "inpackets", 9, newSVuv(inf->udps_ipackets), 0); hv_store(c, "headdrops", 9, newSVuv(inf->udps_hdrops), 0); hv_store(c, "badsum", 6, newSVuv(inf->udps_badsum), 0); hv_store(c, "nosum", 5, newSVuv(inf->udps_nosum), 0); hv_store(c, "badlen", 6, newSVuv(inf->udps_badlen), 0); hv_store(c, "noport", 6, newSVuv(inf->udps_noport), 0); hv_store(c, "noportbcast", 11, newSVuv(inf->udps_noportbcast), 0); hv_store(c, "pcbcachemiss", 12, newSVuv(inf->udpps_pcbcachemiss), 0); hv_store(c, "pcbhashmiss", 11, newSVuv(inf->udpps_pcbhashmiss), 0); hv_store(c, "outpackets", 10, newSVuv(inf->udps_opackets), 0); hv_store(c, "fastout", 7, newSVuv(inf->udps_fastout), 0); hv_store(c, "noportmcast", 11, newSVuv(inf->udps_noportmcast), 0); break; } case FMT_RIP6STAT: { HV *c = (HV *)sv_2mortal((SV *)newHV()); struct rip6stat *inf = (struct rip6stat *)buf; RETVAL = newRV((SV *)c); /* these values are of type u_quad_t */ hv_store(c, "inpackets", 9, newSVnv(inf->rip6s_ipackets), 0); hv_store(c, "insum", 5, newSVnv(inf->rip6s_isum), 0); hv_store(c, "badsum", 6, newSVnv(inf->rip6s_badsum), 0); hv_store(c, "nosock", 6, newSVnv(inf->rip6s_nosock), 0); hv_store(c, "nosockmcast", 11, newSVnv(inf->rip6s_nosockmcast), 0); hv_store(c, "sockfull", 8, newSVnv(inf->rip6s_fullsock), 0); 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: /* don't know how to interpret the results */ SvREFCNT_dec(sv_buf); XSRETURN_IV(0); break; default: warn("%s: unhandled format type=%d\n", arg, oid_fmt); SvREFCNT_dec(sv_buf); XSRETURN_IV(0); break; } if (oid_fmt != FMT_A) { SvREFCNT_dec(sv_buf); } OUTPUT: RETVAL SV * _mib_set(const char *arg, const char *value) INIT: HV *cache; SV **oidp; SV *oid; char *oid_data; int oid_fmt; int oid_len; int intval; unsigned int uintval; long longval; unsigned long ulongval; void *newval = 0; size_t newsize = 0; char *endconvptr; CODE: /* see if the mib exists */ cache = get_hv("BSD::Sysctl::MIB_CACHE", 0); if(oidp = hv_fetch(cache, arg, strlen(arg), 0)) { oid = *oidp; } else { /* else use the cache * How do you call an XS sub from C? */ warn("uncached mib: %s\n", arg); XSRETURN_UNDEF; } oid_data = SvPVX(oid); oid_fmt = (int)(*oid_data); oid_data += sizeof(int); oid_len = (int)(*oid_data); oid_data += sizeof(int); switch(oid_fmt) { case FMT_A: newval = (void *)value; newsize = strlen(value); break; case FMT_INT: intval = (int)strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid integer: '%s'", value); XSRETURN_UNDEF; } newval = &intval; newsize = sizeof(intval); break; case FMT_UINT: uintval = (unsigned int)strtoul(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid unsigned integer: '%s'", value); XSRETURN_UNDEF; } newval = &uintval; newsize = sizeof(uintval); break; case FMT_LONG: longval = strtol(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid long integer: '%s'", value); XSRETURN_UNDEF; } newval = &longval; newsize = sizeof(longval); break; case FMT_ULONG: ulongval = strtoul(value, &endconvptr, 0); if (endconvptr == value || *endconvptr != '\0') { warn("invalid unsigned long integer: '%s'", value); XSRETURN_UNDEF; } newval = &ulongval; newsize = sizeof(ulongval); break; } if (sysctl((int *)oid_data, oid_len, 0, 0, newval, newsize) == -1) { warn("set sysctl %s failed\n", arg); XSRETURN_UNDEF; } RETVAL = newSViv(1); OUTPUT: RETVAL