On Thu, Aug 30, 2001 at 05:01:34PM -0500, Simeon Johnston wrote: > I am looking for some sort of package that will allow me to control a > device via a com/tty port. > Basically - I want to be able to control my Cisco router (or any kind of > router/computer via com/tty) without having to actually log into it. > Lets say I want to get the current configuration. > I use minicom and log in and all that jazz. Then a simple "show > whatever" will give it to me. > I would like to create some sort of script to do this automatically and > have the output be usable by any application. Able to be logged or sent > to another application that will do something else etc. > > I want to be able to monitor the router and be able to respond when > something happens. If the router goes down or changes IP's I want to be > able to reconnect via VPN or something. Have certain daemons restart etc. > > Does this make sense? Is it possible (or will I have to actually make > this program)? Here is something I knocked over a weekend... florin -- "If it's not broken, let's fix it till it is." 41A9 2BDE 8E11 F1C5 87A6 03EE 34B3 E075 3B90 DFE4 -------------- next part -------------- /* router_stats.c - connects via the serial port to a router and gets stats Copyright (C) 2001 Florin Iucha <florin at iucha.net> 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. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: router_stats.c,v 1.9 2001/07/16 16:13:56 florin Exp florin $ */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <signal.h> #include <time.h> /* baudrate settings are defined in <asm/termbits.h>, which is included by <termios.h> */ #define BAUDRATE B38400 #define _POSIX_SOURCE 1 /* POSIX compliant source */ volatile int SIGNAL_HAPPENED = 0; void custom_handler(int signal) { SIGNAL_HAPPENED = 1; } void setup_device(int fd, struct termios* oldtio) { struct termios newtio; fcntl(fd, F_SETFL, FNDELAY); tcgetattr(fd, oldtio); /* save current serial port settings */ bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */ /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity,1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters */ newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) */ newtio.c_iflag = IGNPAR | ICRNL; /* Raw output. */ newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program */ newtio.c_lflag = ICANON; /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here */ newtio.c_cc[VINTR] = 0; /* Ctrl-c */ newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */ newtio.c_cc[VERASE] = 0; /* del */ newtio.c_cc[VKILL] = 0; /* @ */ newtio.c_cc[VEOF] = 4; /* Ctrl-d */ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ newtio.c_cc[VMIN] = 0; /* blocking read until 1 character arrives */ newtio.c_cc[VSWTC] = 0; /* '\0' */ newtio.c_cc[VSTART] = 0; /* Ctrl-q */ newtio.c_cc[VSTOP] = 0; /* Ctrl-s */ newtio.c_cc[VSUSP] = 0; /* Ctrl-z */ newtio.c_cc[VEOL] = 0; /* '\0' */ newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */ newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */ newtio.c_cc[VWERASE] = 0; /* Ctrl-w */ newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */ newtio.c_cc[VEOL2] = 0; /* '\0' */ /* now clean the modem line and activate the settings for the port */ tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &newtio); } void reset_device(int fd, struct termios* oldtio) { /* restore the old port settings */ tcsetattr(fd, TCSANOW, oldtio); } #define BUFSIZE 1024 #define MAX_COMMANDS 16 struct commands { char* device; char* setup_commands[MAX_COMMANDS]; int setup_count; char* data_commands[MAX_COMMANDS]; int data_count; char* reset_commands[MAX_COMMANDS]; int reset_count; char* words[MAX_COMMANDS]; int words_count; char* buff; int toSleep; }; int read_commands(int argc, char* argv[], struct commands* comm) { int fd; int res; if (argc < 4) { printf("Not enough args: use '%s <device> <commandfile>'\n", argv[0]); return 1; } comm->device = strdup(argv[1]); if (comm->device == 0) { puts("Cannot alloc memory."); return 1; } comm->buff = malloc(BUFSIZE); if (comm->buff == 0) { puts("Cannot alloc memory."); return 1; } comm->toSleep = atoi(argv[3]); /* now read the commands */ fd = open(argv[2], O_RDONLY); if (fd == -1) { perror(argv[2]); return 1; } res = read(fd, comm->buff, BUFSIZE); if (res == -1) { perror(argv[2]); return 1; } /* increade BUFSIZE */ if (res == BUFSIZE) { puts("BUFFER FULL"); return 1; } /* so the parsing ends... */ comm->buff[res] = 0; comm->setup_count = 0; comm->data_count = 0; comm->reset_count = 0; comm->words_count = 0; /* parse the thingie */ { int i; char* line = strtok(comm->buff, "\n"); while (line) { switch (line[0]) { case 'S': if (comm->setup_count < MAX_COMMANDS) comm->setup_commands[comm->setup_count ++] = strdup(line + 2); break; case 'D': if (comm->data_count < MAX_COMMANDS) comm->data_commands[comm->data_count ++] = strdup(line + 2); break; case 'R': if (comm->reset_count < MAX_COMMANDS) comm->reset_commands[comm->reset_count ++] = strdup(line + 2); break; case 'G': if (comm->words_count < MAX_COMMANDS) comm->words[comm->words_count ++] = strdup(line + 2); break; case '#': /* comment */ break; default: printf("Line '%s' not understood.\n", line); } line = strtok(0, "\n"); } } close (fd); return 0; } void cleanup_commands(struct commands* comm) { int i; if (comm->buff) free(comm->buff); for (i = 0; i < comm->setup_count; i ++) free(comm->setup_commands[i]); for (i = 0; i < comm->data_count; i ++) free(comm->data_commands[i]); for (i = 0; i < comm->reset_count; i ++) free(comm->reset_commands[i]); for (i = 0; i < comm->words_count; i ++) free(comm->words[i]); } void setup_channel(int fd, struct commands* comm) { int res; int i; for (i = 0; i < comm->setup_count; i ++) { int len = strlen(comm->setup_commands[i]); res = write(fd, comm->setup_commands[i], len); if (res == -1) { perror(comm->device); exit(-1); } if (res != len) { printf("Hmmm: tried %d, wrote %d\n", len, res); } write(fd, "\r", 1); sleep(1); res = 1; while (res) { res = read(fd, comm->buff, BUFSIZE); if (res == -1) { if (errno != EAGAIN) { perror(comm->device); exit(-1); } break; } } } } void reset_channel(int fd, struct commands* comm) { int res; int i; for (i = 0; i < comm->reset_count; i ++) { int len = strlen(comm->reset_commands[i]); res = write(fd, comm->reset_commands[i], len); if (res == -1) { perror(comm->device); exit(-1); } if (res != len) { printf("Hmmm: tried %d, wrote %d\n", len, res); } write(fd, "\r", 1); sleep(1); res = 1; while (res) { res = read(fd, comm->buff, BUFSIZE); if (res == -1) { if (errno != EAGAIN) { perror(comm->device); exit(-1); } break; } } } } void execute_commands(int fd, struct commands* comm) { int res; int last_pos = 0; int i; /* printf("The time is now %d\n", time(0)); */ for (i = 0; i < comm->data_count; i ++) { int len = strlen(comm->data_commands[i]); res = write(fd, comm->data_commands[i], len); if (res == -1) { perror(comm->device); exit(-1); } if (res != len) { printf("Hmmm: tried %d, wrote %d\n", len, res); } write(fd, "\r", 1); sleep(1); res = 1; while (res) { res = read(fd, comm->buff + last_pos, BUFSIZE - last_pos); if (res == -1) { if (errno != EAGAIN) { perror(comm->device); exit(-1); } break; } last_pos += res; } if (last_pos) { char* line = strtok(comm->buff, "\n"); while (line) { int i; for (i = 0; i < comm->words_count; i ++) { if (strstr(line, comm->words[i])) { write(1, line, strlen(line)); write(1, "\n", 1); break; } } line = strtok(0, "\n"); } fsync(1); } } } int main(int argc, char* argv[]) { int fd, res; struct termios oldtio; int i; struct commands comms; if (read_commands(argc, argv, &comms)) { return -1; } /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. */ fd = open(comms.device, O_RDWR | O_NOCTTY ); if (fd < 0) { perror(comms.device); exit(-1); } setup_device(fd, &oldtio); setup_channel(fd, &comms); signal(SIGTERM, custom_handler); signal(SIGINT, custom_handler); execute_commands(fd, &comms); while (SIGNAL_HAPPENED == 0 && comms.toSleep) { sleep(comms.toSleep); execute_commands(fd, &comms); } reset_channel(fd, &comms); reset_device(fd, &oldtio); close(fd); return 0; } -------------- next part -------------- S: S:<your password here> D:show uptime D:show int eth0 D:show int wan0 D:show int wan0-0 D:stats eth0 D:stats wan0 D:stats wan0-0 R:exit