Pull ec into release branch
[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 <string.h>
10 #include <fcntl.h>
11 #include <errno.h>
12 #include <termios.h>
13 #include <sys/stat.h>
14 #include "chan_user.h"
15 #include "os.h"
16 #include "user.h"
17 #include "kern_constants.h"
18 #include "um_malloc.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 = 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                         return err;
60
61                 err = raw(fd);
62                 if (err)
63                         return err;
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
76 static int getmaster(char *line)
77 {
78         struct stat buf;
79         char *pty, *bank, *cp;
80         int master, err;
81
82         pty = &line[strlen("/dev/ptyp")];
83         for (bank = "pqrs"; *bank; bank++) {
84                 line[strlen("/dev/pty")] = *bank;
85                 *pty = '0';
86                 /* Did we hit the end ? */
87                 if ((stat(line, &buf) < 0) && (errno == ENOENT))
88                         break;
89
90                 for (cp = "0123456789abcdef"; *cp; cp++) {
91                         *pty = *cp;
92                         master = open(line, O_RDWR);
93                         if (master >= 0) {
94                                 char *tp = &line[strlen("/dev/")];
95
96                                 /* verify slave side is usable */
97                                 *tp = 't';
98                                 err = access(line, R_OK | W_OK);
99                                 *tp = 'p';
100                                 if(!err)
101                                         return master;
102                                 close(master);
103                         }
104                 }
105         }
106
107         printk(UM_KERN_ERR "getmaster - no usable host pty devices\n");
108         return -ENOENT;
109 }
110
111 static int pty_open(int input, int output, int primary, void *d,
112                     char **dev_out)
113 {
114         struct pty_chan *data = d;
115         int fd, err;
116         char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
117
118         fd = getmaster(dev);
119         if (fd < 0)
120                 return fd;
121
122         if(data->raw){
123                 err = raw(fd);
124                 if (err)
125                         return err;
126         }
127         
128         if (data->announce)
129                 (*data->announce)(dev, data->dev);
130
131         sprintf(data->dev_name, "%s", dev);
132         *dev_out = data->dev_name;
133
134         return fd;
135 }
136
137 const struct chan_ops pty_ops = {
138         .type           = "pty",
139         .init           = pty_chan_init,
140         .open           = pty_open,
141         .close          = generic_close,
142         .read           = generic_read,
143         .write          = generic_write,
144         .console_write  = generic_console_write,
145         .window_size    = generic_window_size,
146         .free           = generic_free,
147         .winch          = 0,
148 };
149
150 const struct chan_ops pts_ops = {
151         .type           = "pts",
152         .init           = pty_chan_init,
153         .open           = pts_open,
154         .close          = generic_close,
155         .read           = generic_read,
156         .write          = generic_write,
157         .console_write  = generic_console_write,
158         .window_size    = generic_window_size,
159         .free           = generic_free,
160         .winch          = 0,
161 };