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