if.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:28k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /* $OpenBSD: if.c,v 1.42 2005/03/13 16:05:50 mpf Exp $ */
  2. /* $NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $ */
  3. /*
  4.  * Copyright (c) 1983, 1988, 1993
  5.  * The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. Neither the name of the University nor the names of its contributors
  16.  *    may be used to endorse or promote products derived from this software
  17.  *    without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  20.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  23.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29.  * SUCH DAMAGE.
  30.  */
  31. #ifdef  INHERITED_CODE
  32. #ifndef lint
  33. #if 0
  34. static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94";
  35. #else
  36. static char *rcsid = "$OpenBSD: if.c,v 1.42 2005/03/13 16:05:50 mpf Exp $";
  37. #endif
  38. #endif /* not lint */
  39. #endif
  40. #include <net-snmp/net-snmp-config.h>
  41. #include <net-snmp/net-snmp-includes.h>
  42. #if HAVE_UNISTD_H
  43. #include <unistd.h>
  44. #endif
  45. #if HAVE_NET_IF_H
  46. #include <net/if.h>
  47. #endif
  48. #define __USE_XOPEN
  49. #define __USE_XOPEN_EXTENDED
  50. #include <signal.h>
  51. #include "main.h"
  52. #include "netstat.h"
  53. #define YES 1
  54. #define NO 0
  55. static void sidewaysintpr(u_int);
  56. static void timerSet(int interval_seconds);
  57. static void timerPause(void);
  58.     struct _if_info {
  59.         char            name[128];
  60.         char            ip[128], route[128];
  61.         int             mtu;
  62.         int             drops;
  63.         int             ifindex;
  64.                         /*
  65.                          * Save "expandable" fields as string values
  66.                          *  rather than integer statistics
  67.                          */
  68.         char            s_ipkts[20], s_ierrs[20];
  69.         char            s_opkts[20], s_oerrs[20];
  70.         char            s_ibytes[20], s_obytes[20];
  71.         char            s_outq[20];
  72.         unsigned long   ipkts, opkts;  /* Need to combine 2 MIB values */
  73.         int             operstatus;
  74. /*
  75.         u_long          netmask;
  76.         struct in_addr  ifip, ifroute;
  77.  */
  78.         struct _if_info *next;
  79.     };
  80. /*
  81.  * Retrieve the interface addressing information
  82.  * XXX - This could also be extended to handle non-IP interfaces
  83.  */
  84. void
  85. _set_address( struct _if_info *cur_if )
  86. {
  87.     oid    ipaddr_oid[] = { 1,3,6,1,2,1,4,20,1,0 };
  88.     size_t ipaddr_len   = OID_LENGTH( ipaddr_oid );
  89.     static netsnmp_variable_list *addr_if_var  =NULL;
  90.     static netsnmp_variable_list *addr_mask_var=NULL;
  91.     netsnmp_variable_list *vp, *vp2;
  92.     union {
  93.         in_addr_t addr;
  94.         char      data[4];
  95.     } tmpAddr;
  96.     char *cp;
  97.     in_addr_t ifAddr, mask;
  98.         /*
  99.          *  Note that this information only needs to be retrieved 
  100.          *    once, and can be re-used for subsequent calls.
  101.          */
  102.     if ( addr_if_var == NULL ) {
  103.         ipaddr_oid[ 9 ] = 2;  /* ipAdEntIfIndex */
  104.         snmp_varlist_add_variable( &addr_if_var, ipaddr_oid, ipaddr_len,
  105.                                    ASN_NULL, NULL,  0);
  106.         netsnmp_query_walk( addr_if_var, ss );
  107.         ipaddr_oid[ 9 ] = 3;  /* ipAdEntNetMask */
  108.         snmp_varlist_add_variable( &addr_mask_var, ipaddr_oid, ipaddr_len,
  109.                                    ASN_NULL, NULL,  0);
  110.         netsnmp_query_walk( addr_mask_var, ss );
  111.     }
  112.     /*
  113.      * Find the address row relevant to this interface
  114.      */
  115.     for (vp=addr_if_var, vp2=addr_mask_var;  vp;
  116.          vp=vp->next_variable, vp2=vp2->next_variable) {
  117.         if ( *vp->val.integer == cur_if->ifindex )
  118.             break;
  119.     }
  120.     if (vp2) {
  121.         /*
  122.          * Always want a numeric interface IP address
  123.          */
  124.         snprintf( cur_if->ip, 128, "%lu.%lu.%lu.%lu",
  125.                   vp2->name[10],
  126.                   vp2->name[11],
  127.                   vp2->name[12],
  128.                   vp2->name[13]);
  129.         /*
  130.          * But re-use the routing table utilities/code for
  131.          *   displaying the local network information
  132.          */
  133.         cp = tmpAddr.data;
  134.         cp[0] = vp2->name[ 10 ] & 0xff;
  135.         cp[1] = vp2->name[ 11 ] & 0xff;
  136.         cp[2] = vp2->name[ 12 ] & 0xff;
  137.         cp[3] = vp2->name[ 13 ] & 0xff;
  138.         ifAddr = tmpAddr.addr;
  139.         cp = tmpAddr.data;
  140.         cp[0] = vp2->val.string[ 0 ] & 0xff;
  141.         cp[1] = vp2->val.string[ 1 ] & 0xff;
  142.         cp[2] = vp2->val.string[ 2 ] & 0xff;
  143.         cp[3] = vp2->val.string[ 3 ] & 0xff;
  144.         mask = tmpAddr.addr;
  145.         snprintf( cur_if->route, 128, "%s", netname(ifAddr, mask));
  146.     }
  147. }
  148. /*
  149.  * Print a description of the network interfaces.
  150.  */
  151. void
  152. intpr(int interval)
  153. {
  154.     oid    ifcol_oid[]  = { 1,3,6,1,2,1,2,2,1,0 };
  155.     size_t ifcol_len    = OID_LENGTH( ifcol_oid );
  156.     struct _if_info *if_head, *if_tail, *cur_if;
  157.     netsnmp_variable_list *var, *vp;
  158.            /*
  159.             * Track maximum field widths, expanding as necessary
  160.             *   This is one reason why results can't be
  161.             *   displayed immediately they are retrieved.
  162.             */
  163.     int    max_name  = 4, max_ip    = 7, max_route = 7, max_outq  = 5;
  164.     int    max_ipkts = 5, max_ierrs = 5, max_opkts = 5, max_oerrs = 5;
  165.     int    max_ibytes = 6, max_obytes = 6;
  166.     int    i;
  167.     if (interval) {
  168.         sidewaysintpr((unsigned)interval);
  169.         return;
  170.     }
  171.         /*
  172.          * The traditional "netstat -i" output combines information
  173.          *   from two SNMP tables:
  174.          *      ipAddrTable   (for the IP address/network)
  175.          *      ifTable       (for the interface statistics)
  176.          *
  177.          * The previous approach was to retrieve (and save) the
  178.          *   address information first. Then walk the main ifTable,
  179.          *   add the relevant stored addresses, and saving the
  180.          *   full information for each interface, before displaying 
  181.          *   the results as a separate pass.
  182.          *
  183.          * This code reverses this general structure, by first retrieving
  184.          *   (and storing) the interface statistics for the whole table,
  185.          *   then inserting the address information obtained from the
  186.          *   ipAddrTable, and finally displaying the results.
  187.          * Such an arrangement should make it easier to extend this
  188.          *   to handle non-IP interfaces (hence not in ipAddrTable)
  189.          */
  190.     if_head = NULL;
  191.     if_tail = NULL;
  192.     var     = NULL;
  193. #define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-1 ] = x; 
  194.     snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len, ASN_NULL, NULL,  0)
  195.     ADD_IFVAR( 2 );                 /* ifName  */
  196.     ADD_IFVAR( 4 );                 /* ifMtu   */
  197.     ADD_IFVAR( 8 );                 /* ifOperStatus */
  198.     /*
  199.      * The Net/Open-BSD behaviour is to display *either* byte
  200.      *   counts *or* packet/error counts (but not both). FreeBSD
  201.      *   integrates the byte counts into the traditional display.
  202.      *
  203.      * The previous 'snmpnetstat' implementation followed the
  204.      *   separatist model.  This re-write offers an opportunity
  205.      *   to adopt the (more useful, IMO) Free-BSD approach.
  206.      *
  207.      * Or we could perhaps support both styles? :-)
  208.      */
  209.     if (bflag || oflag) {
  210.         ADD_IFVAR( 10 );            /* ifInOctets   */
  211.         ADD_IFVAR( 16 );            /* ifOutOctets  */
  212.     }
  213.     if (!oflag) {
  214.         ADD_IFVAR( 11 );            /* ifInUcastPkts  */
  215.         ADD_IFVAR( 12 );            /* ifInNUcastPkts */
  216.         ADD_IFVAR( 14 );            /* ifInErrors     */
  217.         ADD_IFVAR( 17 );            /* ifOutUcastPkts */
  218.         ADD_IFVAR( 18 );            /* ifOutNUcastPkts */
  219.         ADD_IFVAR( 20 );            /* ifOutErrors    */
  220.         ADD_IFVAR( 21 );            /* ifOutQLen      */
  221.     }
  222. /*  if (tflag) {
  223.         ADD_IFVAR( XX );            // ???
  224.     }
  225.  */
  226.     if (dflag) {
  227.         ADD_IFVAR( 19 );            /* ifOutDiscards  */
  228.     }
  229. #undef ADD_IFVAR
  230.         /*
  231.  * Now walk the ifTable, creating a list of interfaces
  232.  */
  233.     while ( 1 ) {
  234.         if (netsnmp_query_getnext( var, ss ) != SNMP_ERR_NOERROR)
  235.             break;
  236.         ifcol_oid[ ifcol_len-1 ] = 2; /* ifDescr */
  237.         if ( snmp_oid_compare( ifcol_oid, ifcol_len,
  238.                                var->name, ifcol_len) != 0 )
  239.             break;    /* End of Table */
  240.         cur_if = SNMP_MALLOC_TYPEDEF( struct _if_info );
  241.         if (!cur_if)
  242.             break;
  243.         cur_if->ifindex = var->name[ var->name_length-1 ];
  244.         for ( vp=var; vp; vp=vp->next_variable ) {
  245.             if ( var->name[ var->name_length-1 ] != cur_if->ifindex ) {
  246.                 /*
  247.                  * Inconsistent index information
  248.                  * XXX - Try to recover ?
  249.                  */
  250.                 SNMP_FREE( cur_if );
  251.                 cur_if = NULL;
  252.                 break;    /* not for now, no */
  253.             }
  254.             switch ( vp->name[ var->name_length-2 ] ) {
  255.             case 2:     /* ifDescr */
  256.                 if (vp->val_len >= sizeof(cur_if->name))
  257.                     vp->val_len  = sizeof(cur_if->name)-1;
  258.                 memmove( cur_if->name, vp->val.string, vp->val_len );
  259.                 cur_if->name[vp->val_len] = 0;
  260.                 if ((i = strlen(cur_if->name) + 1) > max_name)
  261.                     max_name = i;
  262.                 break;
  263.             case 4:     /* ifMtu   */
  264.                 cur_if->mtu = *vp->val.integer;
  265.                 break;
  266.             case 8:     /* ifOperStatus   */
  267.                 cur_if->operstatus = *vp->val.integer;
  268.                 /* XXX - any special processing ?? */
  269.                 break;
  270.             case 10: /* ifInOctets     */
  271.                 sprintf(cur_if->s_ibytes, "%lu", *vp->val.integer);
  272.                 i = strlen(cur_if->s_ibytes);
  273.                 if (i > max_ibytes)
  274.                     max_ibytes = i;
  275.                 break;
  276.             case 11: /* ifInUcastPkts  */
  277.                 cur_if->ipkts += *vp->val.integer;
  278.                 sprintf(cur_if->s_ipkts, "%lu", cur_if->ipkts);
  279.                 i = strlen(cur_if->s_ipkts);
  280.                 if (i > max_ipkts)
  281.                     max_ipkts = i;
  282.                 break;
  283.             case 12: /* ifInNUcastPkts  */
  284.                 cur_if->ipkts += *vp->val.integer;
  285.                 sprintf(cur_if->s_ipkts, "%lu", cur_if->ipkts);
  286.                 i = strlen(cur_if->s_ipkts);
  287.                 if (i > max_ipkts)
  288.                     max_ipkts = i;
  289.                 break;
  290.             case 14: /* ifInErrors      */
  291.                 sprintf(cur_if->s_ierrs, "%lu", *vp->val.integer);
  292.                 i = strlen(cur_if->s_ierrs);
  293.                 if (i > max_ierrs)
  294.                     max_ierrs = i;
  295.                 break;
  296.             case 16: /* ifOutOctets      */
  297.                 sprintf(cur_if->s_obytes, "%lu", *vp->val.integer);
  298.                 i = strlen(cur_if->s_obytes);
  299.                 if (i > max_obytes)
  300.                     max_obytes = i;
  301.                 break;
  302.             case 17: /* ifOutUcastPkts */
  303.                 cur_if->opkts += *vp->val.integer;
  304.                 sprintf(cur_if->s_opkts, "%lu", cur_if->opkts);
  305.                 i = strlen(cur_if->s_opkts);
  306.                 if (i > max_opkts)
  307.                     max_opkts = i;
  308.                 break;
  309.             case 18: /* ifOutNUcastPkts */
  310.                 cur_if->opkts += *vp->val.integer;
  311.                 sprintf(cur_if->s_opkts, "%lu", cur_if->opkts);
  312.                 i = strlen(cur_if->s_opkts);
  313.                 if (i > max_opkts)
  314.                     max_opkts = i;
  315.                 break;
  316.             case 19:    /* ifOutDiscards   */
  317.                 cur_if->drops = *vp->val.integer;
  318.                 break;
  319.             case 20: /* ifOutErrors     */
  320.                 sprintf(cur_if->s_oerrs, "%lu", *vp->val.integer);
  321.                 i = strlen(cur_if->s_oerrs);
  322.                 if (i > max_oerrs)
  323.                     max_oerrs = i;
  324.                 break;
  325.             case 21: /* ifOutQLen       */
  326.                 sprintf(cur_if->s_outq, "%lu", *vp->val.integer);
  327.                 i = strlen(cur_if->s_outq);
  328.                 if (i > max_outq)
  329.                     max_outq = i;
  330.                 break;
  331.             }
  332.         }
  333.         /*
  334.          *  XXX - Perhaps query ifXTable for additional info ??
  335.          *    (ifName/ifAlias, or HC counters)
  336.          */
  337.         /*
  338.          * If we're to monitor a particular interface, then
  339.          *   ignore all others.  It would be more efficient
  340.          *   to check this earlier (as part of processing 
  341.          *   the varbind list).  But performing this test here
  342.          *   means we can recognise ifXTable names as well)
  343.          */
  344.         if ( intrface && strcmp( cur_if->name, intrface ) != 0) {
  345.             SNMP_FREE( cur_if );
  346.             cur_if = NULL;
  347.         }
  348.         /*
  349.          * Insert the IP address and network settings, and
  350.          *   add the new _if_stat structure to the list.
  351.          */
  352.         if ( cur_if ) {
  353.             _set_address( cur_if );
  354.             i = strlen(cur_if->ip);
  355.             if (i > max_ip)
  356.                 max_ip = i;
  357.             i = strlen(cur_if->route);
  358.             if (i > max_route)
  359.                 max_route = i;
  360.             if ( if_tail ) {
  361.                 if_tail->next = cur_if;
  362.                 if_tail       = cur_if;
  363.             } else {
  364.                 if_head       = cur_if;
  365.                 if_tail       = cur_if;
  366.             }
  367.         }
  368.     }   /* while (1) */
  369.         /*
  370.          * Now display the specified results (in Free-BSD format)
  371.          *   setting the field widths appropriately....
  372.          */
  373.     printf("%*.*s %5.5s %*.*s %*.*s",
  374.            -max_name,  max_name,  "Name", "Mtu",
  375.            -max_route, max_route, "Network",
  376.            -max_ip,    max_ip,    "Address");
  377.     if (oflag) {
  378.         printf(" %*s %*s", max_ibytes,  "Ibytes",
  379.                            max_obytes,  "Obytes");
  380.     } else {
  381.         printf(" %*s %*s", max_ipkts,   "Ipkts",
  382.                            max_ierrs,   "Ierrs");
  383.         if (bflag) 
  384.             printf(" %*s", max_ibytes,  "Ibytes");
  385.         printf(" %*s %*s", max_opkts,   "Opkts",
  386.                            max_oerrs,   "Oerrs");
  387.         if (bflag) 
  388.             printf(" %*s", max_obytes,  "Obytes");
  389.         printf(" %*s",     max_outq,    "Queue");
  390.     }
  391.  /* if (tflag)
  392.         printf(" %s", "Time");
  393.   */
  394.     if (dflag)
  395.         printf(" %s", "Drop");
  396.     putchar('n');
  397.     for (cur_if = if_head; cur_if; cur_if=cur_if->next) {
  398.         if (cur_if->name[0] == 0)
  399.             continue;
  400.         printf( "%*.*s %5d", -max_name,  max_name,  cur_if->name, cur_if->mtu);
  401.         printf(" %*.*s",     -max_route, max_route, cur_if->route);
  402.         printf(" %*.*s",     -max_ip,    max_ip,    cur_if->ip);
  403.         if (oflag) {
  404.             printf(" %*s %*s", max_ibytes,  cur_if->s_ibytes,
  405.                                max_obytes,  cur_if->s_obytes);
  406.         } else {
  407.             printf(" %*s %*s", max_ipkts,   cur_if->s_ipkts,
  408.                                max_ierrs,   cur_if->s_ierrs);
  409.             if (bflag) 
  410.                 printf(" %*s", max_ibytes,  cur_if->s_ibytes);
  411.     
  412.             printf(" %*s %*s", max_opkts,   cur_if->s_opkts,
  413.                                max_oerrs,   cur_if->s_oerrs);
  414.             if (bflag) 
  415.                 printf(" %*s", max_obytes,  cur_if->s_obytes);
  416.             printf(" %*s",     max_outq,    cur_if->s_outq);
  417.         }
  418.      /* if (tflag)
  419.             printf(" %4d", cur_if->???);
  420.       */
  421.         if (dflag)
  422.             printf(" %4d", cur_if->drops);
  423.         putchar('n');
  424.     }
  425.         /*
  426.          * ... and tidy up.
  427.          */
  428.     for (cur_if = if_head; cur_if; cur_if=if_head) {
  429.         if_head=cur_if->next;
  430.         cur_if->next = NULL;
  431.         SNMP_FREE( cur_if );
  432.     }
  433. }
  434. #define MAXIF 100
  435. struct iftot {
  436. char ift_name[128]; /* interface name */
  437.         int     ifIndex;
  438. u_long ift_ip; /* input packets */
  439. u_long ift_ib; /* input bytes */
  440. u_long ift_ie; /* input errors */
  441. u_long ift_op; /* output packets */
  442. u_long ift_ob; /* output bytes */
  443. u_long ift_oe; /* output errors */
  444. u_long ift_co; /* collisions */
  445. u_long ift_dr; /* drops */
  446. };
  447. int signalled; /* set if alarm goes off "early" */
  448. /*
  449.  * Print a running summary of interface statistics.
  450.  * Repeat display every interval seconds, showing statistics
  451.  * collected over that interval.  Assumes that interval is non-zero.
  452.  * First line printed at top of screen is always cumulative.
  453.  */
  454. static void
  455. sidewaysintpr(unsigned int interval)
  456. {
  457.     /*
  458.      * As with the "one-shot" interface display, there are
  459.      *   two different possible output formats.  The Net/
  460.      *   Open-BSD style displays both information about a
  461.      *   single interface *and* the overall totals.
  462.      * The equivalent Free-BSD approach is to report on one
  463.      *   or the other (rather than both).  This is probably
  464.      *   more useful (IMO), and significantly more efficient.
  465.      *   So that's the style implemented here.
  466.      *
  467.      * Note that the 'ifcol' OID buffer can represent a full
  468.      *   instance (including ifIndex), rather than just a
  469.      *   column object OID, as with the one-shot code.
  470.      */
  471.     oid    ifcol_oid[]  = { 1,3,6,1,2,1,2,2,1,0,0 };
  472.     size_t ifcol_len    = OID_LENGTH( ifcol_oid );
  473.     netsnmp_variable_list *var, *vp;
  474.     struct iftot *ip  = NULL, *cur_if = NULL;    /* single I/F display */
  475.     struct iftot *sum = NULL, *total  = NULL;    /* overall summary    */
  476.     int    line;
  477.     int    first;
  478.     int    i;
  479.     var = NULL;
  480.     if ( intrface ) {
  481.         /*
  482.          * Locate the ifIndex of the interface to monitor,
  483.          *   by walking the ifDescr column of the ifTable
  484.          */
  485.         ifcol_oid[ ifcol_len-2 ] = 2;   /* ifDescr  */
  486.         snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len-1,
  487.                                    ASN_NULL, NULL,  0);
  488.         i = strlen(intrface);
  489.         netsnmp_query_walk( var, ss );
  490.         for (vp=var; vp; vp=vp->next_variable) {
  491.             if (strncmp(intrface, (char *)vp->val.string, i) == 0 &&
  492.                 i == vp->val_len)
  493.                 break;  /* found requested interface */
  494.         }
  495.         /*
  496.          * XXX - Might be worth searching ifName/ifAlias as well
  497.          */
  498.         if (!vp) {
  499.             fprintf(stderr, "%s: unknown interfacen", intrface );
  500.             exit(1);
  501.         }
  502.         /*
  503.          *  Prepare the current and previous 'iftot' structures,
  504.          *    and set the ifIndex value in the OID buffer.
  505.          */
  506.         ip     = SNMP_MALLOC_TYPEDEF( struct iftot );
  507.         cur_if = SNMP_MALLOC_TYPEDEF( struct iftot );
  508.         if (!ip || !cur_if) {
  509.             fprintf(stderr, "internal errorn");
  510.             exit(1);
  511.         }
  512.         ifcol_oid[ ifcol_len-1 ] = vp->name[ ifcol_len-1 ];
  513.         snmp_free_var( var );
  514.         var = NULL;
  515.     } else {
  516.         /*
  517.          *  Prepare the current and previous 'iftot' structures.
  518.          *    (using different pointers, for consistency with *BSD code)
  519.          */
  520.         sum   = SNMP_MALLOC_TYPEDEF( struct iftot );
  521.         total = SNMP_MALLOC_TYPEDEF( struct iftot );
  522.         if (!sum || !total) {
  523.             fprintf(stderr, "internal errorn");
  524.             exit(1);
  525.         }
  526.     }
  527.     timerSet( interval );
  528.     first = 1;
  529. banner:
  530.     printf( "%17s %14s %16s", "input",
  531.         intrface ? intrface : "(Total)", "output");
  532.     putchar('n');
  533.     printf( "%10s %5s %10s %10s %5s %10s %5s",
  534.         "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
  535.     if (dflag)
  536. printf(" %5.5s", "drops");
  537.     putchar('n');
  538.     fflush(stdout);
  539.     line = 0;
  540. loop:
  541.     if ( intrface ) {
  542. #define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-2 ] = x; 
  543.     snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len, ASN_NULL, NULL,  0)
  544.     /*  if (bflag) { */
  545.             ADD_IFVAR( 10 );        /* ifInOctets     */
  546.             ADD_IFVAR( 16 );        /* ifOutOctets    */
  547.     /*  } */
  548.         ADD_IFVAR( 11 );            /* ifInUcastPkts  */
  549.         ADD_IFVAR( 12 );            /* ifInNUcastPkts */
  550.         ADD_IFVAR( 14 );            /* ifInErrors     */
  551.         ADD_IFVAR( 17 );            /* ifOutUcastPkts */
  552.         ADD_IFVAR( 18 );            /* ifOutNUcastPkts */
  553.         ADD_IFVAR( 20 );            /* ifOutErrors    */
  554.         ADD_IFVAR( 21 );            /* ifOutQLen      */
  555.         if (dflag) {
  556.             ADD_IFVAR( 19 );        /* ifOutDiscards  */
  557.         }
  558. #undef ADD_IFVAR
  559.         netsnmp_query_get( var, ss );   /* Or parallel walk ?? */
  560.         cur_if->ift_ip = 0;
  561.         cur_if->ift_ib = 0;
  562.         cur_if->ift_ie = 0;
  563.         cur_if->ift_op = 0;
  564.         cur_if->ift_ob = 0;
  565.         cur_if->ift_oe = 0;
  566.         cur_if->ift_co = 0;
  567.         cur_if->ift_dr = 0;
  568.         cur_if->ifIndex = var->name[ ifcol_len-1 ];
  569.         for (vp=var; vp; vp=vp->next_variable) {
  570.             switch (vp->name[ifcol_len-2]) {
  571.             case 10:    /* ifInOctets */
  572.                 cur_if->ift_ib = *vp->val.integer;
  573.                 break;
  574.             case 11:    /* ifInUcastPkts */
  575.                 cur_if->ift_ip += *vp->val.integer;
  576.                 break;
  577.             case 12:    /* ifInNUcastPkts */
  578.                 cur_if->ift_ip += *vp->val.integer;
  579.                 break;
  580.             case 14:    /* ifInErrors */
  581.                 cur_if->ift_ie = *vp->val.integer;
  582.                 break;
  583.             case 16:    /* ifOutOctets */
  584.                 cur_if->ift_ob = *vp->val.integer;
  585.                 break;
  586.             case 17:    /* ifOutUcastPkts */
  587.                 cur_if->ift_op += *vp->val.integer;
  588.                 break;
  589.             case 18:    /* ifOutNUcastPkts */
  590.                 cur_if->ift_op += *vp->val.integer;
  591.                 break;
  592.             case 19:    /* ifOutDiscards */
  593.                 cur_if->ift_dr = *vp->val.integer;
  594.                 break;
  595.             case 20:    /* ifOutErrors */
  596.                 cur_if->ift_oe = *vp->val.integer;
  597.                 break;
  598.             case 21:    /* ifOutQLen */
  599.                 cur_if->ift_co = *vp->val.integer;
  600.                 break;
  601.             }
  602.         }
  603.         snmp_free_varbind( var );
  604.         var = NULL;
  605.  
  606.         if (!first) {
  607.       printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
  608.   cur_if->ift_ip - ip->ift_ip,
  609.   cur_if->ift_ie - ip->ift_ie,
  610. cur_if->ift_ib - ip->ift_ib,
  611. cur_if->ift_op - ip->ift_op,
  612. cur_if->ift_oe - ip->ift_oe,
  613. cur_if->ift_ob - ip->ift_ob,
  614. cur_if->ift_co - ip->ift_co);
  615.     if (dflag)
  616. printf(" %5lu", cur_if->ift_dr - ip->ift_dr);
  617.             putchar('n');
  618.             fflush(stdout);
  619. }
  620. ip->ift_ip = cur_if->ift_ip;
  621. ip->ift_ie = cur_if->ift_ie;
  622. ip->ift_ib = cur_if->ift_ib;
  623. ip->ift_op = cur_if->ift_op;
  624. ip->ift_oe = cur_if->ift_oe;
  625. ip->ift_ob = cur_if->ift_ob;
  626. ip->ift_co = cur_if->ift_co;
  627. ip->ift_dr = cur_if->ift_dr;
  628.     }  /* (single) interface */
  629.     else {
  630. sum->ift_ip = 0;
  631. sum->ift_ib = 0;
  632. sum->ift_ie = 0;
  633. sum->ift_op = 0;
  634. sum->ift_ob = 0;
  635. sum->ift_oe = 0;
  636. sum->ift_co = 0;
  637. sum->ift_dr = 0;
  638. #define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-2 ] = x; 
  639.     snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len-1, ASN_NULL, NULL,  0)
  640.         ADD_IFVAR( 11 );            /* ifInUcastPkts  */
  641.         ADD_IFVAR( 12 );            /* ifInNUcastPkts */
  642.         ADD_IFVAR( 14 );            /* ifInErrors     */
  643.         ADD_IFVAR( 17 );            /* ifOutUcastPkts */
  644.         ADD_IFVAR( 18 );            /* ifOutNUcastPkts */
  645.         ADD_IFVAR( 20 );            /* ifOutErrors    */
  646.         ADD_IFVAR( 21 );            /* ifOutQLen      */
  647.     /*  if (bflag) { */
  648.             ADD_IFVAR( 10 );        /* ifInOctets     */
  649.             ADD_IFVAR( 16 );        /* ifOutOctets    */
  650.     /*  } */
  651.         if (dflag) {
  652.             ADD_IFVAR( 19 );        /* ifOutDiscards  */
  653.         }
  654. #undef ADD_IFVAR
  655.         ifcol_oid[ ifcol_len-2 ] = 11;       /* ifInUcastPkts */
  656.         while ( 1 ) {
  657.             if (netsnmp_query_getnext( var, ss ) != SNMP_ERR_NOERROR)
  658.                 break;
  659.             if ( snmp_oid_compare( ifcol_oid, ifcol_len-2,
  660.                                    var->name, ifcol_len-2) != 0 )
  661.                 break;    /* End of Table */
  662.             
  663.             for ( vp=var; vp; vp=vp->next_variable ) {
  664.                 switch ( vp->name[ ifcol_len-2 ] ) {
  665.                 case 10:    /* ifInOctets */
  666.                     sum->ift_ib += *vp->val.integer;
  667.                     break;
  668.                 case 11:    /* ifInUcastPkts */
  669.                     sum->ift_ip += *vp->val.integer;
  670.                     break;
  671.                 case 12:    /* ifInNUcastPkts */
  672.                     sum->ift_ip += *vp->val.integer;
  673.                     break;
  674.                 case 14:    /* ifInErrors */
  675.                     sum->ift_ie += *vp->val.integer;
  676.                     break;
  677.                 case 16:    /* ifOutOctets */
  678.                     sum->ift_ob += *vp->val.integer;
  679.                     break;
  680.                 case 17:    /* ifOutUcastPkts */
  681.                     sum->ift_op += *vp->val.integer;
  682.                     break;
  683.                 case 18:    /* ifOutNUcastPkts */
  684.                     sum->ift_op += *vp->val.integer;
  685.                     break;
  686.                 case 19:    /* ifOutDiscards */
  687.                     sum->ift_dr += *vp->val.integer;
  688.                     break;
  689.                 case 20:    /* ifOutErrors */
  690.                     sum->ift_oe += *vp->val.integer;
  691.                     break;
  692.                 case 21:    /* ifOutQLen */
  693.                     sum->ift_co += *vp->val.integer;
  694.                     break;
  695.                 }
  696.             }
  697.             /*
  698.              * Now loop to retrieve the next entry from the table.
  699.              */
  700.         }   /* while (1) */
  701.         snmp_free_varbind( var );
  702.         var = NULL;
  703.  
  704.         if (!first) {
  705.       printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
  706.   sum->ift_ip - total->ift_ip,
  707.   sum->ift_ie - total->ift_ie,
  708. sum->ift_ib - total->ift_ib,
  709. sum->ift_op - total->ift_op,
  710. sum->ift_oe - total->ift_oe,
  711. sum->ift_ob - total->ift_ob,
  712. sum->ift_co - total->ift_co);
  713.     if (dflag)
  714. printf(" %5lu", sum->ift_dr - total->ift_dr);
  715.             putchar('n');
  716.             fflush(stdout);
  717. }
  718. total->ift_ip = sum->ift_ip;
  719. total->ift_ie = sum->ift_ie;
  720. total->ift_ib = sum->ift_ib;
  721. total->ift_op = sum->ift_op;
  722. total->ift_oe = sum->ift_oe;
  723. total->ift_ob = sum->ift_ob;
  724. total->ift_co = sum->ift_co;
  725. total->ift_dr = sum->ift_dr;
  726.     }  /* overall summary */
  727.     timerPause();
  728.     timerSet(interval);
  729.     line++;
  730.     first = 0;
  731.     if (line == 21)
  732.      goto banner;
  733.     else
  734.      goto loop;
  735.     /*NOTREACHED*/
  736. }
  737. /*
  738.  * timerSet sets or resets the timer to fire in "interval" seconds.
  739.  * timerPause waits only if the timer has not fired.
  740.  * timing precision is not considered important.
  741.  */
  742. #if (defined(WIN32) || defined(cygwin))
  743. static int      sav_int;
  744. static time_t   timezup;
  745. static void
  746. timerSet(int interval_seconds)
  747. {
  748.     sav_int = interval_seconds;
  749.     timezup = time(0) + interval_seconds;
  750. }
  751. /*
  752.  * you can do better than this ! 
  753.  */
  754. static void
  755. timerPause(void)
  756. {
  757.     time_t          now;
  758.     while (time(&now) < timezup)
  759. #ifdef WIN32
  760.         Sleep(400);
  761. #else
  762.     {
  763.         struct timeval  tx;
  764.         tx.tv_sec = 0;
  765.         tx.tv_usec = 400 * 1000;        /* 400 milliseconds */
  766.         select(0, 0, 0, 0, &tx);
  767.     }
  768. #endif
  769. }
  770. #else
  771. /*
  772.  * Called if an interval expires before sidewaysintpr has completed a loop.
  773.  * Sets a flag to not wait for the alarm.
  774.  */
  775. RETSIGTYPE
  776. catchalarm(int sig)
  777. {
  778.     signalled = YES;
  779. }
  780. static void
  781. timerSet(int interval_seconds)
  782. {
  783. #ifdef HAVE_SIGSET
  784.     (void) sigset(SIGALRM, catchalarm);
  785. #else
  786.     (void) signal(SIGALRM, catchalarm);
  787. #endif
  788.     signalled = NO;
  789.     (void) alarm(interval_seconds);
  790. }
  791. static void
  792. timerPause(void)
  793. {
  794. #ifdef HAVE_SIGHOLD
  795.     sighold(SIGALRM);
  796.     if (!signalled) {
  797.         sigpause(SIGALRM);
  798.     }
  799. #else
  800.     int             oldmask;
  801.     oldmask = sigblock(sigmask(SIGALRM));
  802.     if (!signalled) {
  803.         sigpause(0);
  804.     }
  805.     sigsetmask(oldmask);
  806. #endif
  807. }
  808. #endif                          /* !WIN32 && !cygwin */