xref: /linux/arch/um/drivers/pty.c (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
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 
17 struct 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 
25 static 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 
37 static 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){
46 		err = -errno;
47 		printk("open_pts : Failed to open pts\n");
48 		return err;
49 	}
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 
68 static 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 
97 static 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 
121 struct chan_ops pty_ops = {
122 	.type		= "pty",
123 	.init		= pty_chan_init,
124 	.open		= pty_open,
125 	.close		= generic_close,
126 	.read		= generic_read,
127 	.write		= generic_write,
128 	.console_write	= generic_console_write,
129 	.window_size	= generic_window_size,
130 	.free		= generic_free,
131 	.winch		= 0,
132 };
133 
134 struct chan_ops pts_ops = {
135 	.type		= "pts",
136 	.init		= pty_chan_init,
137 	.open		= pts_open,
138 	.close		= generic_close,
139 	.read		= generic_read,
140 	.write		= generic_write,
141 	.console_write	= generic_console_write,
142 	.window_size	= generic_window_size,
143 	.free		= generic_free,
144 	.winch		= 0,
145 };
146 
147 /*
148  * Overrides for Emacs so that we follow Linus's tabbing style.
149  * Emacs will notice this stuff at the end of the file and automatically
150  * adjust the settings for this buffer only.  This must remain at the end
151  * of the file.
152  * ---------------------------------------------------------------------------
153  * Local variables:
154  * c-file-style: "linux"
155  * End:
156  */
157