/*+ $Header: /home/vikas/src/nocol/pingmon/RCS/poll_sites.c,v 1.23 1998/08/31 14:43:43 vikas Exp $ * */ /*+ * * FUNCTION * * This function pings all the sites and determines their status. * * It reads the site info from the output file and after pinging it, * writes the new status back in the file. It uses raw i/o. * * If the status remains DOWN during the next test of the * site, it raises the severity (it polls 7 sites a minute) * * Also, if previous status is same as present, it does not * change the time of test (thus the time is the time that the * site has been at the current status - useful for any other * program that needs to know status of the sites down). * * Does one pass over the entire file, returns -1 if error. * * -Vikas Aggarwal, vikas@navya.com * */ /* * $Log: poll_sites.c,v $ * Revision 1.23 1998/08/31 14:43:43 vikas * Changed multiping -qtc to -qntc to avoid using the DNS for inverse * lookups (slows down if nscd screws up). -limfung@pacific.net.sg * * Revision 1.22 1998/07/31 18:29:37 vikas * Rearranged the 'ifdefs' * * Revision 1.21 1994/06/17 16:16:54 vikas * Added small debug line to show status when site is down. * * Revision 1.20 1994/05/16 02:09:46 vikas * Added support for RPCping * * Revision 1.19 1994/01/10 20:49:34 aggarwal * Changed fgetline() to fgetLine() * * Revision 1.18 1993/10/30 03:16:11 aggarwal * Now uses the update_event() library call. * * Revision 1.17 1993/09/18 22:32:29 aggarwal * Added logging facilities. * * Revision 1.16 1992/06/18 21:14:17 aggarwal * Added code for 'multiping'. Also added macros for increasing * severity. * * Revision 1.15 1992/05/13 16:09:15 aggarwal * Changed the nocol.h struct so that addr is now a char[] instead of * inet_addr. Altered this file to match change. * * Revision 1.7 89/12/19 10:43:54 network * The location of 'ping' should be explicitly defined or else * the path should include '/etc' before calling the program * else the shell does not find 'ping' and all the sites show * down. * * Revision 1.6 89/11/27 17:08:10 aggarwal * Added macro 'ESC_SEVERITY' to escalate the severity. * Shifted around the 'case DOWN' statements a bit since the * state was being changed before the 'if' test making it * kinda redundant. * * Revision 1.1 89/11/08 12:09:55 aggarwal * Initial revision * */ #include "pingmon.h" #include #include static char pingcmd[BUFSIZ]; /* the ping command used */ static int maxseverity = E_CRITICAL ; /* Max severity of pingmon events */ /* #defines for finish_status */ #define REACHED_EOF 1 #define READ_ERROR 2 poll_sites(fdout) int fdout; /* Descriptors to open files */ { extern int debug; /* Enable debug (in pingmon.h) */ static FILE *p_cmd; /* for creating the ping cmd */ static int batchsize = BATCHSIZE ; /* num of sites to ping at a time */ EVENT v[BATCHSIZE]; /* described in nocol.h */ char line[BUFSIZ]; /* to create the ping command */ struct tm *ltime ; time_t locclock ; /* careful: don't use 'long' */ int status; /* site status */ int sent, recv, bufsize; /* received response */ int i, numsites ; /* actual number of sites read in */ int finish_status = 0; /* why we stopped */ if ( lseek(fdout, (off_t)0, SEEK_SET) == -1) /* rewind the file */ { perror (prognm); return (-1); } while (!finish_status) /* until end of all sites... */ { char sites[BUFSIZ] ; /* for list of sites to ping */ *sites = '\0' ; /* try to read in as many sites as we can, up to batchsize */ for (numsites = 0; numsites < batchsize; numsites++) { bufsize = read(fdout, &v[numsites], sizeof(EVENT)); if (bufsize != sizeof(EVENT)) { finish_status = bufsize ? READ_ERROR : REACHED_EOF; break; } else strcat(strcat(sites, " "), v[numsites].site.addr); } /* end for */ if (!numsites) /* means something bad happened, or EOF */ continue; /* ...next while statement, finish_stat set */ /* * The ping command for 'multiping' is different from the standard. * Hence the 'ifdef'. It allows for the -t and -q options. */ #ifdef IPPING # ifdef MULTIPING /* * multiping -q (quiet) -c -s -t (tabular) sites * * For tabular output, data is separated by a line, so use the * sed command to chop off top portion. */ /* * the output from ping looks something like this: * * PING 128.121.50.145 (128.121.50.145): 56 data bytes * PING 128.121.50.147 (128.121.50.147): 56 data bytes * PING 128.121.50.140 (128.121.50.140): 56 data bytes * * -=-=- PING statistics -=-=- * Number of Packets * Remote Site Sent Rcvd Rptd Lost * ----------------------------- ------ ------ ------ ---- * 128.121.50.145 10 10 0 0% * 128.121.50.147 10 10 0 0% * 128.121.50.140 10 10 0 0% * ----------------------------- ------ ------ ------ ---- * TOTALS 30 30 0 0% * * (I've cut off the right part of the screen to make it fit) * the sed command below kills everything up to and including the * first row of dashes ---- * * The site name is printed as %30.30 (30 spaces) */ sprintf(pingcmd, "%s -qtnc %d -s %d %s | %s\0", ping, NPACKETS, DATALEN, sites, "sed '1,/^-----/d'") ; # else /* not MULTIPING */ /* * A typical (standard) 'ping | tail -2' output looks like this: * * If you have a different style ping command format and output, then * alter here. * * nutty> /usr/etc/ping | tail -2 * 5 packets transmitted, 5 packets received, 0% packet loss * round-trip (ms) min/avg/max = 4/4/5 */ # if defined(SUNOS4) || defined(SUNOS5) sprintf(pingcmd,"%s -s %s %d %d 2>&1 | grep transmitted\0", ping, sites, DATALEN, NPACKETS); # else # if defined(HPUX) || defined(ULTRIX) sprintf(pingcmd,"%s %s %d %d | grep transmitted \0", ping, sites, DATALEN, NPACKETS); # else /* for FreeBSD2, Linux1, Linux2, Irix, OSF1, AIX */ sprintf(pingcmd,"%s -c %d -s %d %s | grep transmitted\0", ping, NPACKETS, DATALEN, sites); # endif # endif # endif /* MULTIPING */ #endif /* IPPING */ #ifdef RPCPING sprintf(pingcmd, "%s -t %d %s\0", ping, RPCTIMEOUT, sites); #endif #ifdef OSIPING /* * A typical (standard) 'ping | tail -2' output looks like this: * * solaris> /usr/etc/osiping -s xyz.com 1000 5 | tail -2 * 5 packets transmitted, 5 packets received, 0% packet loss * round-trip (ms) min/avg/max = 4/4/5 */ sprintf(pingcmd,"%s -s %s %d %d | %s\0", ping, sites, DATALEN, NPACKETS, "tail -2" ); #endif /* OSIPING */ if (debug) fprintf(stderr, "(debug) %s: PINGCMD is\t%s\n", prognm, pingcmd) ; if ((p_cmd = popen(pingcmd, "r")) == NULL) /* open up the pipe */ { perror("poll_sites (popen)"); return(-1); } /* * 'multiping' produces output lines in the order in which they * appeared in the command line, so we can just step thru the v[] * array. * After reading each line, update the corresponding event struct */ for (i = 0; i < numsites; i++) { int n ; n = fgetLine(p_cmd, line, sizeof (line)); #ifdef RPCPING if (strstr(line, "is running")) /* output from rpcping */ status = 1 , recv = 1; else status = 0, recv = 0; #endif #if defined(OSIPING) || defined(IPPING) # ifdef MULTIPING /* * The output after 30 characters has pkts sent and recieved * Can't use '%*s' to skip over the sitename since sometimes * the sitename gets truncated and we end up with two words. * The '30' size is defined in the multiping program (yeah, so * its a hack.) */ sscanf(&line[30], "%*d %d", &recv); status = (NPACKETS - recv) > PING_THRES ? 0 : 1 ; # else /* * Trying to scan line of the form: * 10 packets transmitted, 1 packets received, 90% packet loss * round-trip (ms) min/avg/max = 2/2/3 */ sscanf (line, "%d %*s %*s %d", &sent, &recv); if (sent != NPACKETS) /* Error of some sort */ { if (debug) fprintf (stderr,"ERROR %s: (poll_sites) Sent %d != recvd %d\n", NPACKETS, sent); recv = 0 ; status = 0 ; } else status = ((NPACKETS - recv) > PING_THRES) ? 0 : 1 ; # endif /* MULTIPING */ #endif /* defined OSIPING or IPPING */ if (debug && status == 0) fprintf(stderr,"(debug) %s: status is %d\n", prognm, status); update_event(&(v[i]), status, /* VALUE */ (u_long)recv, maxseverity); } /* end for */ if (pclose(p_cmd) < 0) /* close the pipe */ perror("poll_sites (pclose)"); /* rewind the file and write out the whole array */ lseek(fdout, -(off_t)(sizeof(EVENT) * numsites), SEEK_CUR); write(fdout, (char *)v, sizeof(EVENT) * numsites); } /* end while (until end of all sites) */ return (finish_status != REACHED_EOF) ? -1 : 1; } /* end poll_sites */