xref: /linux/arch/um/drivers/pty.c (revision 2b8232ce512105e28453f301d1510de8363bccd1)
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 };
162