1 /* 2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <unistd.h> 9 #include <string.h> 10 #include <errno.h> 11 #include <termios.h> 12 #include "chan_user.h" 13 #include "os.h" 14 #include "init.h" 15 #include "user.h" 16 #include "xterm.h" 17 #include "kern_constants.h" 18 19 struct xterm_chan { 20 int pid; 21 int helper_pid; 22 char *title; 23 int device; 24 int raw; 25 struct termios tt; 26 }; 27 28 static void *xterm_init(char *str, int device, const struct chan_opts *opts) 29 { 30 struct xterm_chan *data; 31 32 data = malloc(sizeof(*data)); 33 if (data == NULL) 34 return NULL; 35 *data = ((struct xterm_chan) { .pid = -1, 36 .helper_pid = -1, 37 .device = device, 38 .title = opts->xterm_title, 39 .raw = opts->raw } ); 40 return data; 41 } 42 43 /* Only changed by xterm_setup, which is a setup */ 44 static char *terminal_emulator = "xterm"; 45 static char *title_switch = "-T"; 46 static char *exec_switch = "-e"; 47 48 static int __init xterm_setup(char *line, int *add) 49 { 50 *add = 0; 51 terminal_emulator = line; 52 53 line = strchr(line, ','); 54 if (line == NULL) 55 return 0; 56 57 *line++ = '\0'; 58 if (*line) 59 title_switch = line; 60 61 line = strchr(line, ','); 62 if (line == NULL) 63 return 0; 64 65 *line++ = '\0'; 66 if (*line) 67 exec_switch = line; 68 69 return 0; 70 } 71 72 __uml_setup("xterm=", xterm_setup, 73 "xterm=<terminal emulator>,<title switch>,<exec switch>\n" 74 " Specifies an alternate terminal emulator to use for the debugger,\n" 75 " consoles, and serial lines when they are attached to the xterm channel.\n" 76 " The values are the terminal emulator binary, the switch it uses to set\n" 77 " its title, and the switch it uses to execute a subprocess,\n" 78 " respectively. The title switch must have the form '<switch> title',\n" 79 " not '<switch>=title'. Similarly, the exec switch must have the form\n" 80 " '<switch> command arg1 arg2 ...'.\n" 81 " The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n" 82 " are 'xterm=gnome-terminal,-t,-x'.\n\n" 83 ); 84 85 static int xterm_open(int input, int output, int primary, void *d, 86 char **dev_out) 87 { 88 struct xterm_chan *data = d; 89 int pid, fd, new, err; 90 char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; 91 char *argv[] = { terminal_emulator, title_switch, title, exec_switch, 92 "/usr/lib/uml/port-helper", "-uml-socket", 93 file, NULL }; 94 95 if (access(argv[4], X_OK) < 0) 96 argv[4] = "port-helper"; 97 98 /* Check that DISPLAY is set, this doesn't guarantee the xterm 99 * will work but w/o it we can be pretty sure it won't. */ 100 if (getenv("DISPLAY") == NULL) { 101 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n"); 102 return -ENODEV; 103 } 104 105 /* 106 * This business of getting a descriptor to a temp file, 107 * deleting the file and closing the descriptor is just to get 108 * a known-unused name for the Unix socket that we really 109 * want. 110 */ 111 fd = mkstemp(file); 112 if (fd < 0) { 113 err = -errno; 114 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n", 115 errno); 116 return err; 117 } 118 119 if (unlink(file)) { 120 err = -errno; 121 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n", 122 errno); 123 return err; 124 } 125 close(fd); 126 127 fd = os_create_unix_socket(file, sizeof(file), 1); 128 if (fd < 0) { 129 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, " 130 "errno = %d\n", -fd); 131 return fd; 132 } 133 134 sprintf(title, data->title, data->device); 135 pid = run_helper(NULL, NULL, argv); 136 if (pid < 0) { 137 err = pid; 138 printk(UM_KERN_ERR "xterm_open : run_helper failed, " 139 "errno = %d\n", -err); 140 goto out_close1; 141 } 142 143 err = os_set_fd_block(fd, 0); 144 if (err < 0) { 145 printk(UM_KERN_ERR "xterm_open : failed to set descriptor " 146 "non-blocking, err = %d\n", -err); 147 goto out_kill; 148 } 149 150 new = xterm_fd(fd, &data->helper_pid); 151 if (new < 0) { 152 err = new; 153 printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n", 154 -err); 155 goto out_kill; 156 } 157 158 err = os_set_fd_block(new, 0); 159 if (err) { 160 printk(UM_KERN_ERR "xterm_open : failed to set xterm " 161 "descriptor non-blocking, err = %d\n", -err); 162 goto out_close2; 163 } 164 165 CATCH_EINTR(err = tcgetattr(new, &data->tt)); 166 if (err) { 167 new = err; 168 goto out_close2; 169 } 170 171 if (data->raw) { 172 err = raw(new); 173 if (err) { 174 new = err; 175 goto out_close2; 176 } 177 } 178 179 unlink(file); 180 data->pid = pid; 181 *dev_out = NULL; 182 183 return new; 184 185 out_close2: 186 close(new); 187 out_kill: 188 os_kill_process(pid, 1); 189 out_close1: 190 close(fd); 191 192 return err; 193 } 194 195 static void xterm_close(int fd, void *d) 196 { 197 struct xterm_chan *data = d; 198 199 if (data->pid != -1) 200 os_kill_process(data->pid, 1); 201 data->pid = -1; 202 203 if (data->helper_pid != -1) 204 os_kill_process(data->helper_pid, 0); 205 data->helper_pid = -1; 206 207 os_close_file(fd); 208 } 209 210 static void xterm_free(void *d) 211 { 212 free(d); 213 } 214 215 const struct chan_ops xterm_ops = { 216 .type = "xterm", 217 .init = xterm_init, 218 .open = xterm_open, 219 .close = xterm_close, 220 .read = generic_read, 221 .write = generic_write, 222 .console_write = generic_console_write, 223 .window_size = generic_window_size, 224 .free = xterm_free, 225 .winch = 1, 226 }; 227