watch.c revision 6521
16521Sugen/* 26521Sugen * Copyright (c) 1995 Ugen J.S.Antsilevich 36521Sugen * 46521Sugen * Redistribution and use in source forms, with and without modification, 56521Sugen * are permitted provided that this entire comment appears intact. 66521Sugen * 76521Sugen * Redistribution in binary form may occur without any restrictions. 86521Sugen * Obviously, it would be nice if you gave credit where credit is due 96521Sugen * but requiring it would be too onerous. 106521Sugen * 116521Sugen * This software is provided ``AS IS'' without any warranties of any kind. 126521Sugen * 136521Sugen * Snoop stuff. 146521Sugen */ 156521Sugen 166521Sugen#include <stdio.h> 176521Sugen#include <unistd.h> 186521Sugen#include <stdlib.h> 196521Sugen#include <signal.h> 206521Sugen#include <sys/types.h> 216521Sugen#include <sys/time.h> 226521Sugen#include <sys/select.h> 236521Sugen#include <sys/fcntl.h> 246521Sugen#include <sys/ioctl.h> 256521Sugen#include <sys/ioctl_compat.h> 266521Sugen#include <sys/snoop.h> 276521Sugen 286521Sugen 296521Sugen#define MSG_INIT "Snoop started." 306521Sugen#define MSG_OFLOW "Snoop stopped due to overflow.Reconnecting." 316521Sugen#define MSG_CLOSED "Snoop stopped due to tty close.Reconnecting." 326521Sugen#define MSG_CHANGE "Snoop device change by user request." 336521Sugen 346521Sugen 356521Sugen#define DEV_NAME_LEN 12 /* for /dev/ttyXX++ */ 366521Sugen#define MIN_SIZE 256 376521Sugen 386521Sugen#define CHR_SWITCH 24 /* Ctrl+X */ 396521Sugen#define CHR_CLEAR 23 /* Ctrl+V */ 406521Sugen 416521Sugen 426521Sugenint opt_reconn_close = 0; 436521Sugenint opt_reconn_oflow = 0; 446521Sugenint opt_interactive = 1; 456521Sugenint opt_timestamp = 0; 466521Sugen 476521Sugenchar dev_name[DEV_NAME_LEN]; 486521Sugenint snp_io; 496521Sugenstruct snptty snp_tty; 506521Sugenint std_in = 0, std_out = 1; 516521Sugen 526521Sugen 536521Sugenint clear_ok = 0; 546521Sugenstruct sgttyb sgo; 556521Sugenchar tbuf[1024], buf[1024]; 566521Sugen 576521Sugen 586521Sugenvoid 596521Sugenclear() 606521Sugen{ 616521Sugen if (clear_ok) 626521Sugen tputs(buf, 1, putchar); 636521Sugen fflush(stdout); 646521Sugen} 656521Sugen 666521Sugenvoid 676521Sugentimestamp(buf) 686521Sugen char *buf; 696521Sugen{ 706521Sugen time_t t; 716521Sugen char btmp[1024]; 726521Sugen clear(); 736521Sugen printf("\n---------------------------------------------\n"); 746521Sugen t = time(NULL); 756521Sugen strftime(btmp, 1024, "Time: %d %b %H:%M", localtime(&t)); 766521Sugen printf("%s\n", btmp); 776521Sugen printf("%s\n", buf); 786521Sugen printf("---------------------------------------------\n"); 796521Sugen fflush(stdout); 806521Sugen} 816521Sugen 826521Sugenvoid 836521Sugenset_tty() 846521Sugen{ 856521Sugen struct sgttyb sgn; 866521Sugen ioctl(std_in, TIOCGETP, &sgo); 876521Sugen /* bcopy(&sgn, &sgo, sizeof(struct sgttyb)); */ 886521Sugen sgn = sgo; 896521Sugen sgn.sg_flags |= CBREAK; 906521Sugen sgn.sg_flags &= ~ECHO; 916521Sugen ioctl(std_in, TIOCSETP, &sgn); 926521Sugen} 936521Sugen 946521Sugenvoid 956521Sugenunset_tty() 966521Sugen{ 976521Sugen ioctl(std_in, TIOCSETP, &sgo); 986521Sugen} 996521Sugen 1006521Sugen 1016521Sugenvoid 1026521Sugenfatal(buf) 1036521Sugen char *buf; 1046521Sugen{ 1056521Sugen unset_tty(); 1066521Sugen if (buf) 1076521Sugen fprintf(stderr, "Fatal: %s\n", buf); 1086521Sugen exit(1); 1096521Sugen} 1106521Sugen 1116521Sugenint 1126521Sugenopen_snp() 1136521Sugen{ 1146521Sugen char snp[DEV_NAME_LEN] = "/dev/snpX"; 1156521Sugen char c; 1166521Sugen int f; 1176521Sugen for (c = '0'; c <= '9'; c++) { 1186521Sugen snp[8] = c; 1196521Sugen if ((f = open(snp, O_RDONLY)) < 0) 1206521Sugen continue; 1216521Sugen return f; 1226521Sugen } 1236521Sugen fatal("Cannot open snoop device."); 1246521Sugen} 1256521Sugen 1266521Sugen 1276521Sugenvoid 1286521Sugencleanup() 1296521Sugen{ 1306521Sugen if (opt_timestamp) 1316521Sugen timestamp("Logging Exited."); 1326521Sugen close(snp_io); 1336521Sugen unset_tty(); 1346521Sugen exit(0); 1356521Sugen} 1366521Sugen 1376521Sugen 1386521Sugenvoid 1396521Sugenshow_usage() 1406521Sugen{ 1416521Sugen printf("watch -[ciot] [tty name]\n"); 1426521Sugen exit(1); 1436521Sugen} 1446521Sugen 1456521Sugenvoid 1466521Sugensetup_scr() 1476521Sugen{ 1486521Sugen char *cbuf = buf, *term; 1496521Sugen if (!opt_interactive) 1506521Sugen return; 1516521Sugen if ((term = getenv("TERM"))) 1526521Sugen if (tgetent(tbuf, term) == 1) 1536521Sugen if (tgetstr("cl", &cbuf)) 1546521Sugen clear_ok = 1; 1556521Sugen clear(); 1566521Sugen set_tty(); 1576521Sugen} 1586521Sugen 1596521Sugen 1606521Sugenint 1616521Sugenctoh(c) 1626521Sugen char c; 1636521Sugen{ 1646521Sugen if (c >= '0' && c <= '9') 1656521Sugen return (int) (c - '0'); 1666521Sugen 1676521Sugen if (c >= 'a' && c <= 'f') 1686521Sugen return (int) (c - 'a' + 10); 1696521Sugen 1706521Sugen fatal("Bad tty number."); 1716521Sugen} 1726521Sugen 1736521Sugen 1746521Sugenvoid 1756521Sugendetach_snp() 1766521Sugen{ 1776521Sugen struct snptty st; 1786521Sugen st.st_type = -1; 1796521Sugen st.st_unit = -1; 1806521Sugen ioctl(snp_io, SNPSTTY, &st); 1816521Sugen} 1826521Sugen 1836521Sugenvoid 1846521Sugenattach_snp() 1856521Sugen{ 1866521Sugen if (ioctl(snp_io, SNPSTTY, &snp_tty) != 0) 1876521Sugen fatal("Cannot attach to tty."); 1886521Sugen if (opt_timestamp) 1896521Sugen timestamp("Logging Started."); 1906521Sugen} 1916521Sugen 1926521Sugen 1936521Sugenvoid 1946521Sugenset_dev(name) 1956521Sugen char *name; 1966521Sugen{ 1976521Sugen char buf[DEV_NAME_LEN], num[DEV_NAME_LEN]; 1986521Sugen int unitbase = 0; 1996521Sugen 2006521Sugen if (strlen(name) > 5 && !strncmp(name, "/dev/", 5)) 2016521Sugen strcpy(buf, &(name[5])); 2026521Sugen else 2036521Sugen strcpy(buf, name); 2046521Sugen 2056521Sugen if (strlen(buf) < 4) 2066521Sugen fatal("Bad tty name."); 2076521Sugen 2086521Sugen if (!strncmp(buf, "tty", 3)) 2096521Sugen switch (buf[3]) { 2106521Sugen case 'v': 2116521Sugen snp_tty.st_unit = ctoh(buf[4]); 2126521Sugen snp_tty.st_type = ST_VTY; 2136521Sugen goto got_num; 2146521Sugen case 'r': 2156521Sugen unitbase += 16; 2166521Sugen case 'q': 2176521Sugen unitbase += 16; 2186521Sugen case 'p': 2196521Sugen snp_tty.st_unit = ctoh(buf[4]) + unitbase; 2206521Sugen snp_tty.st_type = ST_PTY; 2216521Sugen goto got_num; 2226521Sugen case '0': 2236521Sugen case 'd': 2246521Sugen snp_tty.st_unit = ctoh(buf[4]); 2256521Sugen snp_tty.st_type = ST_SIO; 2266521Sugen goto got_num; 2276521Sugen default: 2286521Sugen fatal("Bad tty name."); 2296521Sugen 2306521Sugen } 2316521Sugen 2326521Sugen 2336521Sugen if (!strncmp(buf, "vty", 3)) { 2346521Sugen strcpy(num, &(buf[3])); 2356521Sugen snp_tty.st_unit = atoi(num); 2366521Sugen snp_tty.st_type = ST_VTY; 2376521Sugen goto got_num; 2386521Sugen } 2396521Sugen if (!strncmp(buf, "pty", 3)) { 2406521Sugen strcpy(num, &(buf[3])); 2416521Sugen snp_tty.st_unit = atoi(num); 2426521Sugen snp_tty.st_type = ST_PTY; 2436521Sugen goto got_num; 2446521Sugen } 2456521Sugen if (!strncmp(buf, "sio", 3) || !strncmp(buf, "cua", 3)) { 2466521Sugen strcpy(num, &(buf[3])); 2476521Sugen snp_tty.st_unit = atoi(num); 2486521Sugen snp_tty.st_type = ST_SIO; 2496521Sugen goto got_num; 2506521Sugen } 2516521Sugen fatal("Bad tty name."); 2526521Sugengot_num: 2536521Sugen attach_snp(); 2546521Sugen} 2556521Sugen 2566521Sugenvoid 2576521Sugenask_dev(dev_name, msg) 2586521Sugen char *dev_name, *msg; 2596521Sugen{ 2606521Sugen char buf[DEV_NAME_LEN]; 2616521Sugen int len; 2626521Sugen 2636521Sugen clear(); 2646521Sugen unset_tty(); 2656521Sugen 2666521Sugen if (msg) 2676521Sugen printf("%s\n", msg); 2686521Sugen if (dev_name) 2696521Sugen printf("Enter device name [%s]:", dev_name); 2706521Sugen else 2716521Sugen printf("Enter device name:"); 2726521Sugen 2736521Sugen if (fgets(buf, DEV_NAME_LEN - 1, stdin)) { 2746521Sugen len = strlen(buf); 2756521Sugen if (buf[len - 1] == '\n') 2766521Sugen buf[len - 1] = '\0'; 2776521Sugen if (buf[0] != '\0' && buf[0] != ' ') 2786521Sugen strcpy(dev_name, buf); 2796521Sugen } 2806521Sugen set_tty(); 2816521Sugen} 2826521Sugen 2836521Sugen 2846521Sugenvoid 2856521Sugenmain(ac, av) 2866521Sugen int ac; 2876521Sugen char **av; 2886521Sugen{ 2896521Sugen int res, nread, b_size = MIN_SIZE; 2906521Sugen extern int optind; 2916521Sugen char ch, *buf; 2926521Sugen fd_set fd_s; 2936521Sugen 2946521Sugen if (getuid() != 0) 2956521Sugen fatal(NULL); 2966521Sugen 2976521Sugen if (isatty(std_out)) 2986521Sugen opt_interactive = 1; 2996521Sugen else 3006521Sugen opt_interactive = 0; 3016521Sugen 3026521Sugen 3036521Sugen while ((ch = getopt(ac, av, "ciot")) != EOF) 3046521Sugen switch (ch) { 3056521Sugen case 'c': 3066521Sugen opt_reconn_close = 1; 3076521Sugen break; 3086521Sugen case 'i': 3096521Sugen opt_interactive = 1; 3106521Sugen break; 3116521Sugen case 'o': 3126521Sugen opt_reconn_oflow = 1; 3136521Sugen break; 3146521Sugen case 't': 3156521Sugen opt_timestamp = 1; 3166521Sugen break; 3176521Sugen case '?': 3186521Sugen default: 3196521Sugen show_usage(); 3206521Sugen exit(1); 3216521Sugen } 3226521Sugen 3236521Sugen signal(SIGINT, cleanup); 3246521Sugen 3256521Sugen setup_scr(); 3266521Sugen snp_io = open_snp(); 3276521Sugen 3286521Sugen if (*(av += optind) == NULL) { 3296521Sugen if (opt_interactive) 3306521Sugen ask_dev(dev_name, MSG_INIT); 3316521Sugen else 3326521Sugen fatal("No device name given."); 3336521Sugen } else 3346521Sugen strncpy(dev_name, *av, DEV_NAME_LEN); 3356521Sugen 3366521Sugen set_dev(dev_name); 3376521Sugen 3386521Sugen if (!(buf = (char *) malloc(b_size))) 3396521Sugen fatal("Cannot malloc()."); 3406521Sugen 3416521Sugen FD_ZERO(&fd_s); 3426521Sugen 3436521Sugen while (1) { 3446521Sugen if (opt_interactive) 3456521Sugen FD_SET(std_in, &fd_s); 3466521Sugen FD_SET(snp_io, &fd_s); 3476521Sugen res = select(snp_io + 1, &fd_s, NULL, NULL, NULL); 3486521Sugen if (opt_interactive && FD_ISSET(std_in, &fd_s)) { 3496521Sugen switch (ch = getchar()) { 3506521Sugen case CHR_CLEAR: 3516521Sugen clear(); 3526521Sugen break; 3536521Sugen case CHR_SWITCH: 3546521Sugen /* detach_snp(); */ 3556521Sugen ask_dev(dev_name, MSG_CHANGE); 3566521Sugen set_dev(dev_name); 3576521Sugen break; 3586521Sugen default: 3596521Sugen } 3606521Sugen } 3616521Sugen if (!FD_ISSET(snp_io, &fd_s)) 3626521Sugen continue; 3636521Sugen 3646521Sugen if ((res = ioctl(snp_io, FIONREAD, &nread)) != 0) 3656521Sugen fatal("ioctl() failed."); 3666521Sugen 3676521Sugen switch (nread) { 3686521Sugen case SNP_OFLOW: 3696521Sugen if (opt_reconn_oflow) 3706521Sugen attach_snp(); 3716521Sugen else if (opt_interactive) { 3726521Sugen ask_dev(dev_name, MSG_OFLOW); 3736521Sugen set_dev(dev_name); 3746521Sugen } else 3756521Sugen cleanup(); 3766521Sugen case SNP_DETACH: 3776521Sugen case SNP_TTYCLOSE: 3786521Sugen if (opt_reconn_close) 3796521Sugen attach_snp(); 3806521Sugen else if (opt_interactive) { 3816521Sugen ask_dev(dev_name, MSG_CLOSED); 3826521Sugen set_dev(dev_name); 3836521Sugen } else 3846521Sugen cleanup(); 3856521Sugen default: 3866521Sugen if (nread < (b_size / 2) && (b_size / 2) > MIN_SIZE) { 3876521Sugen free(buf); 3886521Sugen if (!(buf = (char *) malloc(b_size / 2))) 3896521Sugen fatal("Cannot malloc()"); 3906521Sugen b_size = b_size / 2; 3916521Sugen } 3926521Sugen if (nread > b_size) { 3936521Sugen b_size = (nread % 2) ? (nread + 1) : (nread); 3946521Sugen free(buf); 3956521Sugen if (!(buf = (char *) malloc(b_size))) 3966521Sugen fatal("Cannot malloc()"); 3976521Sugen } 3986521Sugen if (read(snp_io, buf, nread) < nread) 3996521Sugen fatal("read failed."); 4006521Sugen if (write(std_out, buf, nread) < nread) 4016521Sugen fatal("write failed."); 4026521Sugen } 4036521Sugen } /* While */ 4046521Sugen} 405