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