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