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 struct tchars tc; 92 93 ioctl(std_in, TIOCGETP, &sgo); 94 ioctl(std_in, TIOCGETC, &tc); 95 /* bcopy(&sgn, &sgo, sizeof(struct sgttyb)); */ 96 sgn = sgo; 97 sgn.sg_flags |= CBREAK; 98 sgn.sg_flags &= ~ECHO; 99 ospeed = sgo.sg_ospeed; 100 tc.t_intrc = 17; /* ^Q */ 101 tc.t_quitc = 17; /* ^Q */ 102 ioctl(std_in, TIOCSETP, &sgn); 103 ioctl(std_in, TIOCSETC, &tc); 104 } 105 106 void 107 unset_tty() 108 { 109 ioctl(std_in, TIOCSETP, &sgo); 110 } 111 112 113 void 114 fatal(buf) 115 char *buf; 116 { 117 unset_tty(); 118 if (buf) 119 fprintf(stderr, "Fatal: %s\n", buf); 120 exit(1); 121 } 122 123 int 124 open_snp() 125 { 126 char snp[] = {"/dev/snpX"}; 127 char c; 128 int f, mode; 129 130 if (opt_write) 131 mode = O_RDWR; 132 else 133 mode = O_RDONLY; 134 135 for (c = '0'; c <= '9'; c++) { 136 snp[8] = c; 137 if ((f = open(snp, mode)) < 0) 138 continue; 139 return f; 140 } 141 fatal("Cannot open snoop device."); 142 } 143 144 145 void 146 cleanup() 147 { 148 if (opt_timestamp) 149 timestamp("Logging Exited."); 150 close(snp_io); 151 unset_tty(); 152 exit(0); 153 } 154 155 156 void 157 show_usage() 158 { 159 printf("watch -[ciotW] [tty name]\n"); 160 exit(1); 161 } 162 163 void 164 setup_scr() 165 { 166 char *cbuf = buf, *term; 167 if (!opt_interactive) 168 return; 169 if ((term = getenv("TERM"))) 170 if (tgetent(tbuf, term) == 1) 171 if (tgetstr("cl", &cbuf)) 172 clear_ok = 1; 173 set_tty(); 174 clear(); 175 } 176 177 178 int 179 ctoh(c) 180 char c; 181 { 182 if (c >= '0' && c <= '9') 183 return (int) (c - '0'); 184 185 if (c >= 'a' && c <= 'f') 186 return (int) (c - 'a' + 10); 187 188 fatal("Bad tty number."); 189 } 190 191 192 void 193 detach_snp() 194 { 195 dev_t dev; 196 197 dev = -1; 198 ioctl(snp_io, SNPSTTY, &dev); 199 } 200 201 void 202 attach_snp() 203 { 204 if (ioctl(snp_io, SNPSTTY, &snp_tty) != 0) 205 fatal("Cannot attach to tty."); 206 if (opt_timestamp) 207 timestamp("Logging Started."); 208 } 209 210 211 void 212 set_dev(name) 213 char *name; 214 { 215 char buf[DEV_NAME_LEN]; 216 struct stat sb; 217 218 if (strlen(name) > 5 && !strncmp(name, "/dev/", 5)) 219 strcpy(buf, name); 220 else { 221 if (strlen(name) == 2) 222 sprintf(buf, "/dev/tty%s", name); 223 else 224 sprintf(buf, "/dev/%s", name); 225 } 226 227 if (stat(buf, &sb) < 0) 228 fatal("Bad device name."); 229 230 snp_tty = sb.st_rdev; 231 attach_snp(); 232 } 233 234 void 235 ask_dev(dev_name, msg) 236 char *dev_name, *msg; 237 { 238 char buf[DEV_NAME_LEN]; 239 int len; 240 241 clear(); 242 unset_tty(); 243 244 if (msg) 245 printf("%s\n", msg); 246 if (dev_name) 247 printf("Enter device name [%s]:", dev_name); 248 else 249 printf("Enter device name:"); 250 251 if (fgets(buf, DEV_NAME_LEN - 1, stdin)) { 252 len = strlen(buf); 253 if (buf[len - 1] == '\n') 254 buf[len - 1] = '\0'; 255 if (buf[0] != '\0' && buf[0] != ' ') 256 strcpy(dev_name, buf); 257 } 258 set_tty(); 259 } 260 261 #define READB_LEN 5 262 263 void 264 main(ac, av) 265 int ac; 266 char **av; 267 { 268 int res, nread, b_size = MIN_SIZE; 269 extern int optind; 270 char ch, *buf, chb[READB_LEN]; 271 fd_set fd_s; 272 273 (void) setlocale(LC_TIME, ""); 274 275 if (getuid() != 0) 276 fatal(NULL); 277 278 if (isatty(std_out)) 279 opt_interactive = 1; 280 else 281 opt_interactive = 0; 282 283 284 while ((ch = getopt(ac, av, "Wciot")) != 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 '?': 302 default: 303 show_usage(); 304 exit(1); 305 } 306 307 signal(SIGINT, cleanup); 308 309 setup_scr(); 310 snp_io = open_snp(); 311 312 if (*(av += optind) == NULL) { 313 if (opt_interactive) 314 ask_dev(dev_name, MSG_INIT); 315 else 316 fatal("No device name given."); 317 } else 318 strncpy(dev_name, *av, DEV_NAME_LEN); 319 320 set_dev(dev_name); 321 322 if (!(buf = (char *) malloc(b_size))) 323 fatal("Cannot malloc()."); 324 325 FD_ZERO(&fd_s); 326 327 while (1) { 328 if (opt_interactive) 329 FD_SET(std_in, &fd_s); 330 FD_SET(snp_io, &fd_s); 331 res = select(snp_io + 1, &fd_s, NULL, NULL, NULL); 332 if (opt_interactive && FD_ISSET(std_in, &fd_s)) { 333 334 if ((res = ioctl(std_in, FIONREAD, &nread)) != 0) 335 fatal("ioctl() failed."); 336 if (nread > READB_LEN) 337 nread = READB_LEN; 338 if (read(std_in,chb,nread)!=nread) 339 fatal("read (stdin) failed."); 340 341 switch (chb[0]) { 342 case CHR_CLEAR: 343 clear(); 344 break; 345 case CHR_SWITCH: 346 detach_snp(); 347 ask_dev(dev_name, MSG_CHANGE); 348 set_dev(dev_name); 349 break; 350 default: 351 if (opt_write) { 352 if (write(snp_io,chb,nread) != nread) { 353 detach_snp(); 354 ask_dev(dev_name, MSG_NOWRITE); 355 set_dev(dev_name); 356 } 357 } 358 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