Merge master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6] / arch / um / drivers / pty.c
1 /* 
2  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.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 <errno.h>
11 #include <termios.h>
12 #include "chan_user.h"
13 #include "user.h"
14 #include "kern_util.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 = um_kmalloc(sizeof(*data));
31         if(data == NULL) return(NULL);
32         *data = ((struct pty_chan) { .announce          = opts->announce, 
33                                      .dev               = device,
34                                      .raw               = opts->raw });
35         return(data);
36 }
37
38 static int pts_open(int input, int output, int primary, void *d,
39                     char **dev_out)
40 {
41         struct pty_chan *data = d;
42         char *dev;
43         int fd, err;
44
45         fd = get_pty();
46         if(fd < 0){
47                 err = -errno;
48                 printk("open_pts : Failed to open pts\n");
49                 return err;
50         }
51         if(data->raw){
52                 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
53                 if(err)
54                         return(err);
55
56                 err = raw(fd);
57                 if(err)
58                         return(err);
59         }
60
61         dev = ptsname(fd);
62         sprintf(data->dev_name, "%s", dev);
63         *dev_out = data->dev_name;
64         if (data->announce)
65                 (*data->announce)(dev, data->dev);
66         return(fd);
67 }
68
69 static int getmaster(char *line)
70 {
71         char *pty, *bank, *cp;
72         int master, err;
73
74         pty = &line[strlen("/dev/ptyp")];
75         for (bank = "pqrs"; *bank; bank++) {
76                 line[strlen("/dev/pty")] = *bank;
77                 *pty = '0';
78                 if (os_stat_file(line, NULL) < 0)
79                         break;
80                 for (cp = "0123456789abcdef"; *cp; cp++) {
81                         *pty = *cp;
82                         master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
83                         if (master >= 0) {
84                                 char *tp = &line[strlen("/dev/")];
85
86                                 /* verify slave side is usable */
87                                 *tp = 't';
88                                 err = os_access(line, OS_ACC_RW_OK);
89                                 *tp = 'p';
90                                 if(err == 0) return(master);
91                                 (void) os_close_file(master);
92                         }
93                 }
94         }
95         return(-1);
96 }
97
98 static int pty_open(int input, int output, int primary, void *d,
99                     char **dev_out)
100 {
101         struct pty_chan *data = d;
102         int fd, err;
103         char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
104
105         fd = getmaster(dev);
106         if(fd < 0)
107                 return(-errno);
108
109         if(data->raw){
110                 err = raw(fd);
111                 if(err)
112                         return(err);
113         }
114         
115         if(data->announce) (*data->announce)(dev, data->dev);
116
117         sprintf(data->dev_name, "%s", dev);
118         *dev_out = data->dev_name;
119         return(fd);
120 }
121
122 const struct chan_ops pty_ops = {
123         .type           = "pty",
124         .init           = pty_chan_init,
125         .open           = pty_open,
126         .close          = generic_close,
127         .read           = generic_read,
128         .write          = generic_write,
129         .console_write  = generic_console_write,
130         .window_size    = generic_window_size,
131         .free           = generic_free,
132         .winch          = 0,
133 };
134
135 const struct chan_ops pts_ops = {
136         .type           = "pts",
137         .init           = pty_chan_init,
138         .open           = pts_open,
139         .close          = generic_close,
140         .read           = generic_read,
141         .write          = generic_write,
142         .console_write  = generic_console_write,
143         .window_size    = generic_window_size,
144         .free           = generic_free,
145         .winch          = 0,
146 };
147
148 /*
149  * Overrides for Emacs so that we follow Linus's tabbing style.
150  * Emacs will notice this stuff at the end of the file and automatically
151  * adjust the settings for this buffer only.  This must remain at the end
152  * of the file.
153  * ---------------------------------------------------------------------------
154  * Local variables:
155  * c-file-style: "linux"
156  * End:
157  */