blob: da2caa5a21efa91333ffd44c9c7743b467ec3f26 [file] [log] [blame]
Jeff Dikecb8fa612007-10-16 01:27:34 -07001/*
Jeff Dike63920f42007-07-15 23:38:52 -07002 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 */
5
Jeff Dikee99525f2007-10-16 01:26:41 -07006#include <stddef.h>
Jeff Dike63920f42007-07-15 23:38:52 -07007#include <stdio.h>
Jeff Dikecb8fa612007-10-16 01:27:34 -07008#include <stdlib.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <unistd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <errno.h>
Jeff Dikee99525f2007-10-16 01:26:41 -070011#include <string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <termios.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "chan_user.h"
Jeff Dikee99525f2007-10-16 01:26:41 -070014#include "kern_constants.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "os.h"
Jeff Dikee99525f2007-10-16 01:26:41 -070016#include "um_malloc.h"
Jeff Dike63920f42007-07-15 23:38:52 -070017#include "user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070027};
28
Jeff Dike63920f42007-07-15 23:38:52 -070029static void *xterm_init(char *str, int device, const struct chan_opts *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -070030{
31 struct xterm_chan *data;
32
Jeff Dike43f5b302008-05-12 14:01:52 -070033 data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
Jeff Dike63920f42007-07-15 23:38:52 -070034 if (data == NULL)
35 return NULL;
36 *data = ((struct xterm_chan) { .pid = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 .helper_pid = -1,
Jeff Dike63920f42007-07-15 23:38:52 -070038 .device = device,
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 .title = opts->xterm_title,
Jeff Dike63920f42007-07-15 23:38:52 -070040 .raw = opts->raw } );
41 return data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042}
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, ',');
Jeff Dike63920f42007-07-15 23:38:52 -070055 if (line == NULL)
56 return 0;
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 *line++ = '\0';
Jeff Dike63920f42007-07-15 23:38:52 -070059 if (*line)
60 title_switch = line;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62 line = strchr(line, ',');
Jeff Dike63920f42007-07-15 23:38:52 -070063 if (line == NULL)
64 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Jeff Dike63920f42007-07-15 23:38:52 -070066 *line++ = '\0';
67 if (*line)
68 exec_switch = line;
69
70 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071}
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
Jeff Dike63920f42007-07-15 23:38:52 -070086static int xterm_open(int input, int output, int primary, void *d,
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 char **dev_out)
88{
89 struct xterm_chan *data = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 int pid, fd, new, err;
91 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
Jeff Dike63920f42007-07-15 23:38:52 -070092 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 "/usr/lib/uml/port-helper", "-uml-socket",
94 file, NULL };
95
Jeff Dike63920f42007-07-15 23:38:52 -070096 if (access(argv[4], X_OK) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 argv[4] = "port-helper";
98
Jeff Dikecb8fa612007-10-16 01:27:34 -070099 /*
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 */
Jeff Dike63920f42007-07-15 23:38:52 -0700103 if (getenv("DISPLAY") == NULL) {
104 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return -ENODEV;
106 }
107
Jeff Dike63920f42007-07-15 23:38:52 -0700108 /*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 fd = mkstemp(file);
Jeff Dike63920f42007-07-15 23:38:52 -0700115 if (fd < 0) {
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700116 err = -errno;
Jeff Dike63920f42007-07-15 23:38:52 -0700117 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
118 errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700119 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 }
121
Jeff Dike63920f42007-07-15 23:38:52 -0700122 if (unlink(file)) {
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700123 err = -errno;
Jeff Dike63920f42007-07-15 23:38:52 -0700124 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
125 errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700126 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 }
Jeff Dike63920f42007-07-15 23:38:52 -0700128 close(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130 fd = os_create_unix_socket(file, sizeof(file), 1);
Jeff Dike63920f42007-07-15 23:38:52 -0700131 if (fd < 0) {
132 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
133 "errno = %d\n", -fd);
134 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 }
136
137 sprintf(title, data->title, data->device);
Jeff Dikec4399012007-07-15 23:38:56 -0700138 pid = run_helper(NULL, NULL, argv);
Jeff Dike63920f42007-07-15 23:38:52 -0700139 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 }
145
Jeff Dike63920f42007-07-15 23:38:52 -0700146 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 }
Jeff Dike63920f42007-07-15 23:38:52 -0700152
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
160
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700161 err = os_set_fd_block(new, 0);
162 if (err) {
Jeff Dike63920f42007-07-15 23:38:52 -0700163 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
164 "descriptor non-blocking, err = %d\n", -err);
165 goto out_close2;
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700166 }
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 CATCH_EINTR(err = tcgetattr(new, &data->tt));
Jeff Dike63920f42007-07-15 23:38:52 -0700169 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700171 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
173
Jeff Dike63920f42007-07-15 23:38:52 -0700174 if (data->raw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 err = raw(new);
Jeff Dike63920f42007-07-15 23:38:52 -0700176 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700178 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 }
180 }
181
Jeff Dike63920f42007-07-15 23:38:52 -0700182 unlink(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 data->pid = pid;
184 *dev_out = NULL;
Jeff Dike63920f42007-07-15 23:38:52 -0700185
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
Jeff Dike63920f42007-07-15 23:38:52 -0700198static void xterm_close(int fd, void *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
200 struct xterm_chan *data = d;
Jeff Dikecb8fa612007-10-16 01:27:34 -0700201
Jeff Dike63920f42007-07-15 23:38:52 -0700202 if (data->pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 os_kill_process(data->pid, 1);
204 data->pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700205
206 if (data->helper_pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 os_kill_process(data->helper_pid, 0);
208 data->helper_pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 os_close_file(fd);
211}
212
Jeff Dike5e7672e2006-09-27 01:50:33 -0700213const struct chan_ops xterm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .type = "xterm",
215 .init = xterm_init,
216 .open = xterm_open,
217 .close = xterm_close,
218 .read = generic_read,
219 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800220 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 .window_size = generic_window_size,
Jeff Dikee99525f2007-10-16 01:26:41 -0700222 .free = generic_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 .winch = 1,
224};