capture.c 27.6 KB
Newer Older
1
2
3
4
5
6
7
8
/* 
 * File:	capture.c
 * Description: 
 * Author:	Leigh Stoller
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	27-Jul-92
 *
9
 * (c) Copyright 1992, 2000-2001, University of Utah, all rights reserved.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 */

/*
 * Testbed note:  This code has developed over the last several
 * years in RCS.  This is an import of the current version of
 * capture from the /usr/src/utah RCS repository into the testbed,
 * with some new hacks to port it to Linux.
 *
 * - dga, 10/10/2000
 */

/*
 * A LITTLE hack to record output from a tty device to a file, and still
 * have it available to tip using a pty/tty pair.
 */
25
26

#define SAFEMODE
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
	
#include <sys/param.h>

#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <syslog.h>
#ifdef HPBSD
#include <sgtty.h>
#else
#include <termios.h>
#endif
#include <errno.h>

#include <sys/param.h>
#include <sys/file.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/termios.h>
49
50
51
52
53
#ifdef USESOCKETS
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
54
55
#include <setjmp.h>
#include <netdb.h>
56
#endif
57
#include "capdecls.h"
58
59
60
61
62

#define geterr(e)	strerror(e)

void quit(int);
void reinit(int);
63
void newrun(int);
64
void terminate(int);
65
66
67
68
69
70
void cleanup(void);
void capture();
void usage();

#ifdef __linux__
#define _POSIX_VDISABLE '\0'
71
72
73
74
75
#define revoke(tty)	(0)
#endif

#ifdef HPBSD
#define TWOPROCESS	/* historic? */
76
77
78
79
80
81
82
#endif

/*
 *  Configurable things.
 */
#define PIDNAME		"%s/%s.pid"
#define LOGNAME		"%s/%s.log"
83
#define RUNNAME		"%s/%s.run"
84
85
86
#define TTYNAME		"%s/%s"
#define PTYNAME		"%s/%s-pty"
#define ACLNAME		"%s/%s.acl"
87
#define DEVNAME		"%s/%s"
88
#define BUFSIZE		4096
89
#define DROP_THRESH	(32*1024)
90
91
92
93

char 	*Progname;
char 	*Pidname;
char	*Logname;
94
char	*Runname;
95
char	*Ttyname;
96
97
98
char	*Ptyname;
char	*Devname;
char	*Machine;
99
100
int	logfd, runfd, devfd, ptyfd;
int	hwflow = 0, speed = B9600, debug = 0, runfile = 0;
101
#ifdef  USESOCKETS
102
103
104
char		  *Bossnode = BOSSNODE;
char		  *Aclname;
int		   serverport = SERVERPORT;
105
int		   sockfd, tipactive, portnum;
106
struct sockaddr_in tipclient;
107
108
109
secretkey_t	   secretkey;
char		   ourhostname[MAXHOSTNAMELEN];
int		   needshake;
110
111
gid_t		   tipgid;
uid_t		   tipuid;
112
#endif
113
114
115
116
117
118
119
120
121
122

int
main(argc, argv)
	int argc;
	char **argv;
{
	char strbuf[MAXPATHLEN], *newstr();
	int flags, op, i;
	extern int optind;
	extern char *optarg;
123
124
125
#ifdef  USESOCKETS
	struct sockaddr_in name;
#endif
126
127
128

	Progname = (Progname = rindex(argv[0], '/')) ? ++Progname : *argv;

129
	while ((op = getopt(argc, argv, "rds:Hb:itp:")) != EOF)
130
		switch (op) {
131
#ifdef	USESOCKETS
132
133
134
		case 'b':
			Bossnode = optarg;
			break;
135
136
137
138

		case 'p':
			serverport = atoi(optarg);
			break;
139
#endif
140
141
142
143
		case 'H':
			++hwflow;
			break;

144
145
146
147
148
149
150
151
		case 'd':
			debug++;
			break;

		case 'r':
			runfile++;
			break;

152
153
154
155
156
157
158
159
160
161
162
163
164
		case 's':
			if ((i = atoi(optarg)) == 0 ||
			    (speed = val2speed(i)) == 0)
				usage();
			break;
		}

	argc -= optind;
	argv += optind;

	if (argc != 2)
		usage();

165
166
167
168
169
#ifndef HPBSD
	if (!debug)
		(void)daemon(0, 0);
#endif

170
171
172
173
174
175
	Machine = argv[0];

	(void) sprintf(strbuf, PIDNAME, LOGPATH, argv[0]);
	Pidname = newstr(strbuf);
	(void) sprintf(strbuf, LOGNAME, LOGPATH, argv[0]);
	Logname = newstr(strbuf);
176
177
	(void) sprintf(strbuf, RUNNAME, LOGPATH, argv[0]);
	Runname = newstr(strbuf);
178
	(void) sprintf(strbuf, TTYNAME, TIPPATH, argv[0]);
179
	Ttyname = newstr(strbuf);
180
	(void) sprintf(strbuf, PTYNAME, TIPPATH, argv[0]);
181
182
183
184
185
186
187
188
189
190
	Ptyname = newstr(strbuf);
	(void) sprintf(strbuf, DEVNAME, DEVPATH, argv[1]);
	Devname = newstr(strbuf);

	openlog(Progname, LOG_PID, LOG_USER);
	dolog(LOG_NOTICE, "starting");

	signal(SIGINT, quit);
	signal(SIGTERM, quit);
	signal(SIGHUP, reinit);
191
192
	if (runfile)
		signal(SIGUSR1, newrun);
193
	signal(SIGUSR2, terminate);
194
195

	/*
196
	 * Open up run/log file, console tty, and controlling pty.
197
	 */
198
	if ((logfd = open(Logname, O_WRONLY|O_CREAT|O_APPEND, 0640)) < 0)
199
		die("%s: open: %s", Logname, geterr(errno));
200
	if (chmod(Logname, 0640) < 0)
201
		die("%s: chmod: %s", Logname, geterr(errno));
202
203

	if (runfile) {
204
205
206
		unlink(Runname);
		
		if ((runfd = open(Runname,O_WRONLY|O_CREAT|O_APPEND,0600)) < 0)
207
			die("%s: open: %s", Runname, geterr(errno));
208
209
		if (fchmod(runfd, 0640) < 0)
			die("%s: fchmod: %s", Runname, geterr(errno));
210
	}
211
#ifdef  USESOCKETS
212
213
214
	(void) sprintf(strbuf, ACLNAME, ACLPATH, Machine);
	Aclname = newstr(strbuf);
	
215
216
217
218
219
220
221
222
223
224
225
	/*
	 * Create and bind our socket.
	 */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
		die("socket(): opening stream socket: %s", geterr(errno));

	i = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
		       (char *)&i, sizeof(i)) < 0)
		die("setsockopt(): SO_REUSEADDR: %s", geterr(errno));
226
	
227
228
229
230
231
232
233
234
235
236
237
238
239
240
	/* Create wildcard name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
	name.sin_port = 0;
	if (bind(sockfd, (struct sockaddr *) &name, sizeof(name)))
		die("bind(): binding stream socket: %s", geterr(errno));

	/* Find assigned port value and print it out. */
	i = sizeof(name);
	if (getsockname(sockfd, (struct sockaddr *)&name, &i))
		die("getsockname(): %s", geterr(errno));
	portnum = ntohs(name.sin_port);

	if (listen(sockfd, 1) < 0)
241
		die("listen(): %s", geterr(errno));
242

243
244
	if (gethostname(ourhostname, sizeof(ourhostname)) < 0)
		die("gethostname(): %s", geterr(errno));
245

246
247
	createkey();
	dolog(LOG_NOTICE, "Ready! Listening on TCP port %d", portnum);
248
#else
249
	if ((ptyfd = open(Ptyname, O_RDWR)) < 0)
250
		die("%s: open: %s", Ptyname, geterr(errno));
251
#endif
252
	if ((devfd = open(Devname, O_RDWR|O_NONBLOCK)) < 0)
253
		die("%s: open: %s", Devname, geterr(errno));
254
255

	if (ioctl(devfd, TIOCEXCL, 0) < 0)
256
		warn("TIOCEXCL %s: %s", Devname, geterr(errno));
257
258
259
260
261
262
263
264
265
266

	writepid();
	rawmode(speed);

	capture();

	cleanup();
	exit(0);
}

267
268
269
#ifdef TWOPROCESS
int	pid;

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
void
capture()
{
	flags = FNDELAY;
	(void) fcntl(ptyfd, F_SETFL, &flags);

	if (pid = fork())
		in();
	else
		out();
}

/*
 * Loop reading from the console device, writing data to log file and
 * to the pty for tip to pick up.
 */
in()
{
288
	char buf[BUFSIZE];
289
290
291
	int cc, omask;
	
	while (1) {
292
		if ((cc = read(devfd, buf, BUFSIZE)) < 0) {
293
294
295
			if ((errno == EWOULDBLOCK) || (errno == EINTR))
				continue;
			else
296
				die("%s: read: %s", Devname, geterr(errno));
297
		}
298
299
		omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
				 sigmask(SIGUSR1)|sigmask(SIGUSR2));
300
301

		if (write(logfd, buf, cc) < 0)
302
			die("%s: write: %s", Logname, geterr(errno));
303

304
305
		if (runfile) {
			if (write(runfd, buf, cc) < 0)
306
				die("%s: write: %s", Runname, geterr(errno));
307
308
		}

309
310
		if (write(ptyfd, buf, cc) < 0) {
			if ((errno != EIO) && (errno != EWOULDBLOCK))
311
				die("%s: write: %s", Ptyname, geterr(errno));
312
313
314
315
316
317
318
319
320
321
		}
		(void) sigsetmask(omask);
	}
}

/*
 * Loop reading input from pty (tip), and send off to the console device.
 */
out()
{
322
	char buf[BUFSIZE];
323
324
325
326
327
328
329
	int cc, omask;
	struct timeval timeout;

	timeout.tv_sec  = 0;
	timeout.tv_usec = 100000;
	
	while (1) {
330
		omask = sigblock(SIGUSR2);
331
		if ((cc = read(ptyfd, buf, BUFSIZE)) < 0) {
332
			(void) sigsetmask(omask);
333
334
335
336
337
338
			if ((errno == EIO) || (errno == EWOULDBLOCK) ||
			    (errno == EINTR)) {
				select(0, 0, 0, 0, &timeout);
				continue;
			}
			else
339
				die("%s: read: %s", Ptyname, geterr(errno));
340
		}
341
342
343
344
		(void) sigsetmask(omask);

		omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
				 sigmask(SIGUSR1)|sigmask(SIGUSR2));
345
346

		if (write(devfd, buf, cc) < 0)
347
			die("%s: write: %s", Devname, geterr(errno));
348
349
350
351
352
		
		(void) sigsetmask(omask);
	}
}
#else
353
354
static fd_set	sfds;
static int	fdcount;
355
356
357
void
capture()
{
358
359
	fd_set fds;
	int i, cc, lcc, omask;
360
	char buf[BUFSIZE];
361
	struct timeval timeout;
362
363
364
365
#ifdef LOG_DROPS
	int drop_topty_chars = 0;
	int drop_todev_chars = 0;
#endif
366

367
368
369
370
371
372
373
374
375
376
377
378
379
	/*
	 * XXX for now we make both directions non-blocking.  This is a
	 * quick hack to achieve the goal that capture never block
	 * uninterruptably for long periods of time (use threads).
	 * This has the unfortunate side-effect that we may drop chars
	 * from the perspective of the user (use threads).  A more exotic
	 * solution would be to poll the readiness of output (use threads)
	 * as well as input and not read from one end unless we can write
	 * the other (use threads).
	 *
	 * I keep thinking (use threads) that there is a better way to do
	 * this (use threads).  Hmm...
	 */
Mike Hibler's avatar
Mike Hibler committed
380
	if (fcntl(devfd, F_SETFL, O_NONBLOCK) < 0)
381
		die("%s: fcntl(O_NONBLOCK): %s", Devname, geterr(errno));
382
#ifndef USESOCKETS
383
384
385
386
387
388
389
390
391
392
393
394
	/*
	 * It gets better!
	 * In FreeBSD 4.0 and beyond, the fcntl fails because the slave
	 * side is not open even though the only effect of this call is
	 * to set the file description's FNONBLOCK flag (i.e. the pty and
	 * tty code do nothing additional).  Turns out that we could use
	 * ioctl instead of fcntl to set the flag.  The call will still
	 * fail, but the flag will be left set.  Rather than rely on that
	 * dubious behavior, I temporarily open the slave, do the fcntl
	 * and close the slave again.
	 */
#ifdef __FreeBSD__
395
	if ((i = open(Ttyname, O_RDONLY)) < 0)
396
397
398
399
400
		die("%s: open: %s", Ttyname, geterr(errno));
#endif
	if (fcntl(ptyfd, F_SETFL, O_NONBLOCK) < 0)
		die("%s: fcntl(O_NONBLOCK): %s", Ptyname, geterr(errno));
#ifdef __FreeBSD__
401
	close(i);
402
#endif
403
#endif /* USESOCKETS */
404
405
406

	FD_ZERO(&sfds);
	FD_SET(devfd, &sfds);
407
408
409
410
411
412
413
414
	fdcount = devfd;
#ifdef  USESOCKETS
	if (devfd < sockfd)
		fdcount = sockfd;
	FD_SET(sockfd, &sfds);
#else
	if (devfd < ptyfd)
		fdcount = ptyfd;
415
	FD_SET(ptyfd, &sfds);
416
417
418
419
#endif	/* USESOCKETS */

	fdcount++;

420
	for (;;) {
421
422
423
424
425
426
427
428
#ifdef LOG_DROPS
		if (drop_topty_chars >= DROP_THRESH) {
			warn("%d dev -> pty chars dropped", drop_topty_chars);
			drop_topty_chars = 0;
		}
		if (drop_todev_chars >= DROP_THRESH) {
			warn("%d pty -> dev chars dropped", drop_todev_chars);
			drop_todev_chars = 0;
429
		}
430
#endif
431
		fds = sfds;
432
		timeout.tv_usec = 0;
433
434
435
436
437
438
439
#ifdef	USESOCKETS
		if (needshake)
			timeout.tv_sec  = 15;
		else
#endif
			timeout.tv_sec  = 30;
		i = select(fdcount, &fds, NULL, NULL, &timeout);
440
441
442
443
444
		if (i < 0) {
			if (errno == EINTR) {
				warn("input select interrupted, continuing");
				continue;
			}
445
			die("%s: select: %s", Devname, geterr(errno));
446
		}
447
		if (i == 0) {
448
449
450
451
452
453
#ifdef	USESOCKETS
			if (needshake) {
				handshake();
				continue;
			}
#endif
454
455
			continue;
		}
456
457
#ifdef	USESOCKETS
		if (FD_ISSET(sockfd, &fds)) {
458
			clientconnect();
459
460
		}
#endif	/* USESOCKETS */
461
462
463
464
		if (FD_ISSET(devfd, &fds)) {
			errno = 0;
			cc = read(devfd, buf, sizeof(buf));
			if (cc < 0)
465
				die("%s: read: %s", Devname, geterr(errno));
466
			if (cc == 0)
467
				die("%s: read: EOF", Devname);
468
469
			errno = 0;

470
471
			omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
					 sigmask(SIGUSR1)|sigmask(SIGUSR2));
472
473
474
475
#ifdef	USESOCKETS
			if (!tipactive)
				goto dropped;
#endif
476
477
478
			for (lcc = 0; lcc < cc; lcc += i) {
				i = write(ptyfd, &buf[lcc], cc-lcc);
				if (i < 0) {
479
480
481
482
483
484
485
					/*
					 * Either tip is blocked (^S) or
					 * not running (the latter should
					 * return EIO but doesn't due to a
					 * pty bug).  Note that we have
					 * dropped some chars.
					 */
486
					if (errno == EIO || errno == EAGAIN) {
487
488
#ifdef LOG_DROPS
						drop_topty_chars += (cc-lcc);
489
490
491
#endif
						goto dropped;
					}
492
					die("%s: write: %s",
493
494
					    Ptyname, geterr(errno));
				}
495
496
497
498
				if (i == 0) {
#ifdef	USESOCKETS
					goto disconnected;
#else
499
					die("%s: write: zero-length", Ptyname);
500
501
#endif
				}
502
503
504
505
			}
dropped:
			i = write(logfd, buf, cc);
			if (i < 0)
506
				die("%s: write: %s", Logname, geterr(errno));
507
			if (i != cc)
508
				die("%s: write: incomplete", Logname);
509
510
511
			if (runfile) {
				i = write(runfd, buf, cc);
				if (i < 0)
512
					die("%s: write: %s",
513
514
					    Runname, geterr(errno));
				if (i != cc)
515
					die("%s: write: incomplete", Runname);
516
			}
517
518
519
520
			(void) sigsetmask(omask);

		}
		if (FD_ISSET(ptyfd, &fds)) {
521
			omask = sigblock(sigmask(SIGUSR2));
522
523
			errno = 0;
			cc = read(ptyfd, buf, sizeof(buf), 0);
524
			(void) sigsetmask(omask);
525
526
527
528
			if (cc < 0) {
				/* XXX commonly observed */
				if (errno == EIO || errno == EAGAIN)
					continue;
529
530
531
532
#ifdef	USESOCKETS
				if (errno == ECONNRESET)
					goto disconnected;
#endif
533
				die("%s: read: %s", Ptyname, geterr(errno));
534
535
			}
			if (cc == 0) {
536
537
538
539
540
541
542
543
544
545
546
#ifdef	USESOCKETS
			disconnected:
				/*
				 * Other end disconnected.
				 */
				dolog(LOG_INFO, "%s disconnecting",
				      inet_ntoa(tipclient.sin_addr));
				FD_CLR(ptyfd, &sfds);
				close(ptyfd);
				tipactive = 0;
				continue;
547
#else
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
				/*
				 * Delay after reading 0 bytes from the pty.
				 * At least under FreeBSD, select on a
				 * disconnected pty (control half) always
				 * return ready and the subsequent read always
				 * returns 0.  To keep capture from eating up
				 * CPU constantly when no one is connected to
				 * the pty (i.e., most of the time) we delay
				 * after doing a zero length read.
				 *
				 * Note we keep tabs on the device so that we
				 * will wake up early if it goes active.
				 */
				timeout.tv_sec  = 1;
				timeout.tv_usec = 0;
				FD_ZERO(&fds);
				FD_SET(devfd, &fds);
				select(devfd+1, &fds, 0, 0, &timeout);
566
				continue;
567
#endif
568
569
570
			}
			errno = 0;

571
572
			omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
					 sigmask(SIGUSR1));
573
574
575
			for (lcc = 0; lcc < cc; lcc += i) {
				i = write(devfd, &buf[lcc], cc-lcc);
				if (i < 0) {
576
577
578
579
					/*
					 * Device backed up (or FUBARed)
					 * Note that we dropped some chars.
					 */
580
					if (errno == EAGAIN) {
581
582
583
#ifdef LOG_DROPS
						drop_todev_chars += (cc-lcc);
#endif
584
585
						goto dropped2;
					}
586
					die("%s: write: %s",
587
588
589
					    Devname, geterr(errno));
				}
				if (i == 0)
590
					die("%s: write: zero-length", Devname);
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
			}
dropped2:
			(void) sigsetmask(omask);

		}
	}
}
#endif

/*
 * SIGHUP means we want to close the old log file (because it has probably
 * been moved) and start a new version of it.
 */
void
reinit(int sig)
{
	/*
	 * We know that the any pending write to the log file completed
	 * because we blocked SIGHUP during the write.
	 */
	close(logfd);
	
613
	if ((logfd = open(Logname, O_WRONLY|O_CREAT|O_APPEND, 0640)) < 0)
614
		die("%s: open: %s", Logname, geterr(errno));
615
	if (chmod(Logname, 0640) < 0)
616
		die("%s: chmod: %s", Logname, geterr(errno));
617
618
619
620
621
622
623
624
	
	dolog(LOG_NOTICE, "new log started");

	if (runfile)
		newrun(sig);
}

/*
625
626
627
 * SIGUSR1 means we want to close the old run file and start a new version
 * of it. The run file is not rolled or saved, so we unlink it to make sure
 * that no one can hang onto an open fd.
628
629
630
631
632
633
634
635
636
 */
void
newrun(int sig)
{
	/*
	 * We know that the any pending write to the log file completed
	 * because we blocked SIGUSR1 during the write.
	 */
	close(runfd);
637
	unlink(Runname);
638

639
	if ((runfd = open(Runname, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0)
640
		die("%s: open: %s", Runname, geterr(errno));
641
642
643
644
645
646
647
648
649
650
651
652

#ifdef  USESOCKETS
	/*
	 * Set owner/group of the new run file. Avoid race in which a
	 * user can get the new file before the chmod, by creating 0600
	 * and doing the chmod below.
	 */
	if (fchown(runfd, tipuid, tipgid) < 0)
		die("%s: fchown: %s", Runname, geterr(errno));
#endif
	if (fchmod(runfd, 0640) < 0)
		die("%s: fchmod: %s", Runname, geterr(errno));
653
654
655
	
	dolog(LOG_NOTICE, "new run started");
}
656

657
658
/*
 * SIGUSR2 means we want to revoke the other side of the pty to close the
659
660
661
 * tip down gracefully.  We flush all input/output pending on the pty,
 * do a revoke on the tty and then close and reopen the pty just to make
 * sure everyone is gone.
662
663
 */
void
664
terminate(int sig)
665
{
666
#ifdef	USESOCKETS
667
668
669
670
671
672
673
674
675
676
	if (tipactive) {
		shutdown(ptyfd, SHUT_RDWR);
		close(ptyfd);
		FD_CLR(ptyfd, &sfds);
		ptyfd = 0;
		tipactive = 0;
		dolog(LOG_INFO, "%s revoked", inet_ntoa(tipclient.sin_addr));
	}
	else
		dolog(LOG_INFO, "revoked");
677

678
679
680
681
	tipuid = tipgid = 0;
	if (runfile)
		newrun(sig);

682
683
	/* Must be done *after* all the above stuff is done! */
	createkey();
684
#else
685
686
687
688
689
690
	int ofd = ptyfd;
	
	/*
	 * We know that the any pending access to the pty completed
	 * because we blocked SIGUSR2 during the operation.
	 */
691
692
693
694
695
696
697
698
#ifdef HPBSD
	int zero = 0;
	ioctl(ptyfd, TIOCFLUSH, &zero);
#else
	tcflush(ptyfd, TCIOFLUSH);
#endif
	if (revoke(Ttyname) < 0)
		dolog(LOG_WARNING, "could not revoke access to tty");
699
700
	close(ptyfd);
	
701
	if ((ptyfd = open(Ptyname, O_RDWR)) < 0)
702
		die("%s: open: %s", Ptyname, geterr(errno));
703
704
705
706
707
708
709
710

	/* XXX so we don't have to recompute the select mask */
	if (ptyfd != ofd) {
		dup2(ptyfd, ofd);
		close(ptyfd);
		ptyfd = ofd;
	}

711
712
#ifdef __FreeBSD__
	/* see explanation in capture() above */
713
	if ((ofd = open(Ttyname, O_RDONLY)) < 0)
714
715
		die("%s: open: %s", Ttyname, geterr(errno));
#endif
716
	if (fcntl(ptyfd, F_SETFL, O_NONBLOCK) < 0)
717
718
719
720
		die("%s: fcntl(O_NONBLOCK): %s", Ptyname, geterr(errno));
#ifdef __FreeBSD__
	close(ofd);
#endif
721
722
	
	dolog(LOG_NOTICE, "pty reset");
723
#endif	/* USESOCKETS */
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
}

/*
 *  Display proper usage / error message and exit.
 */
void
usage()
{
	fprintf(stderr, "usage: %s machine tty\n", Progname);
	exit(1);
}

warn(format, arg0, arg1, arg2, arg3)
	char *format, *arg0, *arg1, *arg2, *arg3;
{
739
	char msgbuf[BUFSIZE];
740

741
	snprintf(msgbuf, BUFSIZE, format, arg0, arg1, arg2, arg3);
742
	dolog(LOG_WARNING, msgbuf);
743
744
745
746
747
}

die(format, arg0, arg1, arg2, arg3)
	char *format, *arg0, *arg1, *arg2, *arg3;
{
748
	char msgbuf[BUFSIZE];
749

750
	snprintf(msgbuf, BUFSIZE, format, arg0, arg1, arg2, arg3);
751
752
753
754
	dolog(LOG_ERR, msgbuf);
	quit(0);
}

755
756
757
dolog(level, format, arg0, arg1, arg2, arg3)
	int level;
	char *format, *arg0, *arg1, *arg2, *arg3;
758
{
759
	char msgbuf[BUFSIZE];
760

761
762
763
764
765
766
	snprintf(msgbuf, BUFSIZE, format, arg0, arg1, arg2, arg3);
	if (debug) {
		fprintf(stderr, "%s - %s\n", Machine, msgbuf);
		fflush(stderr);
	}
	syslog(level, "%s - %s\n", Machine, msgbuf);
767
768
769
770
771
772
773
774
775
776
777
778
}

void
quit(int sig)
{
	cleanup();
	exit(1);
}

void
cleanup()
{
779
780
	dolog(LOG_NOTICE, "exiting");
#ifdef TWOPROCESS
781
782
	if (pid)
		(void) kill(pid, SIGTERM);
783
#endif
784
785
786
787
788
789
790
791
792
793
	(void) unlink(Pidname);
}

char *
newstr(str)
	char *str;
{
	char *malloc();
	register char *np;

794
795
	if ((np = malloc((unsigned) strlen(str) + 1)) == NULL)
		die("malloc: out of memory");
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

	return(strcpy(np, str));
}

#if 0
char *
geterr(errindx)
int errindx;
{
	extern int sys_nerr;
	extern char *sys_errlist[];
	char syserr[25];

	if (errindx < sys_nerr)
		return(sys_errlist[errindx]);

	(void) sprintf(syserr, "unknown error (%d)", errindx);
	return(syserr);
}
#endif

/*
 * Open up PID file and write our pid into it.
 */
writepid()
{
	int fd;
	char buf[8];
	
825
	if ((fd = open(Pidname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0)
826
		die("%s: open: %s", Pidname, geterr(errno));
827
828

	if (chmod(Pidname, 0644) < 0)
829
		die("%s: chmod: %s", Pidname, geterr(errno));
830
831
832
833
	
	(void) sprintf(buf, "%d\n", getpid());
	
	if (write(fd, buf, strlen(buf)) < 0)
834
		die("%s: write: %s", Pidname, geterr(errno));
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
	
	(void) close(fd);
}

/*
 * Put the console line into raw mode.
 */
rawmode(speed)
int speed;
{
#ifdef HPBSD
	struct sgttyb sgbuf;
	int bits;
	
	if (ioctl(devfd, TIOCGETP, (char *)&sgbuf) < 0)
850
		die("%s: ioctl(TIOCGETP): %s", Device, geterr(errno));
851
852
853
854
	sgbuf.sg_ispeed = sgbuf.sg_ospeed = speed;
	sgbuf.sg_flags = RAW|TANDEM;
	bits = LDECCTQ;
	if (ioctl(devfd, TIOCSETP, (char *)&sgbuf) < 0)
855
		die("%s: ioctl(TIOCSETP): %s", Device, geterr(errno));
856
	if (ioctl(devfd, TIOCLBIS, (char *)&bits) < 0)
857
		die("%s: ioctl(TIOCLBIS): %s", Device, geterr(errno));
858
859
860
861
#else
	struct termios t;

	if (tcgetattr(devfd, &t) < 0)
862
		die("%s: tcgetattr: %s", Devname, geterr(errno));
863
864
865
866
867
868
869
870
871
872
873
874
	(void) cfsetispeed(&t, speed);
	(void) cfsetospeed(&t, speed);
	cfmakeraw(&t);
	t.c_cflag |= CLOCAL;
	if (hwflow)
#ifdef __linux__
	        t.c_cflag |= CRTSCTS;
#else
		t.c_cflag |= CCTS_OFLOW | CRTS_IFLOW;
#endif
	t.c_cc[VSTART] = t.c_cc[VSTOP] = _POSIX_VDISABLE;
	if (tcsetattr(devfd, TCSAFLUSH, &t) < 0)
875
		die("%s: tcsetattr: %s", Devname, geterr(errno));
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
#endif
}

/*
 * From kgdbtunnel
 */
static struct speeds {
	int speed;		/* symbolic speed */
	int val;		/* numeric value */
} speeds[] = {
#ifdef B50
	{ B50,	50 },
#endif
#ifdef B75
	{ B75,	75 },
#endif
#ifdef B110
	{ B110,	110 },
#endif
#ifdef B134
	{ B134,	134 },
#endif
#ifdef B150
	{ B150,	150 },
#endif
#ifdef B200
	{ B200,	200 },
#endif
#ifdef B300
	{ B300,	300 },
#endif
#ifdef B600
	{ B600,	600 },
#endif
#ifdef B1200
	{ B1200, 1200 },
#endif
#ifdef B1800
	{ B1800, 1800 },
#endif
#ifdef B2400
	{ B2400, 2400 },
#endif
#ifdef B4800
	{ B4800, 4800 },
#endif
#ifdef B7200
	{ B7200, 7200 },
#endif
#ifdef B9600
	{ B9600, 9600 },
#endif
#ifdef B14400
	{ B14400, 14400 },
#endif
#ifdef B19200
	{ B19200, 19200 },
#endif
#ifdef B38400
	{ B38400, 38400 },
#endif
#ifdef B28800
	{ B28800, 28800 },
#endif
#ifdef B57600
	{ B57600, 57600 },
#endif
#ifdef B76800
	{ B76800, 76800 },
#endif
#ifdef B115200
	{ B115200, 115200 },
#endif
#ifdef B230400
	{ B230400, 230400 },
#endif
};
#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))

int
val2speed(val)
	register int val;
{
	register int n;
	register struct speeds *sp;

	for (sp = speeds, n = NSPEEDS; n > 0; ++sp, --n)
		if (val == sp->val)
			return (sp->speed);

	return (0);
}
968
969
970
971
972

#ifdef USESOCKETS
int
clientconnect()
{
973
974
975
	int		cc, length = sizeof(tipclient);
	int		newfd;
	secretkey_t     key;
976
	capret_t	capret;
977
978
979
980
981
982
983
984
985
986
987
988

	newfd = accept(sockfd, (struct sockaddr *)&tipclient, &length);
	if (newfd < 0)
		die("accept(): accepting new client: %s", geterr(errno));

	/*
	 * Is there a better way to do this? I suppose we
	 * could shut the main socket down, and recreate
	 * it later when the client disconnects, but that
	 * sounds horribly brutish!
	 */
	if (tipactive) {
989
990
991
992
993
		capret = CAPBUSY;
		if ((cc = write(newfd, &capret, sizeof(capret))) <= 0) {
			dolog(LOG_NOTICE, "%s refusing. error writing status",
			      inet_ntoa(tipclient.sin_addr));
		}
994
995
		dolog(LOG_NOTICE, "%s connecting, but tip is active",
		      inet_ntoa(tipclient.sin_addr));
996
997
		
		close(newfd);
998
999
1000
		return 1;
	}
	ptyfd = newfd;
For faster browsing, not all history is shown. View entire blame