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 42 int opt_reconn_close = 0; 43 int opt_reconn_oflow = 0; 44 int opt_interactive = 1; 45 int opt_timestamp = 0; 46 47 char dev_name[DEV_NAME_LEN]; 48 int snp_io; 49 struct snptty snp_tty; 50 int std_in = 0, std_out = 1; 51 52 53 int clear_ok = 0; 54 struct sgttyb sgo; 55 char tbuf[1024], buf[1024]; 56 57 58 void 59 clear() 60 { 61 if (clear_ok) 62 tputs(buf, 1, putchar); 63 fflush(stdout); 64 } 65 66 void 67 timestamp(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 82 void 83 set_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 94 void 95 unset_tty() 96 { 97 ioctl(std_in, TIOCSETP, &sgo); 98 } 99 100 101 void 102 fatal(buf) 103 char *buf; 104 { 105 unset_tty(); 106 if (buf) 107 fprintf(stderr, "Fatal: %s\n", buf); 108 exit(1); 109 } 110 111 int 112 open_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 127 void 128 cleanup() 129 { 130 if (opt_timestamp) 131 timestamp("Logging Exited."); 132 close(snp_io); 133 unset_tty(); 134 exit(0); 135 } 136 137 138 void 139 show_usage() 140 { 141 printf("watch -[ciot] [tty name]\n"); 142 exit(1); 143 } 144 145 void 146 setup_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 160 int 161 ctoh(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 174 void 175 detach_snp() 176 { 177 struct snptty st; 178 st.st_type = -1; 179 st.st_unit = -1; 180 ioctl(snp_io, SNPSTTY, &st); 181 } 182 183 void 184 attach_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 193 void 194 set_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."); 252 got_num: 253 attach_snp(); 254 } 255 256 void 257 ask_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 284 void 285 main(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