capture.c 31.6 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
/*
 * EMULAB-COPYRIGHT
3
 * Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
4
 * All rights reserved.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 */

/*
 * 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.
 */
20
21

#define SAFEMODE
22
23
24
25
26
27
28
29
30
	
#include <sys/param.h>

#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <syslog.h>
#include <termios.h>
#include <errno.h>
31
32
#include <stdlib.h>
#include <stdarg.h>
33
34
35
36
37
38
39
40
41

#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>
42
43
44
45
46
#ifdef USESOCKETS
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
47
48
#include <setjmp.h>
#include <netdb.h>
49
50
51
52
53
#ifdef WITHSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif /* WITHSSL */
#endif /* USESOCKETS */
54
#include "capdecls.h"
55
#include "config.h"
56
57
58
59
60

#define geterr(e)	strerror(e)

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

void usage(void);
void warn(char *format, ...);
void die(char *format, ...);
void dolog(int level, char *format, ...);
70
71
72

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

76
77
78
79
80
/*
 *  Configurable things.
 */
#define PIDNAME		"%s/%s.pid"
#define LOGNAME		"%s/%s.log"
81
#define RUNNAME		"%s/%s.run"
82
83
84
#define TTYNAME		"%s/%s"
#define PTYNAME		"%s/%s-pty"
#define ACLNAME		"%s/%s.acl"
85
#define DEVNAME		"%s/%s"
86
#define BUFSIZE		4096
87
#define DROP_THRESH	(32*1024)
88

89
#define DEFAULT_CERTFILE PREFIX"/etc/capture.pem"
Chad Barb's avatar
   
Chad Barb committed
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
int	logfd, runfd, devfd, ptyfd;
100
int	hwflow = 0, speed = B9600, debug = 0, runfile = 0, standalone = 0;
101
int	stampinterval = -1;
102
103
sigset_t actionsigmask;
sigset_t allsigmask;
104
#ifdef  USESOCKETS
105
106
107
char		  *Bossnode = BOSSNODE;
char		  *Aclname;
int		   serverport = SERVERPORT;
108
int		   sockfd, tipactive, portnum;
109
struct sockaddr_in tipclient;
110
111
112
secretkey_t	   secretkey;
char		   ourhostname[MAXHOSTNAMELEN];
int		   needshake;
113
114
gid_t		   tipgid;
uid_t		   tipuid;
115
116
117
118
119
120
121
122
123
124
125
126
127

#ifdef  WITHSSL

SSL_CTX * ctx;
SSL * sslCon;

int initializedSSL = 0;
int usingSSL = 0;

const char * certfile = NULL;

#endif /* WITHSSL */ 
#endif /* USESOCKETS */
128
129

int
130
main(int argc, char **argv)
131
132
133
{
	char strbuf[MAXPATHLEN], *newstr();
	int flags, op, i;
134
	struct sigaction sa;
135
136
	extern int optind;
	extern char *optarg;
137
138
139
#ifdef  USESOCKETS
	struct sockaddr_in name;
#endif
140
141
142

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

143
	while ((op = getopt(argc, argv, "rds:Hb:ip:c:T:")) != EOF)
144
		switch (op) {
145
#ifdef	USESOCKETS
146
147
148
149
150
#ifdef  WITHSSL
		case 'c':
		        certfile = optarg;
		        break;
#endif  WITHSSL
151
152
153
		case 'b':
			Bossnode = optarg;
			break;
154
155
156
157

		case 'p':
			serverport = atoi(optarg);
			break;
158
159
160
161

		case 'i':
			standalone = 1;
			break;
162
#endif /* USESOCKETS */
163
164
165
166
		case 'H':
			++hwflow;
			break;

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

		case 'r':
			runfile++;
			break;

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

	argc -= optind;
	argv += optind;

	if (argc != 2)
		usage();

193
194
195
	if (!debug)
		(void)daemon(0, 0);

196
197
198
199
200
201
	Machine = argv[0];

	(void) sprintf(strbuf, PIDNAME, LOGPATH, argv[0]);
	Pidname = newstr(strbuf);
	(void) sprintf(strbuf, LOGNAME, LOGPATH, argv[0]);
	Logname = newstr(strbuf);
202
203
	(void) sprintf(strbuf, RUNNAME, LOGPATH, argv[0]);
	Runname = newstr(strbuf);
204
	(void) sprintf(strbuf, TTYNAME, TIPPATH, argv[0]);
205
	Ttyname = newstr(strbuf);
206
	(void) sprintf(strbuf, PTYNAME, TIPPATH, argv[0]);
207
208
209
210
211
212
213
	Ptyname = newstr(strbuf);
	(void) sprintf(strbuf, DEVNAME, DEVPATH, argv[1]);
	Devname = newstr(strbuf);

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

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
	/*
	 * We process the "action" signals sequentially, there are just
	 * too many interdependencies.  We block em while we shut down too.
	 */
	sigemptyset(&actionsigmask);
	sigaddset(&actionsigmask, SIGHUP);
	sigaddset(&actionsigmask, SIGUSR1);
	sigaddset(&actionsigmask, SIGUSR2);
	allsigmask = actionsigmask;
	sigaddset(&allsigmask, SIGINT);
	sigaddset(&allsigmask, SIGTERM);
	memset(&sa, 0, sizeof sa);
	sa.sa_handler = quit;
	sa.sa_mask = allsigmask;
	sigaction(SIGINT, &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);
	sa.sa_handler = reinit;
	sa.sa_mask = actionsigmask;
	sigaction(SIGHUP, &sa, NULL);
	if (runfile) {
		sa.sa_handler = newrun;
		sigaction(SIGUSR1, &sa, NULL);
	}
	sa.sa_handler = terminate;
	sigaction(SIGUSR2, &sa, NULL);

240
241
	srandomdev();
	
242
	/*
243
	 * Open up run/log file, console tty, and controlling pty.
244
	 */
245
	if ((logfd = open(Logname, O_WRONLY|O_CREAT|O_APPEND, 0640)) < 0)
246
		die("%s: open: %s", Logname, geterr(errno));
247
	if (chmod(Logname, 0640) < 0)
248
		die("%s: chmod: %s", Logname, geterr(errno));
249
250

	if (runfile) {
251
252
253
		unlink(Runname);
		
		if ((runfd = open(Runname,O_WRONLY|O_CREAT|O_APPEND,0600)) < 0)
254
			die("%s: open: %s", Runname, geterr(errno));
255
256
		if (fchmod(runfd, 0640) < 0)
			die("%s: fchmod: %s", Runname, geterr(errno));
257
	}
258
#ifdef  USESOCKETS
259
260
261
	(void) sprintf(strbuf, ACLNAME, ACLPATH, Machine);
	Aclname = newstr(strbuf);
	
262
263
264
265
266
267
268
269
270
271
272
	/*
	 * 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));
273
	
274
275
276
277
278
279
280
281
282
283
284
285
286
287
	/* 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)
288
		die("listen(): %s", geterr(errno));
289

290
291
	if (gethostname(ourhostname, sizeof(ourhostname)) < 0)
		die("gethostname(): %s", geterr(errno));
292

293
294
	createkey();
	dolog(LOG_NOTICE, "Ready! Listening on TCP port %d", portnum);
295
#else
296
	if ((ptyfd = open(Ptyname, O_RDWR)) < 0)
297
		die("%s: open: %s", Ptyname, geterr(errno));
298
#endif
299
	if ((devfd = open(Devname, O_RDWR|O_NONBLOCK)) < 0)
300
		die("%s: open: %s", Devname, geterr(errno));
301
302

	if (ioctl(devfd, TIOCEXCL, 0) < 0)
303
		warn("TIOCEXCL %s: %s", Devname, geterr(errno));
304
305
306
307
308
309
310
311
312
313

	writepid();
	rawmode(speed);

	capture();

	cleanup();
	exit(0);
}

314
315
316
#ifdef TWOPROCESS
int	pid;

317
void
318
capture(void)
319
320
321
322
323
324
325
326
327
328
329
330
331
332
{
	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.
 */
333
in(void)
334
{
335
	char buf[BUFSIZE];
336
337
	int cc;
	sigset_t omask;
338
339
	
	while (1) {
340
		if ((cc = read(devfd, buf, BUFSIZE)) < 0) {
341
342
343
			if ((errno == EWOULDBLOCK) || (errno == EINTR))
				continue;
			else
344
				die("%s: read: %s", Devname, geterr(errno));
345
		}
346
		sigprocmask(SIG_BLOCK, &actionsigmask, &omask);
347
348

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

351
352
		if (runfile) {
			if (write(runfd, buf, cc) < 0)
353
				die("%s: write: %s", Runname, geterr(errno));
354
355
		}

356
357
		if (write(ptyfd, buf, cc) < 0) {
			if ((errno != EIO) && (errno != EWOULDBLOCK))
358
				die("%s: write: %s", Ptyname, geterr(errno));
359
		}
360
		sigprocmask(SIG_SETMASK, &omask, NULL);
361
362
363
364
365
366
	}
}

/*
 * Loop reading input from pty (tip), and send off to the console device.
 */
367
out(void)
368
{
369
	char buf[BUFSIZE];
370
371
	int cc;
	sigset_t omask;
372
373
374
375
376
377
	struct timeval timeout;

	timeout.tv_sec  = 0;
	timeout.tv_usec = 100000;
	
	while (1) {
378
		sigprocmask(SIG_BLOCK, &actionsigmask, &omask);
379
		if ((cc = read(ptyfd, buf, BUFSIZE)) < 0) {
380
			sigprocmask(SIG_SETMASK, &omask, NULL);
381
382
383
384
385
386
			if ((errno == EIO) || (errno == EWOULDBLOCK) ||
			    (errno == EINTR)) {
				select(0, 0, 0, 0, &timeout);
				continue;
			}
			else
387
				die("%s: read: %s", Ptyname, geterr(errno));
388
389
390
		}

		if (write(devfd, buf, cc) < 0)
391
			die("%s: write: %s", Devname, geterr(errno));
392
		
393
		sigprocmask(SIG_SETMASK, &omask, NULL);
394
395
396
	}
}
#else
397
398
static fd_set	sfds;
static int	fdcount;
399
void
400
capture(void)
401
{
402
	fd_set fds;
403
404
	int i, cc, lcc;
	sigset_t omask;
405
	char buf[BUFSIZE];
406
	struct timeval timeout;
407
408
409
410
#ifdef LOG_DROPS
	int drop_topty_chars = 0;
	int drop_todev_chars = 0;
#endif
411

412
413
414
415
416
417
418
419
420
421
422
423
424
	/*
	 * 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
425
	if (fcntl(devfd, F_SETFL, O_NONBLOCK) < 0)
426
		die("%s: fcntl(O_NONBLOCK): %s", Devname, geterr(errno));
427
#ifndef USESOCKETS
428
429
430
431
432
433
434
435
436
437
438
439
	/*
	 * 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__
440
	if ((i = open(Ttyname, O_RDONLY)) < 0)
441
442
443
444
445
		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__
446
	close(i);
447
#endif
448
#endif /* USESOCKETS */
449
450
451

	FD_ZERO(&sfds);
	FD_SET(devfd, &sfds);
452
453
454
455
456
457
458
459
	fdcount = devfd;
#ifdef  USESOCKETS
	if (devfd < sockfd)
		fdcount = sockfd;
	FD_SET(sockfd, &sfds);
#else
	if (devfd < ptyfd)
		fdcount = ptyfd;
460
	FD_SET(ptyfd, &sfds);
461
462
463
464
#endif	/* USESOCKETS */

	fdcount++;

465
	for (;;) {
466
467
468
469
470
471
472
473
#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;
474
		}
475
#endif
476
		fds = sfds;
477
		timeout.tv_usec = 0;
478
		timeout.tv_sec  = 30;
479
#ifdef	USESOCKETS
480
481
482
		if (needshake) {
			timeout.tv_sec += (random() % 60);
		}
483
484
#endif
		i = select(fdcount, &fds, NULL, NULL, &timeout);
485
486
487
488
489
		if (i < 0) {
			if (errno == EINTR) {
				warn("input select interrupted, continuing");
				continue;
			}
490
			die("%s: select: %s", Devname, geterr(errno));
491
		}
492
		if (i == 0) {
493
494
495
496
497
498
#ifdef	USESOCKETS
			if (needshake) {
				handshake();
				continue;
			}
#endif
499
500
			continue;
		}
501
502
#ifdef	USESOCKETS
		if (FD_ISSET(sockfd, &fds)) {
503
			clientconnect();
504
505
		}
#endif	/* USESOCKETS */
506
507
508
509
		if (FD_ISSET(devfd, &fds)) {
			errno = 0;
			cc = read(devfd, buf, sizeof(buf));
			if (cc < 0)
510
				die("%s: read: %s", Devname, geterr(errno));
511
			if (cc == 0)
512
				die("%s: read: EOF", Devname);
513
514
			errno = 0;

515
			sigprocmask(SIG_BLOCK, &actionsigmask, &omask);
516
517
518
519
#ifdef	USESOCKETS
			if (!tipactive)
				goto dropped;
#endif
520
			for (lcc = 0; lcc < cc; lcc += i) {
521
522
523
524
525
526
527
528
529
#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);
				}
530
				if (i < 0) {
531
532
533
534
535
536
537
					/*
					 * 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.
					 */
538
					if (errno == EIO || errno == EAGAIN) {
539
540
#ifdef LOG_DROPS
						drop_topty_chars += (cc-lcc);
541
542
543
#endif
						goto dropped;
					}
544
					die("%s: write: %s",
545
546
					    Ptyname, geterr(errno));
				}
547
548
549
550
				if (i == 0) {
#ifdef	USESOCKETS
					goto disconnected;
#else
551
					die("%s: write: zero-length", Ptyname);
552
553
#endif
				}
554
555
			}
dropped:
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
			if (stampinterval >= 0) {
				static time_t laststamp;
				struct timeval tv;
				char stampbuf[40], *cts;
				time_t now;

				gettimeofday(&tv, 0);
				now = tv.tv_sec;
				if (stampinterval == 0 ||
				    now > laststamp + stampinterval) {
					cts = ctime(&now);
					cts[24] = 0;
					snprintf(stampbuf, sizeof stampbuf,
						 "\nSTAMP{%s}\n", cts);
					write(logfd, stampbuf,
					      strlen(stampbuf));
				}
				laststamp = now;
			}
575
576
			i = write(logfd, buf, cc);
			if (i < 0)
577
				die("%s: write: %s", Logname, geterr(errno));
578
			if (i != cc)
579
				die("%s: write: incomplete", Logname);
580
581
582
			if (runfile) {
				i = write(runfd, buf, cc);
				if (i < 0)
583
					die("%s: write: %s",
584
585
					    Runname, geterr(errno));
				if (i != cc)
586
					die("%s: write: incomplete", Runname);
587
			}
588
			sigprocmask(SIG_SETMASK, &omask, NULL);
589
590
591

		}
		if (FD_ISSET(ptyfd, &fds)) {
592
			sigprocmask(SIG_BLOCK, &actionsigmask, &omask);
593
			errno = 0;
594
595
596
597
598
599
600
601
602
#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);
			}
603
			sigprocmask(SIG_SETMASK, &omask, NULL);
604
605
606
607
			if (cc < 0) {
				/* XXX commonly observed */
				if (errno == EIO || errno == EAGAIN)
					continue;
608
609
610
611
#ifdef	USESOCKETS
				if (errno == ECONNRESET)
					goto disconnected;
#endif
612
				die("%s: read: %s", Ptyname, geterr(errno));
613
614
			}
			if (cc == 0) {
615
616
617
618
619
620
621
622
623
624
625
#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;
626
#else
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
				/*
				 * 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);
645
				continue;
646
#endif
647
648
649
			}
			errno = 0;

650
			sigprocmask(SIG_BLOCK, &actionsigmask, &omask);
651
652
653
			for (lcc = 0; lcc < cc; lcc += i) {
				i = write(devfd, &buf[lcc], cc-lcc);
				if (i < 0) {
654
655
656
657
					/*
					 * Device backed up (or FUBARed)
					 * Note that we dropped some chars.
					 */
658
					if (errno == EAGAIN) {
659
660
661
#ifdef LOG_DROPS
						drop_todev_chars += (cc-lcc);
#endif
662
663
						goto dropped2;
					}
664
					die("%s: write: %s",
665
666
667
					    Devname, geterr(errno));
				}
				if (i == 0)
668
					die("%s: write: zero-length", Devname);
669
670
			}
dropped2:
671
			sigprocmask(SIG_SETMASK, &omask, NULL);
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
		}
	}
}
#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);
	
690
	if ((logfd = open(Logname, O_WRONLY|O_CREAT|O_APPEND, 0640)) < 0)
691
		die("%s: open: %s", Logname, geterr(errno));
692
	if (chmod(Logname, 0640) < 0)
693
		die("%s: chmod: %s", Logname, geterr(errno));
694
695
696
697
698
699
700
701
	
	dolog(LOG_NOTICE, "new log started");

	if (runfile)
		newrun(sig);
}

/*
702
703
704
 * 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.
705
706
707
708
709
710
711
712
713
 */
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);
714
	unlink(Runname);
715

716
	if ((runfd = open(Runname, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0)
717
		die("%s: open: %s", Runname, geterr(errno));
718
719
720
721
722
723
724
725
726
727
728
729

#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));
730
731
732
	
	dolog(LOG_NOTICE, "new run started");
}
733

734
735
/*
 * SIGUSR2 means we want to revoke the other side of the pty to close the
736
737
738
 * 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.
739
740
 */
void
741
terminate(int sig)
742
{
743
#ifdef	USESOCKETS
744
745
746
747
748
749
750
751
752
753
	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");
754

755
756
757
758
	tipuid = tipgid = 0;
	if (runfile)
		newrun(sig);

759
760
	/* Must be done *after* all the above stuff is done! */
	createkey();
761
#else
762
763
764
765
766
767
	int ofd = ptyfd;
	
	/*
	 * We know that the any pending access to the pty completed
	 * because we blocked SIGUSR2 during the operation.
	 */
768
769
770
	tcflush(ptyfd, TCIOFLUSH);
	if (revoke(Ttyname) < 0)
		dolog(LOG_WARNING, "could not revoke access to tty");
771
772
	close(ptyfd);
	
773
	if ((ptyfd = open(Ptyname, O_RDWR)) < 0)
774
		die("%s: open: %s", Ptyname, geterr(errno));
775
776
777
778
779
780
781
782

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

783
784
#ifdef __FreeBSD__
	/* see explanation in capture() above */
785
	if ((ofd = open(Ttyname, O_RDONLY)) < 0)
786
787
		die("%s: open: %s", Ttyname, geterr(errno));
#endif
788
	if (fcntl(ptyfd, F_SETFL, O_NONBLOCK) < 0)
789
790
791
792
		die("%s: fcntl(O_NONBLOCK): %s", Ptyname, geterr(errno));
#ifdef __FreeBSD__
	close(ofd);
#endif
793
794
	
	dolog(LOG_NOTICE, "pty reset");
795
#endif	/* USESOCKETS */
796
797
798
799
800
}

/*
 *  Display proper usage / error message and exit.
 */
801
802
803
804
805
806
807
808
char *optstr =
#ifdef USESOCKETS
#ifdef WITHSSL
"[-c certfile] "
#endif
"[-b bossnode] [-p bossport] [-i] "
#endif
"-Hdr [-s speed] [-T stampinterval]";
809
void
810
usage(void)
811
{
812
	fprintf(stderr, "usage: %s %s machine tty\n", Progname, optstr);
813
814
815
	exit(1);
}

816
817
void
warn(char *format, ...)
818
{
819
	char msgbuf[BUFSIZE];
820
	va_list ap;
821

822
823
824
	va_start(ap, format);
	vsnprintf(msgbuf, BUFSIZE, format, ap);
	va_end(ap);
825
	dolog(LOG_WARNING, msgbuf);
826
827
}

828
829
void
die(char *format, ...)
830
{
831
	char msgbuf[BUFSIZE];
832
	va_list ap;
833

834
835
836
	va_start(ap, format);
	vsnprintf(msgbuf, BUFSIZE, format, ap);
	va_end(ap);
837
838
839
840
	dolog(LOG_ERR, msgbuf);
	quit(0);
}

841
842
void
dolog(int level, char *format, ...)
843
{
844
	char msgbuf[BUFSIZE];
845
	va_list ap;
846

847
848
849
	va_start(ap, format);
	vsnprintf(msgbuf, BUFSIZE, format, ap);
	va_end(ap);
850
851
852
853
854
	if (debug) {
		fprintf(stderr, "%s - %s\n", Machine, msgbuf);
		fflush(stderr);
	}
	syslog(level, "%s - %s\n", Machine, msgbuf);
855
856
857
858
859
860
861
862
863
864
}

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

void
865
cleanup(void)
866
{
867
868
	dolog(LOG_NOTICE, "exiting");
#ifdef TWOPROCESS
869
870
	if (pid)
		(void) kill(pid, SIGTERM);
871
#endif
872
873
874
875
	(void) unlink(Pidname);
}

char *
876
newstr(char *str)
877
{
878
	char *np;
879

880
	if ((np = malloc((unsigned) strlen(str) + 1)) == NULL)
881
		die("malloc: out of memory");
882
883
884
885
886
887
888

	return(strcpy(np, str));
}

/*
 * Open up PID file and write our pid into it.
 */
889
writepid(void)
890
891
892
893
{
	int fd;
	char buf[8];
	
894
	if ((fd = open(Pidname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0)
895
		die("%s: open: %s", Pidname, geterr(errno));
896
897

	if (chmod(Pidname, 0644) < 0)
898
		die("%s: chmod: %s", Pidname, geterr(errno));
899
900
901
902
	
	(void) sprintf(buf, "%d\n", getpid());
	
	if (write(fd, buf, strlen(buf)) < 0)
903
		die("%s: write: %s", Pidname, geterr(errno));
904
905
906
907
908
909
910
	
	(void) close(fd);
}

/*
 * Put the console line into raw mode.
 */
911
rawmode(int speed)
912
913
914
915
{
	struct termios t;

	if (tcgetattr(devfd, &t) < 0)
916
		die("%s: tcgetattr: %s", Devname, geterr(errno));
917
918
919
920
921
922
923
924
925
926
927
928
	(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)
929
		die("%s: tcsetattr: %s", Devname, geterr(errno));
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
}

/*
 * 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 },
For faster browsing, not all history is shown. View entire blame