Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/um/drivers/pty.c
10817 views
1
/*
2
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3
* Licensed under the GPL
4
*/
5
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <unistd.h>
9
#include <errno.h>
10
#include <fcntl.h>
11
#include <string.h>
12
#include <termios.h>
13
#include <sys/stat.h>
14
#include "chan_user.h"
15
#include "kern_constants.h"
16
#include "os.h"
17
#include "um_malloc.h"
18
#include "user.h"
19
20
struct pty_chan {
21
void (*announce)(char *dev_name, int dev);
22
int dev;
23
int raw;
24
struct termios tt;
25
char dev_name[sizeof("/dev/pts/0123456\0")];
26
};
27
28
static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
29
{
30
struct pty_chan *data;
31
32
data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
33
if (data == NULL)
34
return NULL;
35
36
*data = ((struct pty_chan) { .announce = opts->announce,
37
.dev = device,
38
.raw = opts->raw });
39
return data;
40
}
41
42
static int pts_open(int input, int output, int primary, void *d,
43
char **dev_out)
44
{
45
struct pty_chan *data = d;
46
char *dev;
47
int fd, err;
48
49
fd = get_pty();
50
if (fd < 0) {
51
err = -errno;
52
printk(UM_KERN_ERR "open_pts : Failed to open pts\n");
53
return err;
54
}
55
56
if (data->raw) {
57
CATCH_EINTR(err = tcgetattr(fd, &data->tt));
58
if (err)
59
goto out_close;
60
61
err = raw(fd);
62
if (err)
63
goto out_close;
64
}
65
66
dev = ptsname(fd);
67
sprintf(data->dev_name, "%s", dev);
68
*dev_out = data->dev_name;
69
70
if (data->announce)
71
(*data->announce)(dev, data->dev);
72
73
return fd;
74
75
out_close:
76
close(fd);
77
return err;
78
}
79
80
static int getmaster(char *line)
81
{
82
struct stat buf;
83
char *pty, *bank, *cp;
84
int master, err;
85
86
pty = &line[strlen("/dev/ptyp")];
87
for (bank = "pqrs"; *bank; bank++) {
88
line[strlen("/dev/pty")] = *bank;
89
*pty = '0';
90
/* Did we hit the end ? */
91
if ((stat(line, &buf) < 0) && (errno == ENOENT))
92
break;
93
94
for (cp = "0123456789abcdef"; *cp; cp++) {
95
*pty = *cp;
96
master = open(line, O_RDWR);
97
if (master >= 0) {
98
char *tp = &line[strlen("/dev/")];
99
100
/* verify slave side is usable */
101
*tp = 't';
102
err = access(line, R_OK | W_OK);
103
*tp = 'p';
104
if (!err)
105
return master;
106
close(master);
107
}
108
}
109
}
110
111
printk(UM_KERN_ERR "getmaster - no usable host pty devices\n");
112
return -ENOENT;
113
}
114
115
static int pty_open(int input, int output, int primary, void *d,
116
char **dev_out)
117
{
118
struct pty_chan *data = d;
119
int fd, err;
120
char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
121
122
fd = getmaster(dev);
123
if (fd < 0)
124
return fd;
125
126
if (data->raw) {
127
err = raw(fd);
128
if (err) {
129
close(fd);
130
return err;
131
}
132
}
133
134
if (data->announce)
135
(*data->announce)(dev, data->dev);
136
137
sprintf(data->dev_name, "%s", dev);
138
*dev_out = data->dev_name;
139
140
return fd;
141
}
142
143
const struct chan_ops pty_ops = {
144
.type = "pty",
145
.init = pty_chan_init,
146
.open = pty_open,
147
.close = generic_close,
148
.read = generic_read,
149
.write = generic_write,
150
.console_write = generic_console_write,
151
.window_size = generic_window_size,
152
.free = generic_free,
153
.winch = 0,
154
};
155
156
const struct chan_ops pts_ops = {
157
.type = "pts",
158
.init = pty_chan_init,
159
.open = pts_open,
160
.close = generic_close,
161
.read = generic_read,
162
.write = generic_write,
163
.console_write = generic_console_write,
164
.window_size = generic_window_size,
165
.free = generic_free,
166
.winch = 0,
167
};
168
169