capture.c 31.1 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
57
58
59
60
#ifdef WITHSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif /* WITHSSL */
#endif /* USESOCKETS */
61
#include "capdecls.h"
62
#include "config.h"
63
64
65
66
67

#define geterr(e)	strerror(e)

void quit(int);
void reinit(int);
68
void newrun(int);
69
void terminate(int);
70
71
72
73
74
75
void cleanup(void);
void capture();
void usage();

#ifdef __linux__
#define _POSIX_VDISABLE '\0'
76
77
78
79
80
#define revoke(tty)	(0)
#endif

#ifdef HPBSD
#define TWOPROCESS	/* historic? */
81
82
83
84
85
86
87
#endif

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

Chad Barb's avatar
Chad Barb committed
96
#define DEFAULT_CERTFILE PREFIX"etc/capture.pem"
Chad Barb's avatar
   
Chad Barb committed
97

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

#ifdef  WITHSSL

SSL_CTX * ctx;
SSL * sslCon;

int initializedSSL = 0;
int usingSSL = 0;

const char * certfile = NULL;

#endif /* WITHSSL */ 
#endif /* USESOCKETS */
132
133
134
135
136
137
138
139
140
141

int
main(argc, argv)
	int argc;
	char **argv;
{
	char strbuf[MAXPATHLEN], *newstr();
	int flags, op, i;
	extern int optind;
	extern char *optarg;
142
143
144
#ifdef  USESOCKETS
	struct sockaddr_in name;
#endif
145
146
147

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

148
	while ((op = getopt(argc, argv, "rds:Hb:itp:c:")) != EOF)
149
		switch (op) {
150
#ifdef	USESOCKETS
151
152
153
154
155
#ifdef  WITHSSL
		case 'c':
		        certfile = optarg;
		        break;
#endif  WITHSSL
156
157
158
		case 'b':
			Bossnode = optarg;
			break;
159
160
161
162

		case 'p':
			serverport = atoi(optarg);
			break;
163
#endif /* USESOCKETS */
164
165
166
167
		case 'H':
			++hwflow;
			break;

168
169
170
171
172
173
174
175
		case 'd':
			debug++;
			break;

		case 'r':
			runfile++;
			break;

176
177
178
179
180
181
182
183
184
185
186
187
188
		case 's':
			if ((i = atoi(optarg)) == 0 ||
			    (speed = val2speed(i)) == 0)
				usage();
			break;
		}

	argc -= optind;
	argv += optind;

	if (argc != 2)
		usage();

189
190
191
192
193
#ifndef HPBSD
	if (!debug)
		(void)daemon(0, 0);
#endif

194
195
196
197
198
199
	Machine = argv[0];

	(void) sprintf(strbuf, PIDNAME, LOGPATH, argv[0]);
	Pidname = newstr(strbuf);
	(void) sprintf(strbuf, LOGNAME, LOGPATH, argv[0]);
	Logname = newstr(strbuf);
200
201
	(void) sprintf(strbuf, RUNNAME, LOGPATH, argv[0]);
	Runname = newstr(strbuf);
202
	(void) sprintf(strbuf, TTYNAME, TIPPATH, argv[0]);
203
	Ttyname = newstr(strbuf);
204
	(void) sprintf(strbuf, PTYNAME, TIPPATH, argv[0]);
205
206
207
208
209
210
211
212
213
214
	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);
215
216
	if (runfile)
		signal(SIGUSR1, newrun);
217
	signal(SIGUSR2, terminate);
218
219
	srandomdev();
	
220
	/*
221
	 * Open up run/log file, console tty, and controlling pty.
222
	 */
223
	if ((logfd = open(Logname, O_WRONLY|O_CREAT|O_APPEND, 0640)) < 0)
224
		die("%s: open: %s", Logname, geterr(errno));
225
	if (chmod(Logname, 0640) < 0)
226
		die("%s: chmod: %s", Logname, geterr(errno));
227
228

	if (runfile) {
229
230
231
		unlink(Runname);
		
		if ((runfd = open(Runname,O_WRONLY|O_CREAT|O_APPEND,0600)) < 0)
232
			die("%s: open: %s", Runname, geterr(errno));
233
234
		if (fchmod(runfd, 0640) < 0)
			die("%s: fchmod: %s", Runname, geterr(errno));
235
	}
236
#ifdef  USESOCKETS
237
238
239
	(void) sprintf(strbuf, ACLNAME, ACLPATH, Machine);
	Aclname = newstr(strbuf);
	
240
241
242
243
244
245
246
247
248
249
250
	/*
	 * 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));
251
	
252
253
254
255
256
257
258
259
260
261
262
263
264
265
	/* 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)
266
		die("listen(): %s", geterr(errno));
267

268
269
	if (gethostname(ourhostname, sizeof(ourhostname)) < 0)
		die("gethostname(): %s", geterr(errno));
270

271
272
	createkey();
	dolog(LOG_NOTICE, "Ready! Listening on TCP port %d", portnum);
273
#else
274
	if ((ptyfd = open(Ptyname, O_RDWR)) < 0)
275
		die("%s: open: %s", Ptyname, geterr(errno));
276
#endif
277
	if ((devfd = open(Devname, O_RDWR|O_NONBLOCK)) < 0)
278
		die("%s: open: %s", Devname, geterr(errno));
279
280

	if (ioctl(devfd, TIOCEXCL, 0) < 0)
281
		warn("TIOCEXCL %s: %s", Devname, geterr(errno));
282
283
284
285
286
287
288
289
290
291

	writepid();
	rawmode(speed);

	capture();

	cleanup();
	exit(0);
}

292
293
294
#ifdef TWOPROCESS
int	pid;

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
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()
{
313
	char buf[BUFSIZE];
314
315
316
	int cc, omask;
	
	while (1) {
317
		if ((cc = read(devfd, buf, BUFSIZE)) < 0) {
318
319
320
			if ((errno == EWOULDBLOCK) || (errno == EINTR))
				continue;
			else
321
				die("%s: read: %s", Devname, geterr(errno));
322
		}
323
324
		omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
				 sigmask(SIGUSR1)|sigmask(SIGUSR2));
325
326

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

329
330
		if (runfile) {
			if (write(runfd, buf, cc) < 0)
331
				die("%s: write: %s", Runname, geterr(errno));
332
333
		}

334
335
		if (write(ptyfd, buf, cc) < 0) {
			if ((errno != EIO) && (errno != EWOULDBLOCK))
336
				die("%s: write: %s", Ptyname, geterr(errno));
337
338
339
340
341
342
343
344
345
346
		}
		(void) sigsetmask(omask);
	}
}

/*
 * Loop reading input from pty (tip), and send off to the console device.
 */
out()
{
347
	char buf[BUFSIZE];
348
349
350
351
352
353
354
	int cc, omask;
	struct timeval timeout;

	timeout.tv_sec  = 0;
	timeout.tv_usec = 100000;
	
	while (1) {
355
		omask = sigblock(SIGUSR2);
356
		if ((cc = read(ptyfd, buf, BUFSIZE)) < 0) {
357
			(void) sigsetmask(omask);
358
359
360
361
362
363
			if ((errno == EIO) || (errno == EWOULDBLOCK) ||
			    (errno == EINTR)) {
				select(0, 0, 0, 0, &timeout);
				continue;
			}
			else
364
				die("%s: read: %s", Ptyname, geterr(errno));
365
		}
366
367
368
369
		(void) sigsetmask(omask);

		omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
				 sigmask(SIGUSR1)|sigmask(SIGUSR2));
370
371

		if (write(devfd, buf, cc) < 0)
372
			die("%s: write: %s", Devname, geterr(errno));
373
374
375
376
377
		
		(void) sigsetmask(omask);
	}
}
#else
378
379
static fd_set	sfds;
static int	fdcount;
380
381
382
void
capture()
{
383
384
	fd_set fds;
	int i, cc, lcc, omask;
385
	char buf[BUFSIZE];
386
	struct timeval timeout;
387
388
389
390
#ifdef LOG_DROPS
	int drop_topty_chars = 0;
	int drop_todev_chars = 0;
#endif
391

392
393
394
395
396
397
398
399
400
401
402
403
404
	/*
	 * 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
405
	if (fcntl(devfd, F_SETFL, O_NONBLOCK) < 0)
406
		die("%s: fcntl(O_NONBLOCK): %s", Devname, geterr(errno));
407
#ifndef USESOCKETS
408
409
410
411
412
413
414
415
416
417
418
419
	/*
	 * 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__
420
	if ((i = open(Ttyname, O_RDONLY)) < 0)
421
422
423
424
425
		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__
426
	close(i);
427
#endif
428
#endif /* USESOCKETS */
429
430
431

	FD_ZERO(&sfds);
	FD_SET(devfd, &sfds);
432
433
434
435
436
437
438
439
	fdcount = devfd;
#ifdef  USESOCKETS
	if (devfd < sockfd)
		fdcount = sockfd;
	FD_SET(sockfd, &sfds);
#else
	if (devfd < ptyfd)
		fdcount = ptyfd;
440
	FD_SET(ptyfd, &sfds);
441
442
443
444
#endif	/* USESOCKETS */

	fdcount++;

445
	for (;;) {
446
447
448
449
450
451
452
453
#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;
454
		}
455
#endif
456
		fds = sfds;
457
		timeout.tv_usec = 0;
458
		timeout.tv_sec  = 30;
459
#ifdef	USESOCKETS
460
461
462
		if (needshake) {
			timeout.tv_sec += (random() % 60);
		}
463
464
#endif
		i = select(fdcount, &fds, NULL, NULL, &timeout);
465
466
467
468
469
		if (i < 0) {
			if (errno == EINTR) {
				warn("input select interrupted, continuing");
				continue;
			}
470
			die("%s: select: %s", Devname, geterr(errno));
471
		}
472
		if (i == 0) {
473
474
475
476
477
478
#ifdef	USESOCKETS
			if (needshake) {
				handshake();
				continue;
			}
#endif
479
480
			continue;
		}
481
482
#ifdef	USESOCKETS
		if (FD_ISSET(sockfd, &fds)) {
483
			clientconnect();
484
485
		}
#endif	/* USESOCKETS */
486
487
488
489
		if (FD_ISSET(devfd, &fds)) {
			errno = 0;
			cc = read(devfd, buf, sizeof(buf));
			if (cc < 0)
490
				die("%s: read: %s", Devname, geterr(errno));
491
			if (cc == 0)
492
				die("%s: read: EOF", Devname);
493
494
			errno = 0;

495
496
			omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
					 sigmask(SIGUSR1)|sigmask(SIGUSR2));
497
498
499
500
#ifdef	USESOCKETS
			if (!tipactive)
				goto dropped;
#endif
501
			for (lcc = 0; lcc < cc; lcc += i) {
502
503
504
505
506
507
508
509
510
#ifdef  WITHSSL
			        if (usingSSL) {
				        i = SSL_write(sslCon, &buf[lcc], cc-lcc);
					if (i < 0) { i = 0; } /* XXX Hack */
			        } else
#endif /* WITHSSL */ 
			        {
				        i = write(ptyfd, &buf[lcc], cc-lcc);
				}
511
				if (i < 0) {
512
513
514
515
516
517
518
					/*
					 * 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.
					 */
519
					if (errno == EIO || errno == EAGAIN) {
520
521
#ifdef LOG_DROPS
						drop_topty_chars += (cc-lcc);
522
523
524
#endif
						goto dropped;
					}
525
					die("%s: write: %s",
526
527
					    Ptyname, geterr(errno));
				}
528
529
530
531
				if (i == 0) {
#ifdef	USESOCKETS
					goto disconnected;
#else
532
					die("%s: write: zero-length", Ptyname);
533
534
#endif
				}
535
536
537
538
			}
dropped:
			i = write(logfd, buf, cc);
			if (i < 0)
539
				die("%s: write: %s", Logname, geterr(errno));
540
			if (i != cc)
541
				die("%s: write: incomplete", Logname);
542
543
544
			if (runfile) {
				i = write(runfd, buf, cc);
				if (i < 0)
545
					die("%s: write: %s",
546
547
					    Runname, geterr(errno));
				if (i != cc)
548
					die("%s: write: incomplete", Runname);
549
			}
550
551
552
553
			(void) sigsetmask(omask);

		}
		if (FD_ISSET(ptyfd, &fds)) {
554
			omask = sigblock(sigmask(SIGUSR2));
555
			errno = 0;
556
557
558
559
560
561
562
563
564
#ifdef WITHSSL
			if (usingSSL) {
			        cc = SSL_read( sslCon, buf, sizeof(buf) );
				if (cc < 0) { cc = 0; } /* XXX hack */
			} else
#endif /* WITHSSL */ 
			{
			        cc = read(ptyfd, buf, sizeof(buf), 0);
			}
565
			(void) sigsetmask(omask);
566
567
568
569
			if (cc < 0) {
				/* XXX commonly observed */
				if (errno == EIO || errno == EAGAIN)
					continue;
570
571
572
573
#ifdef	USESOCKETS
				if (errno == ECONNRESET)
					goto disconnected;
#endif
574
				die("%s: read: %s", Ptyname, geterr(errno));
575
576
			}
			if (cc == 0) {
577
578
579
580
581
582
583
584
585
586
587
#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;
588
#else
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
				/*
				 * 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);
607
				continue;
608
#endif
609
610
611
			}
			errno = 0;

612
613
			omask = sigblock(sigmask(SIGHUP)|sigmask(SIGTERM)|
					 sigmask(SIGUSR1));
614
615
616
			for (lcc = 0; lcc < cc; lcc += i) {
				i = write(devfd, &buf[lcc], cc-lcc);
				if (i < 0) {
617
618
619
620
					/*
					 * Device backed up (or FUBARed)
					 * Note that we dropped some chars.
					 */
621
					if (errno == EAGAIN) {
622
623
624
#ifdef LOG_DROPS
						drop_todev_chars += (cc-lcc);
#endif
625
626
						goto dropped2;
					}
627
					die("%s: write: %s",
628
629
630
					    Devname, geterr(errno));
				}
				if (i == 0)
631
					die("%s: write: zero-length", Devname);
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
			}
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);
	
654
	if ((logfd = open(Logname, O_WRONLY|O_CREAT|O_APPEND, 0640)) < 0)
655
		die("%s: open: %s", Logname, geterr(errno));
656
	if (chmod(Logname, 0640) < 0)
657
		die("%s: chmod: %s", Logname, geterr(errno));
658
659
660
661
662
663
664
665
	
	dolog(LOG_NOTICE, "new log started");

	if (runfile)
		newrun(sig);
}

/*
666
667
668
 * 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.
669
670
671
672
673
674
675
676
677
 */
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);
678
	unlink(Runname);
679

680
	if ((runfd = open(Runname, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0)
681
		die("%s: open: %s", Runname, geterr(errno));
682
683
684
685
686
687
688
689
690
691
692
693

#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));
694
695
696
	
	dolog(LOG_NOTICE, "new run started");
}
697

698
699
/*
 * SIGUSR2 means we want to revoke the other side of the pty to close the
700
701
702
 * 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.
703
704
 */
void
705
terminate(int sig)
706
{
707
#ifdef	USESOCKETS
708
709
710
711
712
713
714
715
716
717
	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");
718

719
720
721
722
	tipuid = tipgid = 0;
	if (runfile)
		newrun(sig);

723
724
	/* Must be done *after* all the above stuff is done! */
	createkey();
725
#else
726
727
728
729
730
731
	int ofd = ptyfd;
	
	/*
	 * We know that the any pending access to the pty completed
	 * because we blocked SIGUSR2 during the operation.
	 */
732
733
734
735
736
737
738
739
#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");
740
741
	close(ptyfd);
	
742
	if ((ptyfd = open(Ptyname, O_RDWR)) < 0)
743
		die("%s: open: %s", Ptyname, geterr(errno));
744
745
746
747
748
749
750
751

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

752
753
#ifdef __FreeBSD__
	/* see explanation in capture() above */
754
	if ((ofd = open(Ttyname, O_RDONLY)) < 0)
755
756
		die("%s: open: %s", Ttyname, geterr(errno));
#endif
757
	if (fcntl(ptyfd, F_SETFL, O_NONBLOCK) < 0)
758
759
760
761
		die("%s: fcntl(O_NONBLOCK): %s", Ptyname, geterr(errno));
#ifdef __FreeBSD__
	close(ofd);
#endif
762
763
	
	dolog(LOG_NOTICE, "pty reset");
764
#endif	/* USESOCKETS */
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
}

/*
 *  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;
{
780
	char msgbuf[BUFSIZE];
781

782
	snprintf(msgbuf, BUFSIZE, format, arg0, arg1, arg2, arg3);
783
	dolog(LOG_WARNING, msgbuf);
784
785
786
787
788
}

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

791
	snprintf(msgbuf, BUFSIZE, format, arg0, arg1, arg2, arg3);
792
793
794
795
	dolog(LOG_ERR, msgbuf);
	quit(0);
}

796
797
798
dolog(level, format, arg0, arg1, arg2, arg3)
	int level;
	char *format, *arg0, *arg1, *arg2, *arg3;
799
{
800
	char msgbuf[BUFSIZE];
801

802
803
804
805
806
807
	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);
808
809
810
811
812
813
814
815
816
817
818
819
}

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

void
cleanup()
{
820
821
	dolog(LOG_NOTICE, "exiting");
#ifdef TWOPROCESS
822
823
	if (pid)
		(void) kill(pid, SIGTERM);
824
#endif
825
826
827
828
829
830
831
832
833
834
	(void) unlink(Pidname);
}

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

835
836
	if ((np = malloc((unsigned) strlen(str) + 1)) == NULL)
		die("malloc: out of memory");
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865

	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];
	
866
	if ((fd = open(Pidname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0)
867
		die("%s: open: %s", Pidname, geterr(errno));
868
869

	if (chmod(Pidname, 0644) < 0)
870
		die("%s: chmod: %s", Pidname, geterr(errno));
871
872
873
874
	
	(void) sprintf(buf, "%d\n", getpid());
	
	if (write(fd, buf, strlen(buf)) < 0)
875
		die("%s: write: %s", Pidname, geterr(errno));
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
	
	(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)
891
		die("%s: ioctl(TIOCGETP): %s", Device, geterr(errno));
892
893
894
895
	sgbuf.sg_ispeed = sgbuf.sg_ospeed = speed;
	sgbuf.sg_flags = RAW|TANDEM;
	bits = LDECCTQ;
	if (ioctl(devfd, TIOCSETP, (char *)&sgbuf) < 0)
896
		die("%s: ioctl(TIOCSETP): %s", Device, geterr(errno));
897
	if (ioctl(devfd, TIOCLBIS, (char *)&bits) < 0)
898
		die("%s: ioctl(TIOCLBIS): %s", Device, geterr(errno));
899
900
901
902
#else
	struct termios t;

	if (tcgetattr(devfd, &t) < 0)
903
		die("%s: tcgetattr: %s", Devname, geterr(errno));
904
905
906
907
908
909
910
911
912
913
914
915
	(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)
916
		die("%s: tcsetattr: %s", Devname, geterr(errno));
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
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#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;
For faster browsing, not all history is shown. View entire blame