blob: aa311afa966761c90e9229d4c8d6f57fa4ccb864 [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>
Jeff Dike24fa6c02007-05-06 14:51:09 -07007#include <stdlib.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#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 "user_util.h"
15#include "kern_util.h"
16#include "os.h"
Paolo 'Blaisorblade' Giarrussoc13e5692006-10-19 23:28:20 -070017#include "um_malloc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19struct pty_chan {
20 void (*announce)(char *dev_name, int dev);
21 int dev;
22 int raw;
23 struct termios tt;
24 char dev_name[sizeof("/dev/pts/0123456\0")];
25};
26
Jeff Dike5e7672e2006-09-27 01:50:33 -070027static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -070028{
29 struct pty_chan *data;
30
31 data = um_kmalloc(sizeof(*data));
32 if(data == NULL) return(NULL);
33 *data = ((struct pty_chan) { .announce = opts->announce,
34 .dev = device,
35 .raw = opts->raw });
36 return(data);
37}
38
39static int pts_open(int input, int output, int primary, void *d,
40 char **dev_out)
41{
42 struct pty_chan *data = d;
43 char *dev;
44 int fd, err;
45
46 fd = get_pty();
47 if(fd < 0){
Jeff Dikeb4fd3102005-09-16 19:27:49 -070048 err = -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 printk("open_pts : Failed to open pts\n");
Jeff Dikeb4fd3102005-09-16 19:27:49 -070050 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 }
52 if(data->raw){
53 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
54 if(err)
55 return(err);
56
57 err = raw(fd);
58 if(err)
59 return(err);
60 }
61
62 dev = ptsname(fd);
63 sprintf(data->dev_name, "%s", dev);
64 *dev_out = data->dev_name;
65 if (data->announce)
66 (*data->announce)(dev, data->dev);
67 return(fd);
68}
69
70static int getmaster(char *line)
71{
72 char *pty, *bank, *cp;
73 int master, err;
74
75 pty = &line[strlen("/dev/ptyp")];
76 for (bank = "pqrs"; *bank; bank++) {
77 line[strlen("/dev/pty")] = *bank;
78 *pty = '0';
79 if (os_stat_file(line, NULL) < 0)
80 break;
81 for (cp = "0123456789abcdef"; *cp; cp++) {
82 *pty = *cp;
83 master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
84 if (master >= 0) {
85 char *tp = &line[strlen("/dev/")];
86
87 /* verify slave side is usable */
88 *tp = 't';
89 err = os_access(line, OS_ACC_RW_OK);
90 *tp = 'p';
91 if(err == 0) return(master);
92 (void) os_close_file(master);
93 }
94 }
95 }
96 return(-1);
97}
98
99static int pty_open(int input, int output, int primary, void *d,
100 char **dev_out)
101{
102 struct pty_chan *data = d;
103 int fd, err;
104 char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
105
106 fd = getmaster(dev);
107 if(fd < 0)
108 return(-errno);
109
110 if(data->raw){
111 err = raw(fd);
112 if(err)
113 return(err);
114 }
115
116 if(data->announce) (*data->announce)(dev, data->dev);
117
118 sprintf(data->dev_name, "%s", dev);
119 *dev_out = data->dev_name;
120 return(fd);
121}
122
Jeff Dike5e7672e2006-09-27 01:50:33 -0700123const struct chan_ops pty_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 .type = "pty",
125 .init = pty_chan_init,
126 .open = pty_open,
127 .close = generic_close,
128 .read = generic_read,
129 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800130 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 .window_size = generic_window_size,
132 .free = generic_free,
133 .winch = 0,
134};
135
Jeff Dike5e7672e2006-09-27 01:50:33 -0700136const struct chan_ops pts_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 .type = "pts",
138 .init = pty_chan_init,
139 .open = pts_open,
140 .close = generic_close,
141 .read = generic_read,
142 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800143 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 .window_size = generic_window_size,
145 .free = generic_free,
146 .winch = 0,
147};
148
149/*
150 * Overrides for Emacs so that we follow Linus's tabbing style.
151 * Emacs will notice this stuff at the end of the file and automatically
152 * adjust the settings for this buffer only. This must remain at the end
153 * of the file.
154 * ---------------------------------------------------------------------------
155 * Local variables:
156 * c-file-style: "linux"
157 * End:
158 */