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