Programming in C of FC tutorial 5
Apr 8, 2014
Technology
###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