Merge branch 'x86-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6] / 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 "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 };