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