added files
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmpdelta.c
1 /*
2  * snmpdelta.c - Monitor deltas of integer valued SNMP variables
3  *
4  */
5 /**********************************************************************
6  *
7  *           Copyright 1996 by Carnegie Mellon University
8  * 
9  *                       All Rights Reserved
10  * 
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation, and that the name of CMU not be
16  * used in advertising or publicity pertaining to distribution of the
17  * software without specific, written prior permission.
18  * 
19  * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21  * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25  * SOFTWARE.
26  * 
27  **********************************************************************/
28
29 #include <net-snmp/net-snmp-config.h>
30
31 #if HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #if HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #if HAVE_STRING_H
38 #include <string.h>
39 #else
40 #include <strings.h>
41 #endif
42 #include <sys/types.h>
43 #if HAVE_NETINET_IN_H
44 #include <netinet/in.h>
45 #endif
46 #include <stdio.h>
47 #include <ctype.h>
48 #if TIME_WITH_SYS_TIME
49 # ifdef WIN32
50 #  include <sys/timeb.h>
51 # else
52 #  include <sys/time.h>
53 # endif
54 # include <time.h>
55 #else
56 # if HAVE_SYS_TIME_H
57 #  include <sys/time.h>
58 # else
59 #  include <time.h>
60 # endif
61 #endif
62 #if HAVE_SYS_SELECT_H
63 #include <sys/select.h>
64 #endif
65 #if HAVE_WINSOCK_H
66 #include <winsock.h>
67 #endif
68 #if HAVE_NETDB_H
69 #include <netdb.h>
70 #endif
71 #if HAVE_ARPA_INET_H
72 #include <arpa/inet.h>
73 #endif
74
75 #include <net-snmp/net-snmp-includes.h>
76
77 #define MAX_ARGS 256
78 #define NETSNMP_DS_APP_DONT_FIX_PDUS 0
79
80 const char     *SumFile = "Sum";
81
82 /*
83  * Information about the handled variables 
84  */
85 struct varInfo {
86     char           *name;
87     oid            *info_oid;
88     int             type;
89     size_t          oidlen;
90     char            descriptor[64];
91     u_int           value;
92     struct counter64 c64value;
93     float           max;
94     time_t          time;
95     int             peak_count;
96     float           peak;
97     float           peak_average;
98     int             spoiled;
99 };
100
101 struct varInfo  varinfo[128];
102 int             current_name = 0;
103 int             period = 1;
104 int             deltat = 0, timestamp = 0, fileout = 0, dosum =
105     0, printmax = 0;
106 int             keepSeconds = 0, peaks = 0;
107 int             tableForm = 0;
108 int             varbindsPerPacket = 60;
109
110 void            processFileArgs(char *fileName);
111
112 void
113 usage(void)
114 {
115     fprintf(stderr,
116             "Usage: snmpdelta [-Cf] [-CF commandFile] [-Cl] [-CL SumFileName]\n\t[-Cs] [-Ck] [-Ct] [-CS] [-Cv vars/pkt] [-Cp period]\n\t[-CP peaks] ");
117     snmp_parse_args_usage(stderr);
118     fprintf(stderr, " oid [oid ...]\n");
119     snmp_parse_args_descriptions(stderr);
120     fprintf(stderr, "snmpdelta specific options\n");
121     fprintf(stderr, "  -Cf\t\tDon't fix errors and retry the request.\n");
122     fprintf(stderr, "  -Cl\t\twrite configuration to file\n");
123     fprintf(stderr, "  -CF config\tload configuration from file\n");
124     fprintf(stderr, "  -Cp period\tspecifies the poll period\n");
125     fprintf(stderr, "  -CP peaks\treporting period in poll periods\n");
126     fprintf(stderr, "  -Cv vars/pkt\tnumber of variables per packet\n");
127     fprintf(stderr, "  -Ck\t\tkeep seconds in output time\n");
128     fprintf(stderr, "  -Cm\t\tshow max values\n");
129     fprintf(stderr, "  -CS\t\tlog to a sum file\n");
130     fprintf(stderr, "  -Cs\t\tshow timestamps\n");
131     fprintf(stderr, "  -Ct\t\tget timing from agent\n");
132     fprintf(stderr, "  -CT\t\tprint output in tabular form\n");
133     fprintf(stderr, "  -CL sumfile\tspecifies the sum file name\n");
134 }
135
136 static void
137 optProc(int argc, char *const *argv, int opt)
138 {
139     switch (opt) {
140     case 'C':
141         while (*optarg) {
142             switch ((opt = *optarg++)) {
143             case 'f':
144                 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
145                                           NETSNMP_DS_APP_DONT_FIX_PDUS);
146                 break;
147             case 'p':
148                 period = atoi(argv[optind++]);
149                 break;
150             case 'P':
151                 peaks = atoi(argv[optind++]);
152                 break;
153             case 'v':
154                 varbindsPerPacket = atoi(argv[optind++]);
155                 break;
156             case 't':
157                 deltat = 1;
158                 break;
159             case 's':
160                 timestamp = 1;
161                 break;
162             case 'S':
163                 dosum = 1;
164                 break;
165             case 'm':
166                 printmax = 1;
167                 break;
168             case 'F':
169                 processFileArgs(argv[optind++]);
170                 break;
171             case 'l':
172                 fileout = 1;
173                 break;
174             case 'L':
175                 SumFile = argv[optind++];
176                 break;
177             case 'k':
178                 keepSeconds = 1;
179                 break;
180             case 'T':
181                 tableForm = 1;
182                 break;
183             default:
184                 fprintf(stderr, "Bad -C options: %c\n", opt);
185                 exit(1);
186             }
187         }
188         break;
189     }
190 }
191
192 int
193 wait_for_peak_start(int period, int peak)
194 {
195     struct timeval  m_time, *tv = &m_time;
196     struct tm       tm;
197     time_t          SecondsAtNextHour;
198     int             target = 0;
199     int             seconds;
200
201     seconds = period * peak;
202
203     /*
204      * Find the current time 
205      */
206     gettimeofday(tv, (struct timezone *) 0);
207
208     /*
209      * Create a tm struct from it 
210      */
211     memcpy(&tm, localtime((time_t *) & tv->tv_sec), sizeof(tm));
212
213     /*
214      * Calculate the next hour 
215      */
216     tm.tm_sec = 0;
217     tm.tm_min = 0;
218     tm.tm_hour++;
219     SecondsAtNextHour = mktime(&tm);
220
221     /*
222      * Now figure out the amount of time to sleep 
223      */
224     target = (SecondsAtNextHour - tv->tv_sec) % seconds;
225
226     return target;
227 }
228
229 void
230 print_log(char *file, char *message)
231 {
232     FILE           *fp;
233
234     fp = fopen(file, "a");
235     if (fp == NULL) {
236         fprintf(stderr, "Couldn't open %s\n", file);
237         return;
238     }
239     fprintf(fp, "%s\n", message);
240     fclose(fp);
241 }
242
243 void
244 sprint_descriptor(char *buffer, struct varInfo *vip)
245 {
246     u_char         *buf = NULL, *cp = NULL;
247     size_t          buf_len = 0, out_len = 0;
248
249     if (!sprint_realloc_objid(&buf, &buf_len, &out_len, 1,
250                               vip->info_oid, vip->oidlen)) {
251         if (buf != NULL) {
252             free(buf);
253         }
254         return;
255     }
256
257     for (cp = buf; *cp; cp++);
258     while (cp >= buf) {
259         if (isalpha(*cp))
260             break;
261         cp--;
262     }
263     while (cp >= buf) {
264         if (*cp == '.')
265             break;
266         cp--;
267     }
268     cp++;
269     if (cp < buf)
270         cp = buf;
271     strcpy(buffer, cp);
272
273     if (buf != NULL) {
274         free(buf);
275     }
276 }
277
278 void
279 processFileArgs(char *fileName)
280 {
281     FILE           *fp;
282     char            buf[260] = { 0 }, *cp;
283     int             blank, linenumber = 0;
284
285     fp = fopen(fileName, "r");
286     if (fp == NULL)
287         return;
288     while (fgets(buf, sizeof(buf), fp)) {
289         linenumber++;
290         if (strlen(buf) > (sizeof(buf) - 2)) {
291             fprintf(stderr, "Line too long on line %d of %s\n",
292                     linenumber, fileName);
293             exit(1);
294         }
295         if (buf[0] == '#')
296             continue;
297         blank = TRUE;
298         for (cp = buf; *cp; cp++)
299             if (!isspace(*cp)) {
300                 blank = FALSE;
301                 break;
302             }
303         if (blank)
304             continue;
305         buf[strlen(buf) - 1] = 0;
306         varinfo[current_name++].name = strdup(buf);
307     }
308     fclose(fp);
309     return;
310 }
311
312 void
313 wait_for_period(int period)
314 {
315     struct timeval  m_time, *tv = &m_time;
316     struct tm       tm;
317     int             count;
318     static int      target = 0;
319     time_t          nexthour;
320
321     gettimeofday(tv, (struct timezone *) 0);
322
323     if (target) {
324         target += period;
325     } else {
326         memcpy(&tm, localtime((time_t *) & tv->tv_sec), sizeof(tm));
327         tm.tm_sec = 0;
328         tm.tm_min = 0;
329         tm.tm_hour++;
330         nexthour = mktime(&tm);
331
332         target = (nexthour - tv->tv_sec) % period;
333         if (target == 0)
334             target = period;
335         target += tv->tv_sec;
336     }
337
338     tv->tv_sec = target - tv->tv_sec;
339     if (tv->tv_usec != 0) {
340         tv->tv_sec--;
341         tv->tv_usec = 1000000 - tv->tv_usec;
342     }
343     if (tv->tv_sec < 0) {
344         /*
345          * ran out of time, schedule immediately 
346          */
347         tv->tv_sec = 0;
348         tv->tv_usec = 0;
349     }
350     count = 1;
351     while (count != 0) {
352         count = select(0, 0, 0, 0, tv);
353         switch (count) {
354         case 0:
355             break;
356         case -1:
357             /*
358              * FALLTHRU 
359              */
360         default:
361             snmp_log_perror("select");
362             break;
363         }
364     }
365 }
366
367 oid             sysUpTimeOid[9] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
368 size_t          sysUpTimeLen = 9;
369
370 int
371 main(int argc, char *argv[])
372 {
373     netsnmp_session session, *ss;
374     netsnmp_pdu    *pdu, *response;
375     netsnmp_variable_list *vars;
376     int             arg;
377     char           *gateway;
378
379     int             count;
380     struct varInfo *vip;
381     u_int           value = 0;
382     struct counter64 c64value;
383     float           printvalue;
384     time_t          last_time = 0;
385     time_t          this_time;
386     time_t          delta_time;
387     int             sum;        /* what the heck is this for, its never used? */
388     char            filename[128] = { 0 };
389     struct timeval  tv;
390     struct tm       tm;
391     char            timestring[64] = { 0 }, valueStr[64] = {
392     0}, maxStr[64] = {
393     0};
394     char            outstr[256] = { 0 }, peakStr[64] = {
395     0};
396     int             status;
397     int             begin, end, last_end;
398     int             print = 1;
399     int             exit_code = 0;
400
401     switch (arg = snmp_parse_args(argc, argv, &session, "C:", &optProc)) {
402     case -2:
403         exit(0);
404     case -1:
405         usage();
406         exit(1);
407     default:
408         break;
409     }
410
411     gateway = session.peername;
412
413     for (; optind < argc; optind++)
414         varinfo[current_name++].name = argv[optind];
415
416     if (current_name == 0) {
417         usage();
418         exit(1);
419     }
420
421     if (dosum) {
422         varinfo[current_name++].name = 0;
423     }
424
425     SOCK_STARTUP;
426
427     /*
428      * open an SNMP session 
429      */
430     ss = snmp_open(&session);
431     if (ss == NULL) {
432         /*
433          * diagnose snmp_open errors with the input netsnmp_session pointer 
434          */
435         snmp_sess_perror("snmpdelta", &session);
436         SOCK_CLEANUP;
437         exit(1);
438     }
439
440     if (tableForm && timestamp) {
441         printf("%s", gateway);
442     }
443     for (count = 0; count < current_name; count++) {
444         vip = varinfo + count;
445         if (vip->name) {
446             vip->oidlen = MAX_OID_LEN;
447             vip->info_oid = (oid *) malloc(sizeof(oid) * vip->oidlen);
448             if (snmp_parse_oid(vip->name, vip->info_oid, &vip->oidlen) ==
449                 NULL) {
450                 snmp_perror(vip->name);
451                 SOCK_CLEANUP;
452                 exit(1);
453             }
454             sprint_descriptor(vip->descriptor, vip);
455             if (tableForm)
456                 printf("\t%s", vip->descriptor);
457         } else {
458             vip->oidlen = 0;
459             strcpy(vip->descriptor, SumFile);
460         }
461         vip->value = 0;
462         zeroU64(&vip->c64value);
463         vip->time = 0;
464         vip->max = 0;
465         if (peaks) {
466             vip->peak_count = -1;
467             vip->peak = 0;
468             vip->peak_average = 0;
469         }
470     }
471
472     wait_for_period(period);
473
474     end = current_name;
475     sum = 0;
476     while (1) {
477         pdu = snmp_pdu_create(SNMP_MSG_GET);
478
479         if (deltat)
480             snmp_add_null_var(pdu, sysUpTimeOid, sysUpTimeLen);
481
482         if (end == current_name)
483             count = 0;
484         else
485             count = end;
486         begin = count;
487         for (; count < current_name
488              && count < begin + varbindsPerPacket - deltat; count++) {
489             if (varinfo[count].oidlen)
490                 snmp_add_null_var(pdu, varinfo[count].info_oid,
491                                   varinfo[count].oidlen);
492         }
493         last_end = end;
494         end = count;
495
496       retry:
497         status = snmp_synch_response(ss, pdu, &response);
498         if (status == STAT_SUCCESS) {
499             if (response->errstat == SNMP_ERR_NOERROR) {
500                 if (timestamp) {
501                     gettimeofday(&tv, (struct timezone *) 0);
502                     memcpy(&tm, localtime((time_t *) & tv.tv_sec),
503                            sizeof(tm));
504                     if (((period % 60)
505                          && (!peaks || ((period * peaks) % 60)))
506                         || keepSeconds)
507                         sprintf(timestring, " [%02d:%02d:%02d %d/%d]",
508                                 tm.tm_hour, tm.tm_min, tm.tm_sec,
509                                 tm.tm_mon + 1, tm.tm_mday);
510                     else
511                         sprintf(timestring, " [%02d:%02d %d/%d]",
512                                 tm.tm_hour, tm.tm_min,
513                                 tm.tm_mon + 1, tm.tm_mday);
514                 }
515
516                 vars = response->variables;
517                 if (deltat) {
518                     if (!vars) {
519                         fprintf(stderr, "Missing variable in reply\n");
520                         continue;
521                     } else {
522                         this_time = *(vars->val.integer);
523                     }
524                     vars = vars->next_variable;
525                 } else {
526                     this_time = 1;
527                 }
528
529                 for (count = begin; count < end; count++) {
530                     vip = varinfo + count;
531
532                     if (vip->oidlen) {
533                         if (!vars) {
534                             fprintf(stderr, "Missing variable in reply\n");
535                             break;
536                         }
537                         vip->type = vars->type;
538                         if (vars->type == ASN_COUNTER64) {
539                             u64Subtract(vars->val.counter64,
540                                         &vip->c64value, &c64value);
541                             memcpy(&vip->c64value, vars->val.counter64,
542                                    sizeof(struct counter64));
543                         } else {
544                             value = *(vars->val.integer) - vip->value;
545                             vip->value = *(vars->val.integer);
546                         }
547                         vars = vars->next_variable;
548                     } else {
549                         value = sum;
550                         sum = 0;
551                     }
552                     delta_time = this_time - vip->time;
553                     if (delta_time <= 0)
554                         delta_time = 100;
555                     last_time = vip->time;
556                     vip->time = this_time;
557                     if (last_time == 0)
558                         continue;
559
560                     if (vip->oidlen && vip->type != ASN_COUNTER64) {
561                         sum += value;
562                     }
563
564                     if (tableForm) {
565                         if (count == begin) {
566                             sprintf(outstr, "%s", timestring + 1);
567                         }
568                     } else {
569                         sprintf(outstr, "%s %s", timestring,
570                                 vip->descriptor);
571                     }
572
573                     if (deltat || tableForm) {
574                         if (vip->type == ASN_COUNTER64) {
575                             fprintf(stderr,
576                                     "time delta and table form not supported for counter64s\n");
577                             exit(1);
578                         } else {
579                             printvalue =
580                                 ((float) value * 100) / delta_time;
581                             if (tableForm)
582                                 sprintf(valueStr, "\t%.2f", printvalue);
583                             else
584                                 sprintf(valueStr, " /sec: %.2f",
585                                         printvalue);
586                         }
587                     } else {
588                         printvalue = (float) value;
589                         sprintf(valueStr, " /%d sec: ", period);
590                         if (vip->type == ASN_COUNTER64)
591                             printU64(valueStr + strlen(valueStr),
592                                      &c64value);
593                         else
594                             sprintf(valueStr + strlen(valueStr), "%u",
595                                     value);
596                     }
597
598                     if (!peaks) {
599                         strcat(outstr, valueStr);
600                     } else {
601                         print = 0;
602                         if (vip->peak_count == -1) {
603                             if (wait_for_peak_start(period, peaks) == 0)
604                                 vip->peak_count = 0;
605                         } else {
606                             vip->peak_average += printvalue;
607                             if (vip->peak < printvalue)
608                                 vip->peak = printvalue;
609                             if (++vip->peak_count == peaks) {
610                                 if (deltat)
611                                     sprintf(peakStr,
612                                             " /sec: %.2f        (%d sec Peak: %.2f)",
613                                             vip->peak_average /
614                                             vip->peak_count, period,
615                                             vip->peak);
616                                 else
617                                     sprintf(peakStr,
618                                             " /%d sec: %.0f     (%d sec Peak: %.0f)",
619                                             period,
620                                             vip->peak_average /
621                                             vip->peak_count, period,
622                                             vip->peak);
623                                 vip->peak_average = 0;
624                                 vip->peak = 0;
625                                 vip->peak_count = 0;
626                                 print = 1;
627                                 strcat(outstr, peakStr);
628                             }
629                         }
630                     }
631
632                     if (printmax) {
633                         if (printvalue > vip->max) {
634                             vip->max = printvalue;
635                         }
636                         if (deltat)
637                             sprintf(maxStr, "   (Max: %.2f)", vip->max);
638                         else
639                             sprintf(maxStr, "   (Max: %.0f)", vip->max);
640                         strcat(outstr, maxStr);
641                     }
642
643                     if (print) {
644                         if (fileout) {
645                             sprintf(filename, "%s-%s", gateway,
646                                     vip->descriptor);
647                             print_log(filename, outstr + 1);
648                         } else {
649                             if (tableForm)
650                                 printf("%s", outstr);
651                             else
652                                 printf("%s\n", outstr + 1);
653                             fflush(stdout);
654                         }
655                     }
656                 }
657                 if (end == last_end && tableForm)
658                     printf("\n");
659             } else {
660                 if (response->errstat == SNMP_ERR_TOOBIG) {
661                     if (response->errindex <= varbindsPerPacket
662                         && response->errindex > 0) {
663                         varbindsPerPacket = response->errindex - 1;
664                     } else {
665                         if (varbindsPerPacket > 30)
666                             varbindsPerPacket -= 5;
667                         else
668                             varbindsPerPacket--;
669                     }
670                     if (varbindsPerPacket <= 0) {
671                         exit_code = 5;
672                         break;
673                     }
674                     end = last_end;
675                     continue;
676                 } else if (response->errindex != 0) {
677                     fprintf(stderr, "Failed object: ");
678                     for (count = 1, vars = response->variables;
679                          vars && count != response->errindex;
680                          vars = vars->next_variable, count++);
681                     if (vars)
682                         fprint_objid(stderr, vars->name,
683                                      vars->name_length);
684                     fprintf(stderr, "\n");
685                     /*
686                      * Don't exit when OIDs from file are not found on agent
687                      * exit_code = 1;
688                      * break;
689                      */
690                 } else {
691                     fprintf(stderr, "Error in packet: %s\n",
692                             snmp_errstring(response->errstat));
693                     exit_code = 1;
694                     break;
695                 }
696
697                 /*
698                  * retry if the errored variable was successfully removed 
699                  */
700                 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
701                                             NETSNMP_DS_APP_DONT_FIX_PDUS)) {
702                     pdu = snmp_fix_pdu(response, SNMP_MSG_GET);
703                     snmp_free_pdu(response);
704                     response = NULL;
705                     if (pdu != NULL)
706                         goto retry;
707                 }
708             }
709
710         } else if (status == STAT_TIMEOUT) {
711             fprintf(stderr, "Timeout: No Response from %s\n", gateway);
712             response = 0;
713             exit_code = 1;
714             break;
715         } else {                /* status == STAT_ERROR */
716             snmp_sess_perror("snmpdelta", ss);
717             response = 0;
718             exit_code = 1;
719             break;
720         }
721
722         if (response)
723             snmp_free_pdu(response);
724         if (end == current_name) {
725             wait_for_period(period);
726         }
727     }
728     snmp_close(ss);
729     SOCK_CLEANUP;
730     return (exit_code);
731 }