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