diff options
Diffstat (limited to 'src/pmdas/cisco/probe.c')
-rw-r--r-- | src/pmdas/cisco/probe.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/src/pmdas/cisco/probe.c b/src/pmdas/cisco/probe.c new file mode 100644 index 0000000..5cd5b4d --- /dev/null +++ b/src/pmdas/cisco/probe.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2012 Red Hat. + * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <fcntl.h> +#include <syslog.h> +#include "./cisco.h" + +int port = 23; +int seen_fr = 0; +char *prompt = ">"; /* unique suffix to IOS prompt */ + +char * +mygetfirstwd(FILE *f) +{ + char *p; + int c; + char line[1024]; + char *lp; + + for ( ; ; ) { + c = fgetc(f); + if (c == EOF) + break; + if (c == '\r' || c == '\n') + continue; + if (c != ' ') { + ungetc(c, f); + break; + } + lp = line; + while ((c = fgetc(f)) != EOF) { + *lp++ = c; + if (c == '\r' || c == '\n') { + *lp = '\0'; + break; + } + } + /* + * some interesting things to look for here ... + */ + if (strncmp(&line[1], "Encapsulation FRAME-RELAY", strlen("Encapsulation FRAME-RELAY")) == 0) { + seen_fr = 1; + } + } + /* either EOF, or line starts with a non-space */ + + p = mygetwd(f, prompt); + + if (p != NULL && (strlen(p) < strlen(prompt) || + strcmp(&p[strlen(p)-strlen(prompt)], prompt)) != 0) { + /* skip to end of line, ready for next one */ + while ((c = fgetc(f)) != EOF) { + if (c == '\r' || c == '\n') + break; + } + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "mygetfirstwd: %s\n", p == NULL ? "<NULL>" : p); +#endif + + return p; +} + +#define PREAMBLE 1 +#define IN_BODY 2 + +static void +probe_cisco(cisco_t * cp) +{ + char *w; + int fd; + int fd2; + int first = 1; + char *pass = NULL; + int defer = 0; + int state = PREAMBLE; + int i; + int namelen; + char *ctype = NULL; + char *name = NULL; + + if (cp->fin == NULL) { + fd = conn_cisco(cp); + if (fd == -1) { + fprintf(stderr, "grab_cisco(%s): connect failed: %s\n", + cp->host, osstrerror()); + return; + } + else { + cp->fin = fdopen (fd, "r"); + if ((fd2 = dup(fd)) < 0) { + perror("dup"); + exit(1); + } + cp->fout = fdopen (fd2, "w"); + if (cp->username != NULL) { + /* + * Username stuff ... + */ + if (dousername(cp, &pass) == 0) { + exit(1); + } + } + if (cp->passwd != NULL) { + /* + * User-level password stuff ... + */ + if (dopasswd(cp, pass) == 0) { + exit(1); + } + } + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: \n"); + fprintf(stderr, "Send: terminal length 0\n"); + } +#endif + fprintf(cp->fout, "\n"); + fflush(cp->fout); + fprintf(cp->fout, "terminal length 0\n"); + fflush(cp->fout); + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: show int\n"); + } +#endif + fprintf(cp->fout, "show int\n"); + fflush(cp->fout); + + } + else { + /* + * parsing text from a file, not a TCP/IP connection to a + * Cisco device + */ + ; + } + + for ( ; ; ) { + w = mygetfirstwd(cp->fin); + if (defer && ctype != NULL && name != NULL) { + if (seen_fr) { + if (first) + first = 0; + else + putchar(' '); + printf("%s%s", ctype, name); + free(name); + name = NULL; + } + } + defer = 0; + if (w == NULL) { + /* + * End of File (telenet timeout?) + */ + fprintf(stderr, "grab_cisco(%s): forced disconnect fin=%d\n", + cp->host, fileno(cp->fin)); + return; + } + if (*w == '\0') + continue; + if (state == PREAMBLE) { + if (strcmp(w, "show") == 0) + state = IN_BODY; + else if (strcmp(w, PWPROMPT) == 0) { + fprintf(stderr, + "Error: user-level password required for \"%s\"\n", + cp->host); + exit(1); + } + continue; + } + else { + if (strlen(w) >= strlen(prompt) && + strcmp(&w[strlen(w)-strlen(prompt)], prompt) == 0) + break; + ctype = NULL; + for (i = 0; i < num_intf_tab; i++) { + namelen = strlen(intf_tab[i].name); + if (strncmp(w, intf_tab[i].name, namelen) == 0) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "Match: if=%s word=%s\n", intf_tab[i].name, w); + } +#endif + name = strdup(&w[namelen]); + ctype = intf_tab[i].type; + if (intf_tab[i].type != NULL && strcmp(intf_tab[i].type, "a") == 0) { + /* + * skip ATMN.M ... need ATMN + */ + if (strchr(&w[namelen], '.') != NULL) + ctype = NULL; + } + else if (intf_tab[i].type != NULL && strcmp(intf_tab[i].type, "s") == 0) { + /* + * skip SerialN.M ... need SerialN, unless frame-relay + */ + if (strchr(&w[namelen], '.') != NULL) + defer = 1; + } + break; + } + } + if (i == num_intf_tab) + fprintf(stderr, "%s: Warning, unknown interface: %s\n", pmProgname, w); + if (ctype != NULL && name != NULL && !defer) { + if (first) + first = 0; + else + putchar(' '); + printf("%s%s", ctype, name); + free(name); + name = NULL; + } + } + } + putchar('\n'); + + /* close CISCO telnet session */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: exit\n"); + } +#endif + fprintf(cp->fout, "exit\n"); + fflush(cp->fout); + + return; +} + +int +main(int argc, char **argv) +{ + int errflag = 0; + int Nflag = 0; + int c; + int sts; + char *endnum; + char *passwd = NULL; + char *username = NULL; + __pmHostEnt *hostInfo = NULL; + + __pmSetProgname(argv[0]); + + while ((c = getopt(argc, argv, "ND:P:s:U:x:?")) != EOF) { + switch (c) { + + case 'N': /* check flag */ + Nflag = 1; + break; + + case 'D': /* debug flag */ + sts = __pmParseDebug(optarg); + if (sts < 0) { + fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", + pmProgname, optarg); + errflag++; + } + else + pmDebug |= sts; + break; + + case 'P': /* passwd */ + passwd = optarg; + break; + + case 's': /* prompt */ + prompt = optarg; + break; + + case 'U': /* username */ + username = optarg; + break; + + case 'x': + port = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -x requires numeric argument\n", + pmProgname); + errflag++; + } + break; + + case '?': + errflag++; + } + } + + if (errflag || optind != argc-1) { + fprintf(stderr, "Usage: %s [-U username] [-P passwd] [-s prompt] [-x port] host\n\n", pmProgname); + exit(1); + } + + if (!Nflag) + hostInfo = __pmGetAddrInfo(argv[optind]); + + if (hostInfo == NULL) { + FILE *f; + + if ((f = fopen(argv[optind], "r")) == NULL) { + fprintf(stderr, "%s: unknown hostname or filename %s: %s\n", + pmProgname, argv[optind], hoststrerror()); + exit(1); + } + else { + cisco_t c; + + fprintf(stderr, "%s: assuming file %s contains output from \"show int\" command\n", + pmProgname, argv[optind]); + + c.host = argv[optind]; + c.username = NULL; + c.passwd = NULL; + c.fin = f; + c.fout = fopen("/dev/null", "w"); + c.prompt = prompt; + + probe_cisco(&c); + } + } else { + cisco_t c; + + c.host = argv[optind]; + c.username = username; + c.passwd = passwd; + c.fin = NULL; + c.fout = NULL; + c.prompt = prompt; + c.hostinfo = hostInfo; + c.port = 23; /* telnet */ + + probe_cisco(&c); + } + + exit(0); +} |