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