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