Programming in C of FC tutorial 5

TurnToJPG -->


###Full Circle C 7 ####Example Following is the origin ifstat.c, this program will list the net-interface payloads, and it will print out the net interface statistics every 2 seconds, but notice this program have several bugs:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef unsigned long long ull;
int parseDevFile(const char * iface, ull *bRx, ull *pRx, ull *bTx, ull *pTx);
void dumpInterfaceUsage(const char * iface);
int parseDevFile(const char * iface, ull *bRx, ull *pRx, ull *bTx, ull *pTx)
{
        FILE * fp = NULL;
        char * line = NULL;
        unsigned int len = 0;
        fp = fopen("/proc/net/dev", "r");
        if(fp == NULL)
        {
                return -1;
        }
        while(getline(&line, &len, fp) != -1)
        {
                if(strstr(line, iface) != NULL)
                {
                        sscanf(strstr(line, ":")+1, "%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", bRx, pRx, bTx, pTx);
                }
        }
        fclose(fp);
        free(line);
        return 0;
}
void dumpInterfaceUsage(const char * iface)
{
        ull ifaceBRxOld = 0, ifaceBTxOld = 0, ifacePRxOld = 0, ifacePTxOld = 0;
        ull ifaceBRxNew = 0, ifaceBTxNew = 0, ifacePRxNew = 0, ifacePTxNew = 0;
        const int SLEEP_TIME = 2;

        if(parseDevFile(iface, &ifaceBRxOld, &ifacePRxOld, &ifaceBTxOld, &ifacePTxOld) == -1) return;
        sleep(SLEEP_TIME);
        while(1)
        {
                if(parseDevFile(iface, &ifaceBRxNew, &ifacePRxNew, &ifaceBTxNew, &ifacePTxNew) == -1) return;
                printf("%s In: %8.2f kbytes/s  %5llu P/s Out: %8.2f kbytes/s %5llu P/s\n", iface,
                                (ifaceBRxNew - ifaceBRxOld)/(SLEEP_TIME *1024.0),
                                (ifacePRxNew - ifacePRxOld)/(SLEEP_TIME),
                                (ifaceBTxNew - ifaceBTxOld)/(SLEEP_TIME *1024.0),
                                (ifacePTxNew - ifacePTxOld)/(SLEEP_TIME));
                ifaceBRxOld = ifaceBRxNew;
                ifaceBTxOld = ifaceBTxNew;
                ifacePRxOld = ifacePRxNew;
                ifacePTxOld = ifacePTxNew;
                sleep(SLEEP_TIME);
        }
}

int main(int argc, char **argv)
{
        if(argc != 2)
        {
                printf("Usage: %s interfacename\n", argv[0]);
                return 1;
        }
        dumpInterfaceUsage(argv[1]);
        return 0;
}

Running result:

[root@localhost C7]# ./ifstat eth0
eth0 In:     0.24 kbytes/s      2 P/s Out:     0.25 kbytes/s     1 P/s
eth0 In:     0.32 kbytes/s      4 P/s Out:     0.97 kbytes/s     3 P/s
eth0 In:     1.29 kbytes/s     13 P/s Out:     5.06 kbytes/s    13 P/s
eth0 In:     0.06 kbytes/s      1 P/s Out:     0.08 kbytes/s     0 P/s

####Bugs Ok, now let’s see its bug:

#enable the unlimited:
[root@localhost C7]# ulimit -c unlimited
#Get the core file: 
[root@localhost C7]# ./ifstat b
Segmentation fault (core dumped)

####Debugging

[root@localhost C7]# ls -l -h core*
-rw------- 1 root root 272K Oct 14 06:53 core.3961
#Use gdb for anlysing the corefile:    
[root@localhost C7]# gdb ifstat core.3961
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./ifstat b'.
Program terminated with signal 11, Segmentation fault.
[New process 3961]
#0  0x00b6f957 in rawmemchr () from /lib/libc.so.6

Seems the corefile is useless, this because the error is not derived from our own code, but rather from the library. Run gdb for anlysing the ./ifstat b

[root@localhost C7]# gdb ./ifstat
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) run b
Starting program: /root/code/C7/ifstat b

Program received signal SIGSEGV, Segmentation fault.
0x00b6f957 in rawmemchr () from /lib/libc.so.6
(gdb) break parseDevFile
Breakpoint 1 at 0x804854a: file ifstat.c, line 10.
(gdb) run b
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/code/C7/ifstat b

Breakpoint 1, parseDevFile (iface=0xbfe52b5e "b", bRx=0xbfe50f80, pRx=0xbfe50f70, bTx=0xbfe50f78, pTx=0xbfe50f68) at ifstat.c:10
10              FILE * fp = NULL;
(gdb) step
11              char * line = NULL;
(gdb)
12              unsigned int len = 0;
(gdb)
13              fp = fopen("/proc/net/dev", "r");
(gdb) print fp
$1 = (FILE *) 0x0
(gdb) step
14              if(fp == NULL)
(gdb) step
18              while(getline(&line, &len, fp) != -1)
(gdb) display line
1: line = 0x0
(gdb) step
20                      if(strstr(line, iface) != NULL)
1: line = 0x9730170 "Inter-|   Receive", ' ' <repeats 48 times>, "|  Transmit\n"
(gdb) step
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9730170 "Inter-|   Receive", ' ' <repeats 48 times>, "|  Transmit\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9730170 " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
(gdb)
22                              sscanf(strstr(line, ":")+1, "%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", bRx, pRx, bTx, pTx);
1: line = 0x9730170 " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
(gdb)

Program received signal SIGSEGV, Segmentation fault.
0x00b6f957 in rawmemchr () from /lib/libc.so.6
(gdb)

We found another bug, also we can see ./ifstat dba

[root@localhost C7]# gdb ./ifstat
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) run dba
Starting program: /root/code/C7/ifstat dba
dba In:     0.00 kbytes/s      0 P/s Out:     0.00 kbytes/s     0 P/s
dba In:     0.00 kbytes/s      0 P/s Out:     0.00 kbytes/s     0 P/s

Program received signal SIGINT, Interrupt.
0x00ef3402 in __kernel_vsyscall ()
(gdb) break parseDevFile
Breakpoint 1 at 0x804854a: file ifstat.c, line 10.
(gdb) run dba
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/code/C7/ifstat dba

Breakpoint 1, parseDevFile (iface=0xbf81bb5c "dba", bRx=0xbf81ad40, pRx=0xbf81ad30, bTx=0xbf81ad38, pTx=0xbf81ad28) at ifstat.c:10
10              FILE * fp = NULL;
(gdb) step
11              char * line = NULL;
(gdb) step
12              unsigned int len = 0;
(gdb) step
13              fp = fopen("/proc/net/dev", "r");
(gdb) step
14              if(fp == NULL)
(gdb) step
18              while(getline(&line, &len, fp) != -1)
(gdb) display line
1: line = 0x0
(gdb) step
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "Inter-|   Receive", ' ' <repeats 48 times>, "|  Transmit\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "Inter-|   Receive", ' ' <repeats 48 times>, "|  Transmit\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "    lo: 4684910    2267    0    0    0     0          0         0  4684910    2267    0    0    0     0       0          0\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "    lo: 4684910    2267    0    0    0     0          0         0  4684910    2267    0    0    0     0       0          0\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "  eth0: 5135043   75928    0    0    0     0          0         0 15204045  129941    0    0    0     0       0          0\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "  eth0: 5135043   75928    0    0    0     0          0         0 15204045  129941    0    0    0     0       0          0\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
25              fclose(fp);
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
26              free(line);
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
27              return 0;
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
28      }
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
dumpInterfaceUsage (iface=0xbf81bb5c "dba") at ifstat.c:36
36              sleep(SLEEP_TIME);
(gdb)
39                      if(parseDevFile(iface, &ifaceBRxNew, &ifacePRxNew, &ifaceBTxNew, &ifacePTxNew) == -1) return;
(gdb)

Breakpoint 1, parseDevFile (iface=0xbf81bb5c "dba", bRx=0xbf81ad20, pRx=0xbf81ad10, bTx=0xbf81ad18, pTx=0xbf81ad08) at ifstat.c:10
10              FILE * fp = NULL;
1: line = 0xaf5ca0 ""
(gdb)
11              char * line = NULL;
1: line = 0xaf5ca0 ""
(gdb)
12              unsigned int len = 0;
1: line = 0x0
(gdb)
13              fp = fopen("/proc/net/dev", "r");
1: line = 0x0
(gdb)
14              if(fp == NULL)
1: line = 0x0
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x0
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "Inter-|   Receive", ' ' <repeats 48 times>, "|  Transmit\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "Inter-|   Receive", ' ' <repeats 48 times>, "|  Transmit\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "    lo: 4684910    2267    0    0    0     0          0         0  4684910    2267    0    0    0     0       0          0\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "    lo: 4684910    2267    0    0    0     0          0         0  4684910    2267    0    0    0     0       0          0\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "  eth0: 5141021   76010    0    0    0     0          0         0 15217535  130042    0    0    0     0       0          0\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "  eth0: 5141021   76010    0    0    0     0          0         0 15217535  130042    0    0    0     0       0          0\n"
(gdb)
20                      if(strstr(line, iface) != NULL)
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
18              while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
25              fclose(fp);
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
26              free(line);
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
27              return 0;
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
28      }
1: line = 0x9101170 "  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0\n"
(gdb)
dumpInterfaceUsage (iface=0xbf81bb5c "dba") at ifstat.c:40
40                      printf("%s In: %8.2f kbytes/s  %5llu P/s Out: %8.2f kbytes/s %5llu P/s\n", iface,
(gdb)
dba In:     0.00 kbytes/s      0 P/s Out:     0.00 kbytes/s     0 P/s

####Conclusion: And now we can get the reason, the ./ifstat b is because we reached the line2 of the /proc/net/dev, it has b for “bytes”.
./ifstat dba always print 0 because we don’t have this equipment at all !
####Correcting So the corrected code is listed as following:

int parseDevFile(const char * iface, ull *bRx, ull *pRx, ull *bTx, ull *pTx)
{
        FILE * fp = NULL;
        char * line = NULL;
        unsigned int len = 0;
        short int exists = 0;
        fp = fopen("/proc/net/dev", "r");
        if(fp == NULL)
        {
                return -1;
        }
        while(getline(&line, &len, fp) != -1)
        {
                if(strstr(line, iface) != NULL)
                {
                        if(strstr(line, ":") != NULL)
                        {
                                sscanf(strstr(line, ":")+1, "%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", bRx, pRx, bTx, pTx);
                                exists = 1;
                        }
                }
        }
        fclose(fp);
        free(line);
        if( exists != 1)
        {
                fprintf(stderr, "Your device %s is not in the file /proc/net/dev!\n", iface);
                exit(2);
        }
        return 0;
}

Now run it and the result is listed as:

[root@localhost C7]# ./ifstat_upgrade b
Your device b is not in the file /proc/net/dev!
[root@localhost C7]# ./ifstat_upgrade bba
Your device bba is not in the file /proc/net/dev!
[root@localhost C7]# ./ifstat_upgrade eth0
eth0 In:     0.03 kbytes/s      0 P/s Out:     0.00 kbytes/s     0 P/s
eth0 In:     0.03 kbytes/s      0 P/s Out:     0.08 kbytes/s     0 P/s