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