dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / snmp / apps / snmpdelta.c
blob0d78c97e7e5945296b36671724e40b2b21487f76
1 /*
2 * snmpdelta.c - Monitor deltas of integer valued SNMP variables
4 */
5 /**********************************************************************
7 * Copyright 1996 by Carnegie Mellon University
8 *
9 * All Rights Reserved
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.
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.
27 **********************************************************************/
29 #include <net-snmp/net-snmp-config.h>
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
75 #include <net-snmp/net-snmp-includes.h>
77 #define MAX_ARGS 256
78 #define NETSNMP_DS_APP_DONT_FIX_PDUS 0
80 const char *SumFile = "Sum";
83 * Information about the handled variables
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;
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;
110 void processFileArgs(char *fileName);
112 void
113 usage(void)
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");
136 static void
137 optProc(int argc, char *const *argv, int opt)
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);
188 break;
193 wait_for_peak_start(int period, int peak)
195 struct timeval m_time, *tv = &m_time;
196 struct tm tm;
197 time_t SecondsAtNextHour;
198 int target = 0;
199 int seconds;
201 seconds = period * peak;
204 * Find the current time
206 gettimeofday(tv, (struct timezone *) 0);
209 * Create a tm struct from it
211 memcpy(&tm, localtime((time_t *) & tv->tv_sec), sizeof(tm));
214 * Calculate the next hour
216 tm.tm_sec = 0;
217 tm.tm_min = 0;
218 tm.tm_hour++;
219 SecondsAtNextHour = mktime(&tm);
222 * Now figure out the amount of time to sleep
224 target = (SecondsAtNextHour - tv->tv_sec) % seconds;
226 return target;
229 void
230 print_log(char *file, char *message)
232 FILE *fp;
234 fp = fopen(file, "a");
235 if (fp == NULL) {
236 fprintf(stderr, "Couldn't open %s\n", file);
237 return;
239 fprintf(fp, "%s\n", message);
240 fclose(fp);
243 void
244 sprint_descriptor(char *buffer, struct varInfo *vip)
246 u_char *buf = NULL, *cp = NULL;
247 size_t buf_len = 0, out_len = 0;
249 if (!sprint_realloc_objid(&buf, &buf_len, &out_len, 1,
250 vip->info_oid, vip->oidlen)) {
251 if (buf != NULL) {
252 free(buf);
254 return;
257 for (cp = buf; *cp; cp++);
258 while (cp >= buf) {
259 if (isalpha(*cp))
260 break;
261 cp--;
263 while (cp >= buf) {
264 if (*cp == '.')
265 break;
266 cp--;
268 cp++;
269 if (cp < buf)
270 cp = buf;
271 strcpy(buffer, cp);
273 if (buf != NULL) {
274 free(buf);
278 void
279 processFileArgs(char *fileName)
281 FILE *fp;
282 char buf[260] = { 0 }, *cp;
283 int blank, linenumber = 0;
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);
295 if (buf[0] == '#')
296 continue;
297 blank = TRUE;
298 for (cp = buf; *cp; cp++)
299 if (!isspace(*cp)) {
300 blank = FALSE;
301 break;
303 if (blank)
304 continue;
305 buf[strlen(buf) - 1] = 0;
306 varinfo[current_name++].name = strdup(buf);
308 fclose(fp);
309 return;
312 void
313 wait_for_period(int period)
315 struct timeval m_time, *tv = &m_time;
316 struct tm tm;
317 int count;
318 static int target = 0;
319 time_t nexthour;
321 gettimeofday(tv, (struct timezone *) 0);
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);
332 target = (nexthour - tv->tv_sec) % period;
333 if (target == 0)
334 target = period;
335 target += tv->tv_sec;
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;
343 if (tv->tv_sec < 0) {
345 * ran out of time, schedule immediately
347 tv->tv_sec = 0;
348 tv->tv_usec = 0;
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:
358 * FALLTHRU
360 default:
361 snmp_log_perror("select");
362 break;
367 oid sysUpTimeOid[9] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
368 size_t sysUpTimeLen = 9;
371 main(int argc, char *argv[])
373 netsnmp_session session, *ss;
374 netsnmp_pdu *pdu, *response;
375 netsnmp_variable_list *vars;
376 int arg;
377 char *gateway;
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] = {
394 char outstr[256] = { 0 }, peakStr[64] = {
396 int status;
397 int begin, end, last_end;
398 int print = 1;
399 int exit_code = 0;
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;
411 gateway = session.peername;
413 for (; optind < argc; optind++)
414 varinfo[current_name++].name = argv[optind];
416 if (current_name == 0) {
417 usage();
418 exit(1);
421 if (dosum) {
422 varinfo[current_name++].name = 0;
425 SOCK_STARTUP;
428 * open an SNMP session
430 ss = snmp_open(&session);
431 if (ss == NULL) {
433 * diagnose snmp_open errors with the input netsnmp_session pointer
435 snmp_sess_perror("snmpdelta", &session);
436 SOCK_CLEANUP;
437 exit(1);
440 if (tableForm && timestamp) {
441 printf("%s", gateway);
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);
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);
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;
472 wait_for_period(period);
474 end = current_name;
475 sum = 0;
476 while (1) {
477 pdu = snmp_pdu_create(SNMP_MSG_GET);
479 if (deltat)
480 snmp_add_null_var(pdu, sysUpTimeOid, sysUpTimeLen);
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);
493 last_end = end;
494 end = count;
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);
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);
524 vars = vars->next_variable;
525 } else {
526 this_time = 1;
529 for (count = begin; count < end; count++) {
530 vip = varinfo + count;
532 if (vip->oidlen) {
533 if (!vars) {
534 fprintf(stderr, "Missing variable in reply\n");
535 break;
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);
547 vars = vars->next_variable;
548 } else {
549 value = sum;
550 sum = 0;
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;
560 if (vip->oidlen && vip->type != ASN_COUNTER64) {
561 sum += value;
564 if (tableForm) {
565 if (count == begin) {
566 sprintf(outstr, "%s", timestring + 1);
568 } else {
569 sprintf(outstr, "%s %s", timestring,
570 vip->descriptor);
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);
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);
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);
632 if (printmax) {
633 if (printvalue > vip->max) {
634 vip->max = printvalue;
636 if (deltat)
637 sprintf(maxStr, " (Max: %.2f)", vip->max);
638 else
639 sprintf(maxStr, " (Max: %.0f)", vip->max);
640 strcat(outstr, maxStr);
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);
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--;
670 if (varbindsPerPacket <= 0) {
671 exit_code = 5;
672 break;
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");
686 * Don't exit when OIDs from file are not found on agent
687 * exit_code = 1;
688 * break;
690 } else {
691 fprintf(stderr, "Error in packet: %s\n",
692 snmp_errstring(response->errstat));
693 exit_code = 1;
694 break;
698 * retry if the errored variable was successfully removed
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;
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;
722 if (response)
723 snmp_free_pdu(response);
724 if (end == current_name) {
725 wait_for_period(period);
728 snmp_close(ss);
729 SOCK_CLEANUP;
730 return (exit_code);