sources-request@mirror.UUCP (10/24/86)
Submitted by: alasdair@ux.cs.man.ac.uk Mod.sources: Volume 7, Issue 37 Archive-name: hostup [ This program can be very expensive to run. -r$ ] Inspired by the Tektronix TCP/IP 'hostup' command, I've done an equivalent thing for 4.[23] UNIX. Tried and tested on a 4.3 Beta Vax8600, and SUN3 version 3.0. It's primitive stuff, so feel free to enhance it to suit your own needs! Alasdair #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # hostup.1 # Makefile # hostup.c # hostup.h # hostupd.c # This archive created: Sat Sep 6 16:01:51 1986 export PATH; PATH=/bin:$PATH echo shar: extracting "'hostup.1'" '(1386 characters)' if test -f 'hostup.1' then echo shar: will not over-write existing file "'hostup.1'" else cat << \SHAR_EOF > 'hostup.1' .TH HOSTUP l "6 September 1986" .SH NAME hostup, hostupd \- network status report .SH SYNOPSIS .B hostup .SH DESCRIPTION .I hostup prints a list of network node names, with an indication of their reachability. It relies on a copy of .I hostupd running: .I hostupd polls machines in the /etc/hosts file and maintains a binary file of its results. .PP .I hostupd polls each machine by attempting to .IR connect (2) to an unused TCP port, and logging the type of error returned. This mechanism is a useful alternative to .IR ruptime (1), as it works with non-BSD machines, as well as with machines not running the ruptime daemon (such as diskless .B SUN workstations). .SH "SEE ALSO" ruptime(1) .br connect(2) .SH BUGS The polling process is .B slow (taking perhaps 75 minutes to complete one poll of the internal network at Manchester at weekends, when most machines are switched off) as it depends upon the .IR connect (2) timeout for each machine that is down. .PP .I hostupd currently sleeps for 5 minutes every time round the loop of machines: this is not strictly necessary if enough machines are down! .PP For machines connected to the Internet, polling every machine in /etc/hosts is probably a mistake. .PP The order of polling and the format of displaying the hosts is optimised for my network and my convenience. .SH AUTHOR Alasdair Rawsthorne (arawsthorne@uk.ac.man.cs.ux). SHAR_EOF if test 1386 -ne "`wc -c < 'hostup.1'`" then echo shar: error transmitting "'hostup.1'" '(should have been 1386 characters)' fi fi # end of overwriting check echo shar: extracting "'Makefile'" '(119 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' hostup: hostup.c hostup.h cc -O -o hostup hostup.c -ltermcap hostupd: hostupd.c hostup.h cc -O -o hostupd hostupd.c SHAR_EOF if test 119 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 119 characters)' fi fi # end of overwriting check echo shar: extracting "'hostup.c'" '(2480 characters)' if test -f 'hostup.c' then echo shar: will not over-write existing file "'hostup.c'" else cat << \SHAR_EOF > 'hostup.c' #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/time.h> #include "hostup.h" #define FIELDWIDTH 11 FILE *f; /* input file */ struct timeval first, last; /* GMT of polls */ struct timezone timezone; /* my offset */ char * timeof(); int currentpos = 0, width = 80; /* for formatting screen */ char tbuf[1024]; u_long lastnetwork = 0; struct perhost thishost; main() { long seconds; int cols; u_long network; if (tgetent(tbuf, getenv("TERM")) == 1) { if ((cols = tgetnum("co")) > 0) { width = cols; } } if ((f = fopen(FILENAME, "r")) == NULL) { perror(FILENAME); exit(1); } gettimeofday(&first, &timezone); last.tv_sec = 0; while (fread(&thishost, sizeof(thishost), 1, f) == 1) { network = ntohl(thishost.ph_to.sin_addr.s_addr); if (IN_CLASSA(network)) { network &= IN_CLASSA_NET; } else if (IN_CLASSB(network)) { network &= IN_CLASSB_NET; } else { network &= IN_CLASSC_NET; } if (network != lastnetwork) { lastnetwork = network; donl(); } printstat(thishost.ph_name, thishost.ph_result); seconds = thishost.ph_time.tv_sec; if (first.tv_sec > seconds) { first.tv_sec = seconds; } if (last.tv_sec < seconds) { last.tv_sec = seconds; } } donl(); printf("Polled from %s", timeof(&first)); printf(" to %s; KEY: ", timeof(&last)); printstat("Up", ECONNREFUSED); printstat("Down", ETIMEDOUT); printstat("UnReachable", ENETUNREACH); donl(); exit(0); } char * timeof(tp) struct timeval *tp; { char *rp; struct tm *tm; tm = localtime(&tp->tv_sec); rp = asctime(tm); rp[19] = '\0'; /* truncate before timezone */ return(rp + 11); /* return just the time */ } printstat(name, errno) char *name; { int up = 0; char extra = ' '; switch(errno) { case ECONNREFUSED: up = 1; break; case 0: up = 1; extra = '!'; break; case ETIMEDOUT: break; case ENETUNREACH: extra = '-'; break; default: extra = '?'; break; } if (up) { printf(" %s%c ", name, extra); } else { printf("(%s)%c", name, extra); } if (currentpos > (width - (2 * FIELDWIDTH))) { donl(); } else { int i; currentpos += FIELDWIDTH; for (i = strlen(name)+3; i < FIELDWIDTH; i++) { putchar(' '); } } } donl() { if (currentpos) { putchar('\n'); } currentpos = 0; } SHAR_EOF if test 2480 -ne "`wc -c < 'hostup.c'`" then echo shar: error transmitting "'hostup.c'" '(should have been 2480 characters)' fi fi # end of overwriting check echo shar: extracting "'hostup.h'" '(186 characters)' if test -f 'hostup.h' then echo shar: will not over-write existing file "'hostup.h'" else cat << \SHAR_EOF > 'hostup.h' #define MAXHOSTCHARS 12 #define FILENAME "/usr/adm/host up" struct perhost { char ph_name[MAXHOSTCHARS]; struct sockaddr_in ph_to; struct timeval ph_time; int ph_result; }; SHAR_EOF if test 186 -ne "`wc -c < 'hostup.h'`" then echo shar: error transmitting "'hostup.h'" '(should have been 186 characters)' fi fi # end of overwriting check echo shar: extracting "'hostupd.c'" '(2349 characters)' if test -f 'hostupd.c' then echo shar: will not over-write existing file "'hostupd.c'" else cat << \SHAR_EOF > 'hostupd.c' #include <stdio.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #define HISPORT 919 /* 'cos that's what tektronix use */ #define MAXHOSTS 200 #define SLEEPTIME 300 /* 5 mins wait at end of loop */ #include "hostup.h" extern int errno; struct hostent *gethostent(), *host; int inetcomp(); int s; /* socket number */ FILE *f; /* output file */ struct timezone timezone; /* somewhere to ignore it */ struct perhost thishost[MAXHOSTS]; int nohosts = 0; main() { if ((f = fopen(FILENAME, "w")) == NULL) { perror(FILENAME); exit(1); } readhosts(); /* find a table of hosts to poll */ #ifndef DEBUG if (fork()) exit(0); { int s; for (s = 0; s < 10; s++) if (s != fileno(f)) (void) close(s); (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2); s = open("/dev/tty", 2); if (s >= 0) { ioctl(s, TIOCNOTTY, 0); (void) close(s); } } #endif while(1) { fseek(f, 0L, 0); /* keep writing from start */ pollhosts(); sleep(SLEEPTIME); } } readhosts() { while ((host = gethostent()) != NULL) { strncpy(thishost[nohosts].ph_name, host->h_name, MAXHOSTCHARS); thishost[nohosts].ph_name[MAXHOSTCHARS-1] = '\0'; bzero((char *)&thishost[nohosts].ph_to, sizeof(thishost[nohosts].ph_to)); bcopy(host->h_addr, (char *)&thishost[nohosts].ph_to.sin_addr, host->h_length); thishost[nohosts].ph_to.sin_family = host->h_addrtype; thishost[nohosts].ph_to.sin_port = HISPORT; nohosts++; if (nohosts == MAXHOSTS) break; } endhostent(); qsort(thishost, nohosts, sizeof(thishost[0]), inetcomp); } inetcomp(a, b) struct perhost *a, *b; { return(ntohl(a->ph_to.sin_addr.s_addr) - ntohl(b->ph_to.sin_addr.s_addr)); } pollhosts() { int i; for (i = 0; i < nohosts; i++) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { #ifdef DEBUG perror("socket:"); #endif exit(1); } if (connect(s, (char *)&thishost[i].ph_to, sizeof(thishost[i].ph_to)) < 0) { thishost[i].ph_result = errno; } else { thishost[i].ph_result = 0; } gettimeofday(&thishost[i].ph_time, &timezone); fwrite(&thishost[i], sizeof(thishost[i]), 1, f); fflush(f); (void) close(s); /* ! */ } } SHAR_EOF if test 2349 -ne "`wc -c < 'hostupd.c'`" then echo shar: error transmitting "'hostupd.c'" '(should have been 2349 characters)' fi fi # end of overwriting check # End of shell archive exit 0