Print unknown fields in /proc/net/snmp unformatted instead of ignoring
[platform/upstream/net-tools.git] / statistics.c
1 /* Copyright '97 by Andi Kleen. Subject to the GPL. */
2
3 #include <ctype.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 /* #define WARN 1 */
9
10 #ifdef WARN
11 #define UFWARN(x) x
12 #else
13 #define UFWARN(x) 
14 #endif
15
16 int print_static; 
17
18 enum State { number = 0, i_forward, i_inp_icmp, i_outp_icmp, i_rto_alg };
19 #define normal number
20
21 struct entry {
22         char *title;
23         char *out; 
24         enum State type;
25 }; 
26
27 static enum State state;
28 static int indent[] = { 4, 4, 8, 8, 4 };       /* for each state */
29
30 #define I_STATIC (1<<16) /* static configuration option. */
31 #define I_TITLE  (1<<17)
32
33 char *titles[] = { /* for each state */
34         NULL, NULL, 
35         "ICMP input histogram:",
36         "ICMP output histogram:",
37         NULL
38 };
39
40 /* XXX check against the snmp mib rfc.
41  */
42 struct entry Iptab[] = {
43         { "Forwarding", "Forwarding is %s", i_forward|I_STATIC },
44         { "DefaultTTL", "Default TTL is %d", number|I_STATIC },
45         { "InReceives", "%d total packets received", number },
46         { "InHdrErrors", "%d with invalid headers", number },
47         { "InAddrErrors", "%d with invalid addresses", number },
48         { "ForwDatagrams", "%d forwarded", number },
49         { "InUnknownProtos", "%d with unknown protocol", number },
50         { "InDiscards", "%d incoming packets discarded", number },
51         { "InDelivers", "%d incoming packets delivered", number },
52         { "OutRequests", "%d requests sent out", number }, /*?*/
53         { "OutDiscards", "%d outgoing packets dropped", number }, 
54         { "OutNoRoutes", "%d dropped because of missing route", number },
55         { "ReasmTimeout", "%d fragments dropped after timeout", number },
56         { "ReasmReqds", "%d reassemblies required", number }, /* ? */
57         { "ReasmOKs", "%d packets reassembled ok", number }, 
58         { "ReasmFails", "%d packet reassembles failed", number }, 
59         { "FragOKs", "%d fragments received ok", number },
60         { "FragFails", "%d fragments failed", number },
61         { "FragCreates", "%d fragments created", number }
62 };
63
64 struct entry Icmptab[] = {
65         { "InMsgs", "%d ICMP messages received", number },
66         { "InErrors", "%d input ICMP message failed.", number },
67         { "InDestUnreachs", "destination unreachable: %d", i_inp_icmp|I_TITLE },
68         { "InTimeExcds", "timeout in transit: %d", i_inp_icmp|I_TITLE },
69         { "InParmProbs", "wrong parameters: %d", i_inp_icmp|I_TITLE },  /*?*/
70         { "InSrcQuenchs", "source quenchs: %d", i_inp_icmp|I_TITLE },
71         { "InRedirects", "redirects: %d", i_inp_icmp|I_TITLE },
72         { "InEchos", "echo requests: %d", i_inp_icmp|I_TITLE },
73         { "InEchoReps", "echo replies: %d", i_inp_icmp|I_TITLE },
74         { "InTimestamps", "timestamp request: %d", i_inp_icmp|I_TITLE },
75         { "InTimestampReps", "timestamp reply: %d", i_inp_icmp|I_TITLE },
76         { "InAddrMasks", "address mask request: %d", i_inp_icmp|I_TITLE }, /*?*/
77         { "InAddrMaskReps", "address mask replies", i_inp_icmp|I_TITLE }, /*?*/
78         { "OutMsgs", "%d ICMP messages sent", number },
79         { "OutErrors", "%d ICMP messages failed", number },
80         { "OutDestUnreachs", "destination unreachable: %d", i_outp_icmp|I_TITLE },
81         { "OutTimeExcds", "time exceeded: %d", i_outp_icmp|I_TITLE },
82         { "OutParmProbs", "wrong parameters: %d", i_outp_icmp|I_TITLE }, /*?*/
83         { "OutSrcQuenchs", "source quench: %d", i_outp_icmp|I_TITLE },
84         { "OutRedirects", "redirect: %d", i_outp_icmp|I_TITLE },
85         { "OutEchos", "echo request: %d", i_outp_icmp|I_TITLE },
86         { "OutEchoReps", "echo replies: %d", i_outp_icmp|I_TITLE },
87         { "OutTimestamps", "timestamp requests: %d", i_outp_icmp|I_TITLE },
88         { "OutTimestampReps", "timestamp replies: %d", i_outp_icmp|I_TITLE },
89         { "OutAddrMasks", "address mask requests: %d", i_outp_icmp|I_TITLE },
90         { "OutAddrMaskReps", "address mask replies: %d", i_outp_icmp|I_TITLE },
91 };
92
93 struct entry Tcptab[] = {
94         { "RtoAlgorithm", "RTO algorithm is %s", i_rto_alg|I_STATIC },
95         { "RtoMin", "", number },
96         { "RtoMax", "", number },
97         { "MaxConn", "", number },
98         { "ActiveOpens", "%d active opens", number },
99         { "PassiveOpens", "%d passive opens", number },
100         { "AttemptFails", "%d failed connection attempts", number },
101         { "EstabResets", "%d connection resets received", number },
102         { "CurrEstab", "%d connections established", number },
103         { "InSegs", "%d segments received", number },
104         { "OutSegs", "%d segments send out", number },
105         { "RetransSegs", "%d segments retransmited", number },
106         { "InErrs", "%d bad segments received.", number },
107         { "OutRsts", "%d resets sent", number },
108 };
109
110 struct entry Udptab[] = {
111         { "InDatagrams", "%d packets received", number },
112         { "NoPorts", "%d packets to unknown port received.", number },
113         { "InErrors", "%d packet receive errors", number },
114         { "OutDatagrams", "%d packets send", number },
115 };
116
117 struct tabtab {
118         char *title; 
119         struct entry *tab; 
120         size_t size; 
121 }; 
122
123 struct tabtab snmptabs[] = { 
124         { "Ip", Iptab, sizeof(Iptab) },
125         { "Icmp", Icmptab, sizeof(Icmptab) },
126         { "Tcp", Tcptab, sizeof(Tcptab) },
127         { "Udp", Udptab, sizeof(Udptab) },
128         { NULL }
129 }; 
130
131 static char *skiptok(char *s)
132 {
133         while (!isspace(*s) && *s != '\0')
134                 s++; 
135         return s;
136 }
137
138
139 /* XXX IGMP */ 
140
141 int cmpentries(const void *a, const void *b)
142 {
143         return strcmp( ((struct entry*)a)->title, ((struct entry*)b)->title);
144 }
145
146 void printval(struct tabtab *tab, char *title, int val) 
147 {
148         struct entry *ent, key; 
149         int type; 
150         char buf[512];
151
152         key.title = title; 
153         ent = bsearch(&key, tab->tab, tab->size/sizeof(struct entry),
154                                   sizeof(struct entry), cmpentries); 
155         if (!ent)  { /* try our best */ 
156                 printf("%*s%s: %d\n", indent[state], "", title, val);
157                 return;
158         }
159         type = ent->type; 
160         if (type & I_STATIC) {
161                 type &= ~I_STATIC; 
162                 if (!print_static) 
163                         return; 
164         }
165         if (*ent->out == '\0') 
166                 return; 
167
168         if (type & I_TITLE) {
169                 type &= ~I_TITLE;
170                 if (state != type)
171                         printf("%*s%s\n", indent[state], "", titles[type]);
172         }
173
174         buf[0] = '\0';
175         switch (type) {
176         case number:
177                 sprintf(buf, ent->out, val);
178                 break; 
179         case i_forward:
180                 type = normal;
181                 sprintf(buf, ent->out, val == 2 ? "enabled" : "disabled");
182                 break; 
183         case i_outp_icmp:
184         case i_inp_icmp: 
185                 if (val > 0) {
186                         sprintf(buf,ent->out, val); 
187                 }
188                 break; 
189         case i_rto_alg: /* XXXX */
190                 break; 
191         default:
192                 abort(); 
193         }
194         if (buf[0]) 
195                 printf("%*s%s\n",indent[type],"", buf);
196         
197         state = type;
198 }
199
200 struct tabtab *newtable(struct tabtab *tabs, char *title) 
201 {
202         struct tabtab *t; 
203
204         for (t = tabs; t->title; t++) 
205                 if (!strcmp(title, t->title)) {
206                         printf("%s:\n", title); 
207                         state = normal; 
208                         return t; 
209                 }
210         return NULL; 
211 }
212
213 void parsesnmp()
214 {
215         FILE *f; 
216         char buf1[512], buf2[512]; 
217         char *sp, *np, *p; 
218
219         f = fopen("/proc/net/snmp", "r"); 
220         if (!f) {
221                 perror("cannot open /proc/net/snmp");
222                 return;
223         }
224         while (fgets(buf1,sizeof buf1,f)) {
225                 int endflag; 
226                 struct tabtab *tab; 
227
228                 if (!fgets(buf2,sizeof buf2,f)) break; 
229                 sp = strchr(buf1, ':');
230                 np = strchr(buf2, ':'); 
231                 if (!np || !sp) 
232                         goto formaterr; 
233                 *sp = '\0'; 
234                 tab = newtable(snmptabs, buf1); 
235                 if (tab == NULL)  {
236                         UFWARN((printf("unknown title %s\n", buf1)));
237                         continue; 
238                 }
239                 np++; sp++; 
240                 
241                 endflag = 0; 
242                 while (!endflag) {
243                         while(isspace(*sp)) sp++; 
244                         while(isspace(*np)) np++; 
245                         /*if (*np == '\0') goto formaterr;*/ 
246
247                         p = skiptok(sp); 
248                         if (*p == '\0') endflag=1; 
249                         *p = '\0'; 
250
251                         if (*sp != '\0') /* XXX */ 
252                                 printval(tab, sp, strtoul(np,&np,10)); 
253                         sp = p+1; 
254                 }
255         }
256         if (ferror(f)) 
257                 perror("/proc/net/snmp"); 
258         fclose(f); 
259         return; 
260
261 formaterr: 
262         perror("error parsing /proc/net/snmp"); 
263         return; 
264 }
265
266 void inittab()
267 {
268         struct tabtab *t;
269  
270         /* we sort at runtime because I'm lazy ;) */ 
271         for (t = snmptabs; t->title; t++)  
272                 qsort(t->tab, t->size/sizeof(struct entry), 
273                           sizeof(struct entry), cmpentries); 
274 }