xref: /linux/arch/um/drivers/pty.c (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
1 /*
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 #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  */
158