watch.c revision 20085
1/* 2 * Copyright (c) 1995 Ugen J.S.Antsilevich 3 * 4 * Redistribution and use in source forms, with and without modification, 5 * are permitted provided that this entire comment appears intact. 6 * 7 * Redistribution in binary form may occur without any restrictions. 8 * Obviously, it would be nice if you gave credit where credit is due 9 * but requiring it would be too onerous. 10 * 11 * This software is provided ``AS IS'' without any warranties of any kind. 12 * 13 * Snoop stuff. 14 */ 15 16#include <stdio.h> 17#include <unistd.h> 18#include <stdlib.h> 19#include <signal.h> 20#include <string.h> 21#include <termcap.h> 22#include <sgtty.h> 23#include <locale.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <sys/time.h> 27#include <sys/select.h> 28#include <sys/fcntl.h> 29#include <sys/snoop.h> 30 31 32#define MSG_INIT "Snoop started." 33#define MSG_OFLOW "Snoop stopped due to overflow. Reconnecting." 34#define MSG_CLOSED "Snoop stopped due to tty close. Reconnecting." 35#define MSG_CHANGE "Snoop device change by user request." 36#define MSG_NOWRITE "Snoop device change due to write failure." 37 38 39#define DEV_NAME_LEN 1024 /* for /dev/ttyXX++ */ 40#define MIN_SIZE 256 41 42#define CHR_SWITCH 24 /* Ctrl+X */ 43#define CHR_CLEAR 23 /* Ctrl+V */ 44 45 46int opt_reconn_close = 0; 47int opt_reconn_oflow = 0; 48int opt_interactive = 1; 49int opt_timestamp = 0; 50int opt_write = 0; 51int opt_no_switch = 0; 52 53char dev_name[DEV_NAME_LEN]; 54int snp_io; 55dev_t snp_tty; 56int std_in = 0, std_out = 1; 57 58 59int clear_ok = 0; 60struct sgttyb sgo; 61struct tchars tco; 62char tbuf[1024], buf[1024]; 63 64 65void 66clear() 67{ 68 if (clear_ok) 69 tputs(buf, 1, putchar); 70 fflush(stdout); 71} 72 73void 74timestamp(buf) 75 char *buf; 76{ 77 time_t t; 78 char btmp[1024]; 79 clear(); 80 printf("\n---------------------------------------------\n"); 81 t = time(NULL); 82 strftime(btmp, 1024, "Time: %d %b %H:%M", localtime(&t)); 83 printf("%s\n", btmp); 84 printf("%s\n", buf); 85 printf("---------------------------------------------\n"); 86 fflush(stdout); 87} 88 89void 90set_tty() 91{ 92 struct sgttyb sgn; 93 struct tchars tc; 94 95 ioctl(std_in, TIOCGETP, &sgo); 96 ioctl(std_in, TIOCGETC, &tco); 97 sgn = sgo; 98 tc = tco; 99 sgn.sg_flags |= CBREAK; 100 sgn.sg_flags &= ~ECHO; 101 ospeed = sgo.sg_ospeed; 102 tc.t_intrc = 17; /* ^Q */ 103 tc.t_quitc = 17; /* ^Q */ 104 ioctl(std_in, TIOCSETP, &sgn); 105 ioctl(std_in, TIOCSETC, &tc); 106} 107 108void 109unset_tty() 110{ 111 ioctl(std_in, TIOCSETP, &sgo); 112 ioctl(std_in, TIOCSETC, &tco); 113} 114 115 116void 117fatal(buf) 118 char *buf; 119{ 120 unset_tty(); 121 if (buf) 122 fprintf(stderr, "Fatal: %s\n", buf); 123 exit(1); 124} 125 126int 127open_snp() 128{ 129 char snp[] = {"/dev/snpX"}; 130 char c; 131 int f, mode; 132 133 if (opt_write) 134 mode = O_RDWR; 135 else 136 mode = O_RDONLY; 137 138 for (c = '0'; c <= '9'; c++) { 139 snp[8] = c; 140 if ((f = open(snp, mode)) < 0) 141 continue; 142 return f; 143 } 144 fatal("Cannot open snoop device."); 145} 146 147 148void 149cleanup() 150{ 151 if (opt_timestamp) 152 timestamp("Logging Exited."); 153 close(snp_io); 154 unset_tty(); 155 exit(0); 156} 157 158 159void 160show_usage() 161{ 162 printf("watch -[ciotnW] [tty name]\n"); 163 exit(1); 164} 165 166void 167setup_scr() 168{ 169 char *cbuf = buf, *term; 170 if (!opt_interactive) 171 return; 172 if ((term = getenv("TERM"))) 173 if (tgetent(tbuf, term) == 1) 174 if (tgetstr("cl", &cbuf)) 175 clear_ok = 1; 176 set_tty(); 177 clear(); 178} 179 180 181int 182ctoh(c) 183 char c; 184{ 185 if (c >= '0' && c <= '9') 186 return (int) (c - '0'); 187 188 if (c >= 'a' && c <= 'f') 189 return (int) (c - 'a' + 10); 190 191 fatal("Bad tty number."); 192} 193 194 195void 196detach_snp() 197{ 198 dev_t dev; 199 200 dev = -1; 201 ioctl(snp_io, SNPSTTY, &dev); 202} 203 204void 205attach_snp() 206{ 207 if (ioctl(snp_io, SNPSTTY, &snp_tty) != 0) 208 fatal("Cannot attach to tty."); 209 if (opt_timestamp) 210 timestamp("Logging Started."); 211} 212 213 214void 215set_dev(name) 216 char *name; 217{ 218 char buf[DEV_NAME_LEN]; 219 struct stat sb; 220 221 if (strlen(name) > 5 && !strncmp(name, "/dev/", 5)) 222 strcpy(buf, name); 223 else { 224 if (strlen(name) == 2) 225 sprintf(buf, "/dev/tty%s", name); 226 else 227 sprintf(buf, "/dev/%s", name); 228 } 229 230 if (stat(buf, &sb) < 0) 231 fatal("Bad device name."); 232 233 snp_tty = sb.st_rdev; 234 attach_snp(); 235} 236 237void 238ask_dev(dev_name, msg) 239 char *dev_name, *msg; 240{ 241 char buf[DEV_NAME_LEN]; 242 int len; 243 244 clear(); 245 unset_tty(); 246 247 if (msg) 248 printf("%s\n", msg); 249 if (dev_name) 250 printf("Enter device name [%s]:", dev_name); 251 else 252 printf("Enter device name:"); 253 254 if (fgets(buf, DEV_NAME_LEN - 1, stdin)) { 255 len = strlen(buf); 256 if (buf[len - 1] == '\n') 257 buf[len - 1] = '\0'; 258 if (buf[0] != '\0' && buf[0] != ' ') 259 strcpy(dev_name, buf); 260 } 261 set_tty(); 262} 263 264#define READB_LEN 5 265 266void 267main(ac, av) 268 int ac; 269 char **av; 270{ 271 int res, nread, b_size = MIN_SIZE; 272 extern int optind; 273 char ch, *buf, chb[READB_LEN]; 274 fd_set fd_s; 275 276 (void) setlocale(LC_TIME, ""); 277 278 if (isatty(std_out)) 279 opt_interactive = 1; 280 else 281 opt_interactive = 0; 282 283 284 while ((ch = getopt(ac, av, "Wciotn")) != EOF) 285 switch (ch) { 286 case 'W': 287 opt_write = 1; 288 break; 289 case 'c': 290 opt_reconn_close = 1; 291 break; 292 case 'i': 293 opt_interactive = 1; 294 break; 295 case 'o': 296 opt_reconn_oflow = 1; 297 break; 298 case 't': 299 opt_timestamp = 1; 300 break; 301 case 'n': 302 opt_no_switch = 1; 303 break; 304 case '?': 305 default: 306 show_usage(); 307 exit(1); 308 } 309 310 signal(SIGINT, cleanup); 311 312 setup_scr(); 313 snp_io = open_snp(); 314 315 if (*(av += optind) == NULL) { 316 if (opt_interactive && !opt_no_switch) 317 ask_dev(dev_name, MSG_INIT); 318 else 319 fatal("No device name given."); 320 } else 321 strncpy(dev_name, *av, DEV_NAME_LEN); 322 323 set_dev(dev_name); 324 325 if (!(buf = (char *) malloc(b_size))) 326 fatal("Cannot malloc()."); 327 328 FD_ZERO(&fd_s); 329 330 while (1) { 331 if (opt_interactive) 332 FD_SET(std_in, &fd_s); 333 FD_SET(snp_io, &fd_s); 334 res = select(snp_io + 1, &fd_s, NULL, NULL, NULL); 335 if (opt_interactive && FD_ISSET(std_in, &fd_s)) { 336 337 if ((res = ioctl(std_in, FIONREAD, &nread)) != 0) 338 fatal("ioctl() failed."); 339 if (nread > READB_LEN) 340 nread = READB_LEN; 341 if (read(std_in,chb,nread)!=nread) 342 fatal("read (stdin) failed."); 343 344 switch (chb[0]) { 345 case CHR_CLEAR: 346 clear(); 347 break; 348 case CHR_SWITCH: 349 if (opt_no_switch) 350 break; 351 detach_snp(); 352 ask_dev(dev_name, MSG_CHANGE); 353 set_dev(dev_name); 354 break; 355 default: 356 if (opt_write) { 357 if (write(snp_io,chb,nread) != nread) { 358 detach_snp(); 359 if (opt_no_switch) 360 fatal("Write failed."); 361 ask_dev(dev_name, MSG_NOWRITE); 362 set_dev(dev_name); 363 } 364 } 365 366 } 367 } 368 if (!FD_ISSET(snp_io, &fd_s)) 369 continue; 370 371 if ((res = ioctl(snp_io, FIONREAD, &nread)) != 0) 372 fatal("ioctl() failed."); 373 374 switch (nread) { 375 case SNP_OFLOW: 376 if (opt_reconn_oflow) 377 attach_snp(); 378 else if (opt_interactive && !opt_no_switch) { 379 ask_dev(dev_name, MSG_OFLOW); 380 set_dev(dev_name); 381 } else 382 cleanup(); 383 case SNP_DETACH: 384 case SNP_TTYCLOSE: 385 if (opt_reconn_close) 386 attach_snp(); 387 else if (opt_interactive && !opt_no_switch) { 388 ask_dev(dev_name, MSG_CLOSED); 389 set_dev(dev_name); 390 } else 391 cleanup(); 392 default: 393 if (nread < (b_size / 2) && (b_size / 2) > MIN_SIZE) { 394 free(buf); 395 if (!(buf = (char *) malloc(b_size / 2))) 396 fatal("Cannot malloc()"); 397 b_size = b_size / 2; 398 } 399 if (nread > b_size) { 400 b_size = (nread % 2) ? (nread + 1) : (nread); 401 free(buf); 402 if (!(buf = (char *) malloc(b_size))) 403 fatal("Cannot malloc()"); 404 } 405 if (read(snp_io, buf, nread) < nread) 406 fatal("read failed."); 407 if (write(std_out, buf, nread) < nread) 408 fatal("write failed."); 409 } 410 } /* While */ 411} 412