summaryrefslogtreecommitdiffstats
path: root/src/tty.c
blob: 5ccc8cf4cd61ab5bd5fb7ae762018d00f65a6664 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <setjmp.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include "config.h"

static int setup_slave(int fd)
{
	struct termios tio;

	tcgetattr(fd, &tio);

	/* disable "\n" -> "\r\n" */
	tio.c_oflag &= ~ONLCR;

	return tcsetattr(fd, TCSANOW, &tio);
}

int tty_master(struct lt_config_app *cfg)
{
	int mfd;

	if ((mfd = getpt()) < 0) {
		perror("getpt failed");
		return -1;
	}

	if (unlockpt(mfd)) {
		perror("unlockpt failed");
		return -1;
	}

	PRINT_VERBOSE(cfg, 1, "pty master opened succesfully\n");
	return mfd;
}

int tty_init(struct lt_config_app *cfg, int master)
{
	int i, slave, num_files = getdtablesize();
	char *sname;
	jmp_buf env;

	if (setjmp(env)) {
		tty_restore(cfg);
		return -1;
	}

	sname = (char*) ptsname(master);
	if (!sname)
		longjmp(env, 1);

	PRINT_VERBOSE(cfg, 1, "closing all opened descriptors\n");
	for(i = 0; i < num_files; i++)
		close(i);

	/* get new session before we open new controling tty */
	if (-1 == setsid()) {
		perror("setsid failed");
		return -1;
	}

	slave = open(sname, O_RDWR);
	if (slave != 0)
		longjmp(env, 1);

	/* set controling tty */
	if (ioctl(0, TIOCSCTTY, 1))
		longjmp(env, 1);

	if (setup_slave(0))
		longjmp(env, 1);

	dup(0);
	dup(0);
	return 0;
}

void tty_close(struct lt_config_app *cfg)
{
	close(cfg->output_tty_fd);
}

int tty_restore(struct lt_config_app *cfg)
{
	int i, num_files = getdtablesize();

	for(i = 0; i < num_files; i++) {
		if (fcntl(i, F_GETFD, NULL) != -1)
			close(i);
	}

	open("/dev/tty", O_RDWR);
	dup(0);
	dup(0);

	return 0;
}

int tty_process(struct lt_config_app *cfg, int master)
{
#define BUFSIZE 4096
	char buf[BUFSIZE];
	ssize_t ret;
	int fd = cfg->output_tty_fd;

	if (fd == -1) {
		fd = open(cfg->output_tty_file, O_RDWR | O_CREAT | O_TRUNC,
				S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
		if (fd < 0) {
			perror("failed to open OUTPUT_TTY file,"
				" output is not logged");
			return -1;
		}
		PRINT_VERBOSE(cfg, 1, "opened tty output file %s\n",
				cfg->output_tty_file);

		cfg->output_tty_fd = fd;
	}

	ret = read(master, buf, BUFSIZE);
	/* Most likely the other side closed */
	if (ret <= 0) {
		PRINT_VERBOSE(cfg, 1,
			"failed to read tty, closing [ errno %d '%s']\n",
			errno, strerror(errno));
		return -1;
	}

	if (fd < 0)
		return -1;

	if (write(fd, buf, ret) <= 0) {
		perror("failed to write to OUTPUT_TTY file");
		return -1;
	}

	return 0;
}