📄 sntop.c
字号:
/* * sntop - simple network top - a top-like console network status tool * sntop.c * 04.30.2000 - 03.21.2001 * * robert m love <rml@tech9.net> * chris m rivera <cmrivera@ufl.edu> * * http://sntop.sourceforge.net - homepage * ftp://sntop.sourceforge.net/pub/sntop/ - anon ftp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, v2, as * published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Copyright (C) 2001 Robert M. Love and Christopher M. Rivera * * All code by the above authors unless otherwise specified. */#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/time.h>#include <fcntl.h>#include <string.h>#include <errno.h> #include <signal.h> #include <ncurses.h>#if HAVE_SYS_WAIT_H#include <sys/wait.h>#endif /* HAVE_SYS_WAIT_H */#ifndef WEXITSTATUS#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)#endif /* WEXITSTATUS */#ifndef WIFEXITED#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)#endif /* WIFEXITED */#if HAVE_GETOPT_LONG#include <getopt.h>#else#include "getopt_long.h"#endif /* HAVE_GETOPT_LONG */#include "sntop.h"#define SNTOP_VERSION "sntop v1.4.3"int main(int argc, char *argv[]){ char up_status[] = UP; char down_status[] = DOWN; char buf[IN_BUF + PING_BUF + PEND_BUF]; char cfile[CONF_BUF]; char hfile[CONF_BUF] = HTML_FILE; /* Default to FPING_LINE */ char ping[PING_BUF + 1] = FPING_LINE; char action[ACTION_BUF]; char ch; FILE *hf = NULL; fd_set readfds; struct timeval timeout; hdc *head = NULL, *current = NULL; unsigned int up; unsigned int refresh = REFRESH_TIME; unsigned int i; unsigned short int val; unsigned int bold_attribute = 0; /* no bold if no color */ unsigned short flags = DO_COLOR; struct option longopts[] = { { "once", 0, 0, 'o' }, { "nocolor", 0, 0, 'c' }, { "ping", 0, 0, 'p' }, { "html", 0, 0, 'w' }, { "secure", 0, 0, 's' }, { "wfile", 1, 0, 'e' }, { "refresh", 1, 0, 'r' }, { "version", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { "conf", 1, 0, 'f' }, { "alarm", 1, 0, 'a' }, { "log", 1, 0, 'l' }, { "byte", 1, 0, 'b' }, { "daemon", 0, 0, 'd' }, { 0, 0, 0, 0 } }; /* we need to construct the user's home, for the conf file, now, so we can change it with -f in the following getopt loop */ snprintf(cfile, CONF_BUF, "%s%s", getenv("HOME"), CONF_UFILE); while((i = getopt_long(argc, argv, "docpwse:f:r:vhb:a:l:", longopts, (int *) 0)) != -1) { switch(i) { case 'd': flags ^= DAEMON; break; case 'o': flags ^= DO_ONCE; refresh = 0; break; case 'c': flags ^= DO_COLOR; break; case 'p': strcpy(ping, PING_LINE); break; case 'w': flags ^= DO_HTML; break; case 's': flags ^= SECURE_MODE; break; case 'e': strncpy(hfile, optarg, CONF_BUF); break; case 'f': strncpy(cfile, optarg, CONF_BUF); break; case 'r': refresh = atoi(optarg); break; case 'a': flags ^= DO_ALARM; strncpy(action, optarg, ACTION_BUF); break; case 'l': flags ^= DO_LOG; strncpy(action, optarg, ACTION_BUF); break; case 'v': printf("\r" SNTOP_VERSION); printf(" - a top-like console network status monitor\n" SNTOP_AUTHORS "\n"); exit(EXIT_SUCCESS); break; case 'b': snprintf(ping, PING_BUF, "fping -r 1 -b %d -q", atoi(optarg)); break; case ':': case '?': case 'h': printf("\r" SNTOP_VERSION ": " SNTOP_AUTHORS "\n\n"); printf("Usage: %s [FLAG(S)...]\n\n", argv[0]); printf(" -d, --daemon allow use as a daemon\n"); printf(" -o, --once poll and display once, then exit\n"); printf(" -c, --nocolor disable use of ncurses' color\n"); printf(" -p, --ping use 'ping' in lieu of 'fping'. MUCH SLOWER!\n"); printf(" -w, --html generate html output of results\n"); printf(" -s, --secure secure mode: interactive commands are disabled\n"); printf(" -e, --wfile=file output html to <file> instead of " HTML_FILE "\n"); printf(" -f, --conf=file read conf data from <file> instead of ~" CONF_UFILE ".\n"); printf(" note, sntop will still try to read from\n"); printf(" %s if <file> fails\n", CONF_SFILE); printf(" -r, --refresh=time refresh every <time> seconds instead of every %d\n", REFRESH_TIME); printf(" -a, --alarm=action when a site goes down, execute action\n"); printf(" -l, --log=action when a site changes status, execute action\n"); printf(" -b, --byte=bytes bytes of ping data to send\n"); printf(" -v, --version display version information and exit\n"); printf(" -h, --help display this help and exit\n"); printf("\nSee 'man sntop'\n"); exit(EXIT_SUCCESS); break; } } signal(SIGINT, aborted); load_config(cfile, &head); if (!(flags & DAEMON)) { printf(SNTOP_VERSION " - loading ... "); initscr(); /* color code orig. by Ron Cooper <rcooper@crstexas.com> 20001024 */ if ((flags & DO_COLOR) && has_colors()) { start_color(); bold_attribute = A_BOLD; /* remap all colors onto a black background */ init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK); init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK); init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK); init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK); init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK); init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); } attrset(COLOR_PAIR(COLOR_YELLOW) | bold_attribute); printw("(sntop) simple network top\n"); standout(); printw("%-16s %-12s %-32s\n", "HOST", "STATUS", "COMMENT"); standend(); } do { if (!(flags & DAEMON)) { move(2, 0); clrtobot(); } current = head; i = up = 0; if (flags & DO_HTML) start_html(hfile, &hf, refresh); do { sprintf(buf, "%s %s %s", ping, current->host, PING_END); val = sntop_exec(buf); if (val == 127) { abortion("error, execution of (f)ping failed", 6); } else if (val == 0) { /* site is up */ if ((flags & DO_LOG) && (current->status == down_status)) exec_alarm(action, current->name, current->host, up_status); current->status = up_status; if (!(flags & DAEMON)) attrset(COLOR_PAIR(COLOR_GREEN) | bold_attribute); up++; } else { /* site is down */ if (((flags & DO_ALARM) || (flags & DO_LOG)) && (current->status == up_status)) exec_alarm(action, current->name, current->host, down_status); current->status = down_status; if (!(flags & DAEMON)) attrset(COLOR_PAIR(COLOR_RED) | bold_attribute); } if (!(flags & DAEMON)) printw("%-16s %-12s %-32s\n", current->name, current->status, current->note); if (flags & DO_HTML) add_html(hf, current->name, current->status, current->note); i++; current = current->next; } while(current->next != NULL); if (!(flags & DAEMON)) { attrset(COLOR_PAIR(COLOR_CYAN) | bold_attribute); printw("\n\n%u hosts polled: %u up, %u down", i, up, i - up); attrset(COLOR_PAIR(COLOR_YELLOW) | bold_attribute); refresh(); } if (flags & DO_HTML) end_html(hf, i, up); if (!(flags & DAEMON)) { /* we use select() to sleep for REFRESH seconds or until a key is pressed */ FD_ZERO(&readfds); FD_SET(0, &readfds); timeout.tv_sec = refresh; timeout.tv_usec = 0; if (select(1, &readfds, NULL, NULL, &timeout) > 0) { if (read(0, &ch, 1) != 1) abortion("error, stdin cannot be read", 4); if (!(flags & SECURE_MODE)) { switch (ch) { case 'q': flags ^= DO_ONCE; break; case 'r': printw("\nreloading conf data..."); refresh(); load_config(cfile, &head); printw("done\nrefreshing..."); refresh(); break; case 'w': flags ^= DO_HTML; load_config(cfile, &head); printw("\nhtml generation toggled %s", (flags & DO_HTML) ? "ON" : "OFF"); refresh(); break; default: printw("\nrefreshing..."); refresh(); } } } } else sleep(refresh); } while(!(flags & DO_ONCE)); if (!(flags & DAEMON)) endwin(); exit(EXIT_SUCCESS);}/* * a replacement for my nemesis, fgets() ... reads from f into s, stopping * at n-1 bytes, d, or EOF. clears the remaining line so future reads * start on newline. ignores inline comments, and removes trailing * whitespace. returns upto n bytes in s, with d stripped and \0 appended.; */char * get(char *s, int n, char d, FILE *f){ int c = 0; char *cs = s; while(--n > 0 && (c = getc(f)) != EOF && (*cs++ = c) != d && c != '#') ; if (c == d || c == '#') *--cs = '\0'; else *cs = '\0'; /* remove trailing whitespace */ cs = strchr(s, '\0'); while (*--cs == ' ' || *cs == '\t') /* nop */ ; *++cs = '\0'; while (c != '\n' && c != EOF) c = getc(f); /* clear the line */ return (c == EOF) ? NULL : s;}void abortion(const char *msg, int type){ endwin(); fprintf(stderr, "sntop: %s\n", msg); exit(type);}RETSIGTYPE aborted(int ignore) { abortion("caught SIGINT -- aborted", 5); }/* * glibc's system() disables interrupt signals which is a pretty evil * thing to do, especially in a loop, as we cant break out. * * we return 127 on error, as this is what waitpid's status will show * on error since it is unsigned, so we can check against a single value */unsigned short int sntop_exec(char *command){ extern char **environ; int pid, status; pid = fork(); if (pid == -1) return 127; if (pid == 0) { char * argv[4]; argv[0] = "sh"; argv[1] = "-c"; argv[2] = command; argv[3] = NULL; execve("/bin/sh", argv, environ); exit(127); } while(1) { if (waitpid(pid, &status, 0) == -1) return 127; else if (WIFEXITED(status)) return WEXITSTATUS(status); else return 127; }}void load_config(char *cfile, hdc **head){ char *field[3]; char buf[IN_BUF]; char up_status[] = UP; int i; FILE *cf; hdc *current = NULL, *last = NULL; if ((cf = fopen(cfile, "r")) == NULL) { /* lets try opening the system-wide conf file, then */ strncpy(cfile, CONF_SFILE, CONF_BUF); if ((cf = fopen(cfile, "r")) == NULL) abortion("error, cannot open systen or user conf file", 1); } if ((*head) != NULL) { /* if we are called a subsequent time, we free() first */ current = (*head); do { last = current->next; free(current); current = last; } while (current != NULL); (*head) = NULL; } while (!feof(cf)) { if ((current = malloc(sizeof(hdc))) == NULL) abortion("error, malloc() returned NULL", 2); i = 0; field[0] = current->name; field[1] = current->host; field[2] = current->note; if ((*head) == NULL) { (*head) = current; last = current; } last->next = current; last = current; current->next = NULL; current->status = up_status; while(i < 3) { if (get(buf, IN_BUF, '\n', cf) == NULL) break; if (buf[0]) strncpy(field[i++], buf, IN_BUF); } } fclose(cf);}/* written 30,000ft in the air */void exec_alarm(char *command, char *name, char *host, char *status){ extern char **environ; int pid; pid = fork(); if (pid == -1) return; if (pid == 0) { char *argv[5]; argv[1] = name; argv[2] = host; argv[3] = status; argv[4] = NULL; if (execve(command, argv, environ) == -1) abortion("error executing alarm command", 7); }}void start_html(char *file, FILE **hf, unsigned int refresh){ if (((*hf) = fopen(file, "w")) == NULL) abortion("error, cannot open html file", 3); fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", (*hf)); fputs("<HTML>\n<HEAD>\n", (*hf)); if (refresh) fprintf((*hf), "<META http-equiv=\"Refresh\" content=\"%d\">\n", refresh); fputs("<TITLE>sntop network status</TITLE>\n</HEAD>\n", (*hf)); fputs("<BODY TEXT=\"#000000\" BGCOLOR=\"#FFFFFF\">\n\n", (*hf)); fputs("<P><B>sntop network status - automatically generated html</B></P><BR>\n\n", (*hf)); fputs("<TABLE BORDER CELLPADDING=5>\n<TR VALIGN=top>\n", (*hf)); fputs("<TD BGCOLOR=#EEEEEE><B>Host</B></TD>\n<TD BGCOLOR=#EEEEEE>", (*hf)); fputs("<B>Status</B></TD>\n<TD BGCOLOR=#EEEEEE><B>Comments</B></TD>\n", (*hf)); fputs("</TR>\n", (*hf));}void add_html(FILE *hf, char *name, char *status, char *comments){ fprintf(hf, "<TR>\n<TD BGCOLOR=#EEEEEE>%s</TD>\n", name); fprintf(hf, "<TD BGCOLOR=#EEEEEE><B><FONT COLOR=%s", strcmp(status, UP) ? HTML_DOWN : HTML_UP); fprintf(hf, "</FONT></B></TD>\n<TD BGCOLOR=#EEEEEE>%s</TD>\n", comments);}void end_html(FILE *hf, unsigned int hosts, unsigned int up) { extern char *tzname[2]; time_t t; char *s; fputs("</TABLE>\n\n", hf); fprintf(hf, "<P><B>%u</B> hosts polled: <B>%u</B> up, <B>%u</B> down</P><BR>\n\n", hosts, up, hosts - up); /* ok, so these sanity checks are a bit much -- but they arent overkill */ if (time(&t) != (time_t) -1) if ((s = ctime(&t)) && tzname[0]) fprintf(hf, "<P><SMALL>Last updated: %s %s</SMALL></P>\n\n", s, tzname[0]); fputs("<P><SMALL>Generated by <A HREF=\"http://sntop.sourceforge.net\">", hf); fputs(SNTOP_VERSION "</A> - " SNTOP_AUTHORS "</SMALL></P>\n\n", hf); fputs("</BODY>\n</HTML>", hf); fclose(hf);}/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -