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