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