summaryrefslogtreecommitdiff
path: root/tty.c
blob: a430f0f11023a6231699aec621cbdcef79ef2aba (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
/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

void uutty_resize(int fd, int w, int h)
{
#ifdef TIOCSWINSZ
	struct winsize ws = { };
	ws.ws_col = w;
	ws.ws_row = h;
	ioctl(fd, TIOCSWINSZ, &ws);
#endif
}

/* #define posix_openpt(x) open("/dev/ptmx", x) */

int uutty_open(char **cmd, int w, int h)
{
	int ptm, pts;
	struct stat st;

	if (!cmd || !cmd[0] || stat(cmd[0], &st) < 0
	 || !S_ISCHR(st.st_mode)
	 || (ptm = open(cmd[0], O_RDWR|O_NOCTTY)) < 0
	 || (isatty(ptm) ? 0 : (close(ptm),1)) ) {

		if ((ptm = posix_openpt(O_RDWR|O_NOCTTY)) < 0)
			return -1;
		if (grantpt(ptm) < 0 || unlockpt(ptm) < 0) {
			close(ptm);
			return -1;
		}

		switch(fork()) {
		case -1:
			close(ptm);
			return -1;
		case 0:
			setsid();
			pts = open(ptsname(ptm), O_RDWR);
			close(ptm);
			dup2(pts, 0);
			dup2(pts, 1);
			dup2(pts, 2);
			if (pts > 2) close(pts);
			// FIXME............................
			if (cmd) execvp(cmd[0], cmd);
			else {
				char *s = getenv("SHELL");
				if (!s) s = "/bin/sh";
				execl(s, s, (char *)0);
			}
			return 1;
		}
	
		uutty_resize(ptm, w, h);
	}

	fcntl(ptm, F_SETFL, fcntl(ptm, F_GETFL)|O_NONBLOCK);

	return ptm;
}