blob: 0306a1b215b7d8016f04bd3eca2dba996ee53dfa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <string.h>
9#include <errno.h>
10#include <termios.h>
11#include "chan_user.h"
12#include "user.h"
13#include "user_util.h"
14#include "kern_util.h"
15#include "os.h"
16
17struct pty_chan {
18 void (*announce)(char *dev_name, int dev);
19 int dev;
20 int raw;
21 struct termios tt;
22 char dev_name[sizeof("/dev/pts/0123456\0")];
23};
24
25static void *pty_chan_init(char *str, int device, struct chan_opts *opts)
26{
27 struct pty_chan *data;
28
29 data = um_kmalloc(sizeof(*data));
30 if(data == NULL) return(NULL);
31 *data = ((struct pty_chan) { .announce = opts->announce,
32 .dev = device,
33 .raw = opts->raw });
34 return(data);
35}
36
37static int pts_open(int input, int output, int primary, void *d,
38 char **dev_out)
39{
40 struct pty_chan *data = d;
41 char *dev;
42 int fd, err;
43
44 fd = get_pty();
45 if(fd < 0){
Jeff Dikeb4fd3102005-09-16 19:27:49 -070046 err = -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 printk("open_pts : Failed to open pts\n");
Jeff Dikeb4fd3102005-09-16 19:27:49 -070048 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 }
50 if(data->raw){
51 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
52 if(err)
53 return(err);
54
55 err = raw(fd);
56 if(err)
57 return(err);
58 }
59
60 dev = ptsname(fd);
61 sprintf(data->dev_name, "%s", dev);
62 *dev_out = data->dev_name;
63 if (data->announce)
64 (*data->announce)(dev, data->dev);
65 return(fd);
66}
67
68static int getmaster(char *line)
69{
70 char *pty, *bank, *cp;
71 int master, err;
72
73 pty = &line[strlen("/dev/ptyp")];
74 for (bank = "pqrs"; *bank; bank++) {
75 line[strlen("/dev/pty")] = *bank;
76 *pty = '0';
77 if (os_stat_file(line, NULL) < 0)
78 break;
79 for (cp = "0123456789abcdef"; *cp; cp++) {
80 *pty = *cp;
81 master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
82 if (master >= 0) {
83 char *tp = &line[strlen("/dev/")];
84
85 /* verify slave side is usable */
86 *tp = 't';
87 err = os_access(line, OS_ACC_RW_OK);
88 *tp = 'p';
89 if(err == 0) return(master);
90 (void) os_close_file(master);
91 }
92 }
93 }
94 return(-1);
95}
96
97static int pty_open(int input, int output, int primary, void *d,
98 char **dev_out)
99{
100 struct pty_chan *data = d;
101 int fd, err;
102 char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
103
104 fd = getmaster(dev);
105 if(fd < 0)
106 return(-errno);
107
108 if(data->raw){
109 err = raw(fd);
110 if(err)
111 return(err);
112 }
113
114 if(data->announce) (*data->announce)(dev, data->dev);
115
116 sprintf(data->dev_name, "%s", dev);
117 *dev_out = data->dev_name;
118 return(fd);
119}
120
121static int pty_console_write(int fd, const char *buf, int n, void *d)
122{
123 struct pty_chan *data = d;
124
125 return(generic_console_write(fd, buf, n, &data->tt));
126}
127
128struct chan_ops pty_ops = {
129 .type = "pty",
130 .init = pty_chan_init,
131 .open = pty_open,
132 .close = generic_close,
133 .read = generic_read,
134 .write = generic_write,
135 .console_write = pty_console_write,
136 .window_size = generic_window_size,
137 .free = generic_free,
138 .winch = 0,
139};
140
141struct chan_ops pts_ops = {
142 .type = "pts",
143 .init = pty_chan_init,
144 .open = pts_open,
145 .close = generic_close,
146 .read = generic_read,
147 .write = generic_write,
148 .console_write = pty_console_write,
149 .window_size = generic_window_size,
150 .free = generic_free,
151 .winch = 0,
152};
153
154/*
155 * Overrides for Emacs so that we follow Linus's tabbing style.
156 * Emacs will notice this stuff at the end of the file and automatically
157 * adjust the settings for this buffer only. This must remain at the end
158 * of the file.
159 * ---------------------------------------------------------------------------
160 * Local variables:
161 * c-file-style: "linux"
162 * End:
163 */