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 <errno.h> 10 #include <fcntl.h> 11 #include <string.h> 12 #include <termios.h> 13 #include <sys/stat.h> 14 #include "chan_user.h" 15 #include "kern_constants.h" 16 #include "os.h" 17 #include "um_malloc.h" 18 #include "user.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 = uml_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 goto out_close; 60 61 err = raw(fd); 62 if (err) 63 goto out_close; 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 out_close: 76 close(fd); 77 return err; 78 } 79 80 static int getmaster(char *line) 81 { 82 struct stat buf; 83 char *pty, *bank, *cp; 84 int master, err; 85 86 pty = &line[strlen("/dev/ptyp")]; 87 for (bank = "pqrs"; *bank; bank++) { 88 line[strlen("/dev/pty")] = *bank; 89 *pty = '0'; 90 /* Did we hit the end ? */ 91 if ((stat(line, &buf) < 0) && (errno == ENOENT)) 92 break; 93 94 for (cp = "0123456789abcdef"; *cp; cp++) { 95 *pty = *cp; 96 master = open(line, O_RDWR); 97 if (master >= 0) { 98 char *tp = &line[strlen("/dev/")]; 99 100 /* verify slave side is usable */ 101 *tp = 't'; 102 err = access(line, R_OK | W_OK); 103 *tp = 'p'; 104 if (!err) 105 return master; 106 close(master); 107 } 108 } 109 } 110 111 printk(UM_KERN_ERR "getmaster - no usable host pty devices\n"); 112 return -ENOENT; 113 } 114 115 static int pty_open(int input, int output, int primary, void *d, 116 char **dev_out) 117 { 118 struct pty_chan *data = d; 119 int fd, err; 120 char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; 121 122 fd = getmaster(dev); 123 if (fd < 0) 124 return fd; 125 126 if (data->raw) { 127 err = raw(fd); 128 if (err) { 129 close(fd); 130 return err; 131 } 132 } 133 134 if (data->announce) 135 (*data->announce)(dev, data->dev); 136 137 sprintf(data->dev_name, "%s", dev); 138 *dev_out = data->dev_name; 139 140 return fd; 141 } 142 143 const struct chan_ops pty_ops = { 144 .type = "pty", 145 .init = pty_chan_init, 146 .open = pty_open, 147 .close = generic_close, 148 .read = generic_read, 149 .write = generic_write, 150 .console_write = generic_console_write, 151 .window_size = generic_window_size, 152 .free = generic_free, 153 .winch = 0, 154 }; 155 156 const struct chan_ops pts_ops = { 157 .type = "pts", 158 .init = pty_chan_init, 159 .open = pts_open, 160 .close = generic_close, 161 .read = generic_read, 162 .write = generic_write, 163 .console_write = generic_console_write, 164 .window_size = generic_window_size, 165 .free = generic_free, 166 .winch = 0, 167 }; 168