blob: 87e18bf2c6673869ffaa26d9da0a6f03e1c67757 [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
Jeff Dikee99525f2007-10-16 01:26:41 -07006#include <stddef.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include <stdlib.h>
Jeff Dike63920f42007-07-15 23:38:52 -07008#include <stdio.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 Dikee99525f2007-10-16 01:26:41 -070033 data = 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
99 /* Check that DISPLAY is set, this doesn't guarantee the xterm
100 * will work but w/o it we can be pretty sure it won't. */
Jeff Dike63920f42007-07-15 23:38:52 -0700101 if (getenv("DISPLAY") == NULL) {
102 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 return -ENODEV;
104 }
105
Jeff Dike63920f42007-07-15 23:38:52 -0700106 /*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 fd = mkstemp(file);
Jeff Dike63920f42007-07-15 23:38:52 -0700113 if (fd < 0) {
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700114 err = -errno;
Jeff Dike63920f42007-07-15 23:38:52 -0700115 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
116 errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700117 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
119
Jeff Dike63920f42007-07-15 23:38:52 -0700120 if (unlink(file)) {
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700121 err = -errno;
Jeff Dike63920f42007-07-15 23:38:52 -0700122 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
123 errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700124 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
Jeff Dike63920f42007-07-15 23:38:52 -0700126 close(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128 fd = os_create_unix_socket(file, sizeof(file), 1);
Jeff Dike63920f42007-07-15 23:38:52 -0700129 if (fd < 0) {
130 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
131 "errno = %d\n", -fd);
132 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 }
134
135 sprintf(title, data->title, data->device);
Jeff Dikec4399012007-07-15 23:38:56 -0700136 pid = run_helper(NULL, NULL, argv);
Jeff Dike63920f42007-07-15 23:38:52 -0700137 if (pid < 0) {
138 err = pid;
139 printk(UM_KERN_ERR "xterm_open : run_helper failed, "
140 "errno = %d\n", -err);
141 goto out_close1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 }
143
Jeff Dike63920f42007-07-15 23:38:52 -0700144 err = os_set_fd_block(fd, 0);
145 if (err < 0) {
146 printk(UM_KERN_ERR "xterm_open : failed to set descriptor "
147 "non-blocking, err = %d\n", -err);
148 goto out_kill;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
Jeff Dike63920f42007-07-15 23:38:52 -0700150
151 new = xterm_fd(fd, &data->helper_pid);
152 if (new < 0) {
153 err = new;
154 printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n",
155 -err);
156 goto out_kill;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
158
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700159 err = os_set_fd_block(new, 0);
160 if (err) {
Jeff Dike63920f42007-07-15 23:38:52 -0700161 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
162 "descriptor non-blocking, err = %d\n", -err);
163 goto out_close2;
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700164 }
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 CATCH_EINTR(err = tcgetattr(new, &data->tt));
Jeff Dike63920f42007-07-15 23:38:52 -0700167 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700169 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 }
171
Jeff Dike63920f42007-07-15 23:38:52 -0700172 if (data->raw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 err = raw(new);
Jeff Dike63920f42007-07-15 23:38:52 -0700174 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700176 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 }
178 }
179
Jeff Dike63920f42007-07-15 23:38:52 -0700180 unlink(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 data->pid = pid;
182 *dev_out = NULL;
Jeff Dike63920f42007-07-15 23:38:52 -0700183
184 return new;
185
186 out_close2:
187 close(new);
188 out_kill:
189 os_kill_process(pid, 1);
190 out_close1:
191 close(fd);
192
193 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194}
195
Jeff Dike63920f42007-07-15 23:38:52 -0700196static void xterm_close(int fd, void *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
198 struct xterm_chan *data = d;
199
Jeff Dike63920f42007-07-15 23:38:52 -0700200 if (data->pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 os_kill_process(data->pid, 1);
202 data->pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700203
204 if (data->helper_pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 os_kill_process(data->helper_pid, 0);
206 data->helper_pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 os_close_file(fd);
209}
210
Jeff Dike5e7672e2006-09-27 01:50:33 -0700211const struct chan_ops xterm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 .type = "xterm",
213 .init = xterm_init,
214 .open = xterm_open,
215 .close = xterm_close,
216 .read = generic_read,
217 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800218 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .window_size = generic_window_size,
Jeff Dikee99525f2007-10-16 01:26:41 -0700220 .free = generic_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 .winch = 1,
222};