blob: fd817e5415435564fcf359945a7362b6ad38db23 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -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
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <stdlib.h>
Jeff Dike63920f42007-07-15 23:38:52 -07007#include <stdio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <termios.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "chan_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "os.h"
Jeff Dike63920f42007-07-15 23:38:52 -070014#include "init.h"
15#include "user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "xterm.h"
Jeff Dike63920f42007-07-15 23:38:52 -070017#include "kern_constants.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19struct xterm_chan {
20 int pid;
21 int helper_pid;
22 char *title;
23 int device;
24 int raw;
25 struct termios tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026};
27
Jeff Dike63920f42007-07-15 23:38:52 -070028static void *xterm_init(char *str, int device, const struct chan_opts *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -070029{
30 struct xterm_chan *data;
31
32 data = malloc(sizeof(*data));
Jeff Dike63920f42007-07-15 23:38:52 -070033 if (data == NULL)
34 return NULL;
35 *data = ((struct xterm_chan) { .pid = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 .helper_pid = -1,
Jeff Dike63920f42007-07-15 23:38:52 -070037 .device = device,
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 .title = opts->xterm_title,
Jeff Dike63920f42007-07-15 23:38:52 -070039 .raw = opts->raw } );
40 return data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041}
42
43/* Only changed by xterm_setup, which is a setup */
44static char *terminal_emulator = "xterm";
45static char *title_switch = "-T";
46static char *exec_switch = "-e";
47
48static int __init xterm_setup(char *line, int *add)
49{
50 *add = 0;
51 terminal_emulator = line;
52
53 line = strchr(line, ',');
Jeff Dike63920f42007-07-15 23:38:52 -070054 if (line == NULL)
55 return 0;
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 *line++ = '\0';
Jeff Dike63920f42007-07-15 23:38:52 -070058 if (*line)
59 title_switch = line;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 line = strchr(line, ',');
Jeff Dike63920f42007-07-15 23:38:52 -070062 if (line == NULL)
63 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Jeff Dike63920f42007-07-15 23:38:52 -070065 *line++ = '\0';
66 if (*line)
67 exec_switch = line;
68
69 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
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
Jeff Dike63920f42007-07-15 23:38:52 -070085static int xterm_open(int input, int output, int primary, void *d,
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 char **dev_out)
87{
88 struct xterm_chan *data = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 int pid, fd, new, err;
90 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
Jeff Dike63920f42007-07-15 23:38:52 -070091 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 "/usr/lib/uml/port-helper", "-uml-socket",
93 file, NULL };
94
Jeff Dike63920f42007-07-15 23:38:52 -070095 if (access(argv[4], X_OK) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 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. */
Jeff Dike63920f42007-07-15 23:38:52 -0700100 if (getenv("DISPLAY") == NULL) {
101 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 return -ENODEV;
103 }
104
Jeff Dike63920f42007-07-15 23:38:52 -0700105 /*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 fd = mkstemp(file);
Jeff Dike63920f42007-07-15 23:38:52 -0700112 if (fd < 0) {
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700113 err = -errno;
Jeff Dike63920f42007-07-15 23:38:52 -0700114 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
115 errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700116 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 }
118
Jeff Dike63920f42007-07-15 23:38:52 -0700119 if (unlink(file)) {
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700120 err = -errno;
Jeff Dike63920f42007-07-15 23:38:52 -0700121 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
122 errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700123 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 }
Jeff Dike63920f42007-07-15 23:38:52 -0700125 close(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 fd = os_create_unix_socket(file, sizeof(file), 1);
Jeff Dike63920f42007-07-15 23:38:52 -0700128 if (fd < 0) {
129 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
130 "errno = %d\n", -fd);
131 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133
134 sprintf(title, data->title, data->device);
Jeff Dikec4399012007-07-15 23:38:56 -0700135 pid = run_helper(NULL, NULL, argv);
Jeff Dike63920f42007-07-15 23:38:52 -0700136 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 }
142
Jeff Dike63920f42007-07-15 23:38:52 -0700143 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
Jeff Dike63920f42007-07-15 23:38:52 -0700149
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
157
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700158 err = os_set_fd_block(new, 0);
159 if (err) {
Jeff Dike63920f42007-07-15 23:38:52 -0700160 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
161 "descriptor non-blocking, err = %d\n", -err);
162 goto out_close2;
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700163 }
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 CATCH_EINTR(err = tcgetattr(new, &data->tt));
Jeff Dike63920f42007-07-15 23:38:52 -0700166 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700168 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 }
170
Jeff Dike63920f42007-07-15 23:38:52 -0700171 if (data->raw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 err = raw(new);
Jeff Dike63920f42007-07-15 23:38:52 -0700173 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700175 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 }
177 }
178
Jeff Dike63920f42007-07-15 23:38:52 -0700179 unlink(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 data->pid = pid;
181 *dev_out = NULL;
Jeff Dike63920f42007-07-15 23:38:52 -0700182
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
Jeff Dike63920f42007-07-15 23:38:52 -0700195static void xterm_close(int fd, void *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196{
197 struct xterm_chan *data = d;
198
Jeff Dike63920f42007-07-15 23:38:52 -0700199 if (data->pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 os_kill_process(data->pid, 1);
201 data->pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700202
203 if (data->helper_pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 os_kill_process(data->helper_pid, 0);
205 data->helper_pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 os_close_file(fd);
208}
209
210static void xterm_free(void *d)
211{
212 free(d);
213}
214
Jeff Dike5e7672e2006-09-27 01:50:33 -0700215const struct chan_ops xterm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 .type = "xterm",
217 .init = xterm_init,
218 .open = xterm_open,
219 .close = xterm_close,
220 .read = generic_read,
221 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800222 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 .window_size = generic_window_size,
224 .free = xterm_free,
225 .winch = 1,
226};