2 * snmpdelta.c - Monitor deltas of integer valued SNMP variables
5 /**********************************************************************
7 * Copyright 1996 by Carnegie Mellon University
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
27 **********************************************************************/
29 #include <net-snmp/net-snmp-config.h>
42 #include <sys/types.h>
44 #include <netinet/in.h>
48 #if TIME_WITH_SYS_TIME
50 # include <sys/timeb.h>
52 # include <sys/time.h>
57 # include <sys/time.h>
63 #include <sys/select.h>
72 #include <arpa/inet.h>
75 #include <net-snmp/net-snmp-includes.h>
78 #define NETSNMP_DS_APP_DONT_FIX_PDUS 0
80 const char *SumFile = "Sum";
83 * Information about the handled variables
92 struct counter64 c64value;
101 struct varInfo varinfo[128];
102 int current_name = 0;
104 int deltat = 0, timestamp = 0, fileout = 0, dosum =
106 int keepSeconds = 0, peaks = 0;
108 int varbindsPerPacket = 60;
110 void processFileArgs(char *fileName);
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");
137 optProc(int argc, char *const *argv, int opt)
142 switch ((opt = *optarg++)) {
144 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
145 NETSNMP_DS_APP_DONT_FIX_PDUS);
148 period = atoi(argv[optind++]);
151 peaks = atoi(argv[optind++]);
154 varbindsPerPacket = atoi(argv[optind++]);
169 processFileArgs(argv[optind++]);
175 SumFile = argv[optind++];
184 fprintf(stderr, "Bad -C options: %c\n", opt);
193 wait_for_peak_start(int period, int peak)
195 struct timeval m_time, *tv = &m_time;
197 time_t SecondsAtNextHour;
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
219 SecondsAtNextHour = mktime(&tm);
222 * Now figure out the amount of time to sleep
224 target = (SecondsAtNextHour - tv->tv_sec) % seconds;
230 print_log(char *file, char *message)
234 fp = fopen(file, "a");
236 fprintf(stderr, "Couldn't open %s\n", file);
239 fprintf(fp, "%s\n", message);
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)) {
257 for (cp = buf; *cp; cp++);
279 processFileArgs(char *fileName)
282 char buf[260] = { 0 }, *cp;
283 int blank, linenumber = 0;
285 fp = fopen(fileName, "r");
288 while (fgets(buf, sizeof(buf), fp)) {
290 if (strlen(buf) > (sizeof(buf) - 2)) {
291 fprintf(stderr, "Line too long on line %d of %s\n",
292 linenumber, fileName);
298 for (cp = buf; *cp; cp++)
305 buf[strlen(buf) - 1] = 0;
306 varinfo[current_name++].name = strdup(buf);
313 wait_for_period(int period)
315 struct timeval m_time, *tv = &m_time;
318 static int target = 0;
321 gettimeofday(tv, (struct timezone *) 0);
326 memcpy(&tm, localtime((time_t *) & tv->tv_sec), sizeof(tm));
330 nexthour = mktime(&tm);
332 target = (nexthour - tv->tv_sec) % period;
335 target += tv->tv_sec;
338 tv->tv_sec = target - tv->tv_sec;
339 if (tv->tv_usec != 0) {
341 tv->tv_usec = 1000000 - tv->tv_usec;
343 if (tv->tv_sec < 0) {
345 * ran out of time, schedule immediately
352 count = select(0, 0, 0, 0, tv);
361 snmp_log_perror("select");
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;
382 struct counter64 c64value;
384 time_t last_time = 0;
387 int sum; /* what the heck is this for, its never used? */
388 char filename[128] = { 0 };
391 char timestring[64] = { 0 }, valueStr[64] = {
394 char outstr[256] = { 0 }, peakStr[64] = {
397 int begin, end, last_end;
401 switch (arg = snmp_parse_args(argc, argv, &session, "C:", &optProc)) {
411 gateway = session.peername;
413 for (; optind < argc; optind++)
414 varinfo[current_name++].name = argv[optind];
416 if (current_name == 0) {
422 varinfo[current_name++].name = 0;
428 * open an SNMP session
430 ss = snmp_open(&session);
433 * diagnose snmp_open errors with the input netsnmp_session pointer
435 snmp_sess_perror("snmpdelta", &session);
440 if (tableForm && timestamp) {
441 printf("%s", gateway);
443 for (count = 0; count < current_name; count++) {
444 vip = varinfo + count;
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) ==
450 snmp_perror(vip->name);
454 sprint_descriptor(vip->descriptor, vip);
456 printf("\t%s", vip->descriptor);
459 strcpy(vip->descriptor, SumFile);
462 zeroU64(&vip->c64value);
466 vip->peak_count = -1;
468 vip->peak_average = 0;
472 wait_for_period(period);
477 pdu = snmp_pdu_create(SNMP_MSG_GET);
480 snmp_add_null_var(pdu, sysUpTimeOid, sysUpTimeLen);
482 if (end == current_name)
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);
497 status = snmp_synch_response(ss, pdu, &response);
498 if (status == STAT_SUCCESS) {
499 if (response->errstat == SNMP_ERR_NOERROR) {
501 gettimeofday(&tv, (struct timezone *) 0);
502 memcpy(&tm, localtime((time_t *) & tv.tv_sec),
505 && (!peaks || ((period * peaks) % 60)))
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);
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;
519 fprintf(stderr, "Missing variable in reply\n");
522 this_time = *(vars->val.integer);
524 vars = vars->next_variable;
529 for (count = begin; count < end; count++) {
530 vip = varinfo + count;
534 fprintf(stderr, "Missing variable in reply\n");
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));
544 value = *(vars->val.integer) - vip->value;
545 vip->value = *(vars->val.integer);
547 vars = vars->next_variable;
552 delta_time = this_time - vip->time;
555 last_time = vip->time;
556 vip->time = this_time;
560 if (vip->oidlen && vip->type != ASN_COUNTER64) {
565 if (count == begin) {
566 sprintf(outstr, "%s", timestring + 1);
569 sprintf(outstr, "%s %s", timestring,
573 if (deltat || tableForm) {
574 if (vip->type == ASN_COUNTER64) {
576 "time delta and table form not supported for counter64s\n");
580 ((float) value * 100) / delta_time;
582 sprintf(valueStr, "\t%.2f", printvalue);
584 sprintf(valueStr, " /sec: %.2f",
588 printvalue = (float) value;
589 sprintf(valueStr, " /%d sec: ", period);
590 if (vip->type == ASN_COUNTER64)
591 printU64(valueStr + strlen(valueStr),
594 sprintf(valueStr + strlen(valueStr), "%u",
599 strcat(outstr, valueStr);
602 if (vip->peak_count == -1) {
603 if (wait_for_peak_start(period, peaks) == 0)
606 vip->peak_average += printvalue;
607 if (vip->peak < printvalue)
608 vip->peak = printvalue;
609 if (++vip->peak_count == peaks) {
612 " /sec: %.2f (%d sec Peak: %.2f)",
614 vip->peak_count, period,
618 " /%d sec: %.0f (%d sec Peak: %.0f)",
621 vip->peak_count, period,
623 vip->peak_average = 0;
627 strcat(outstr, peakStr);
633 if (printvalue > vip->max) {
634 vip->max = printvalue;
637 sprintf(maxStr, " (Max: %.2f)", vip->max);
639 sprintf(maxStr, " (Max: %.0f)", vip->max);
640 strcat(outstr, maxStr);
645 sprintf(filename, "%s-%s", gateway,
647 print_log(filename, outstr + 1);
650 printf("%s", outstr);
652 printf("%s\n", outstr + 1);
657 if (end == last_end && tableForm)
660 if (response->errstat == SNMP_ERR_TOOBIG) {
661 if (response->errindex <= varbindsPerPacket
662 && response->errindex > 0) {
663 varbindsPerPacket = response->errindex - 1;
665 if (varbindsPerPacket > 30)
666 varbindsPerPacket -= 5;
670 if (varbindsPerPacket <= 0) {
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++);
682 fprint_objid(stderr, vars->name,
684 fprintf(stderr, "\n");
686 * Don't exit when OIDs from file are not found on agent
691 fprintf(stderr, "Error in packet: %s\n",
692 snmp_errstring(response->errstat));
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);
710 } else if (status == STAT_TIMEOUT) {
711 fprintf(stderr, "Timeout: No Response from %s\n", gateway);
715 } else { /* status == STAT_ERROR */
716 snmp_sess_perror("snmpdelta", ss);
723 snmp_free_pdu(response);
724 if (end == current_name) {
725 wait_for_period(period);