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