summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/bsd/pty.c
blob: 3189d24e123f0d17295a0616ab3d12ecef593553 (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
/* posix */
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <sys/pty.h>
#include "lib.h"
#include "sys9.h"
#include "dir.h"

/*
 * return the name of the slave
 */
char*
ptsname(int fd)
{
	Dir *d;
	static char buf[32];

	if((d = _dirfstat(fd)) == nil || strlen(d->name) < 4){
		free(d);
		_syserrno();
		return 0;
	}
	snprintf(buf, sizeof buf, "/dev/ptty%d", atoi(d->name+4));
	free(d);
	return buf;
}

/*
 * return the name of the master
 */
char*
ptmname(int fd)
{
	Dir *d;
	static char buf[32];

	if((d = _dirfstat(fd)) == nil || strlen(d->name) < 4){
		free(d);
		_syserrno();
		return 0;
	}

	snprintf(buf, sizeof buf, "/dev/ttym%d", atoi(d->name+4));
	return buf;
}

static char ptycl[] = "/dev/ptyclone";
static char fssrv[] = "/srv/ptyfs";

static void
mkserver(void)
{
	int fd, i;
	char *argv[3];

	fd = _OPEN(fssrv, O_RDWR);
	if(_MOUNT(fd, -1, "/dev", MAFTER, "") < 0) {
		/*
		 * remove fssrv here, if it exists, to avoid a race
		 * between the loop in the default case below and the
		 * new ptyfs removing fssrv when it starts.
		 * we otherwise might be unlucky enough to open the old
		 * (hung channel) fssrv before ptyfs removes it and break
		 * out of the loop with an open fd to a hung channel?
		 */
		_CLOSE(fd);
		_REMOVE(fssrv);
		switch(_RFORK(RFPROC|RFFDG)) {
		case -1:
			return;
		case 0:
			argv[0] = "ptyfs";
			argv[1] = 0;
			_EXEC("/bin/ape/ptyfs", argv);
			_EXITS(0);
		default:
			for(i = 0; i < 3; i++) {
				fd = _OPEN(fssrv, O_RDWR);
				if(fd >= 0)
					break;
				_SLEEP(1000);
			}
		}
		if(fd < 0)
			return;
		if(_MOUNT(fd, -1, "/dev", MAFTER, "") < 0)
			_CLOSE(fd);
	}
	/* successful _MOUNT closes fd */
}

/*
 * allocate a new pty
 */
int
_getpty(void)
{
	struct stat sb;

	if(stat(ptycl, &sb) < 0)
		mkserver();

	return open(ptycl, O_RDWR);
}