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