blob: 2e1de57286045ab9cf606250059a4d094b486ab2 [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,
Richard Weinberger0ce451a2011-05-24 17:13:00 -070093 OS_LIB_PATH "/uml/port-helper", "-uml-socket",
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 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);
Jonathan Neuschäferb40997b2011-09-14 16:21:20 -0700126 close(fd);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700127 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 }
Jeff Dike63920f42007-07-15 23:38:52 -0700129 close(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 fd = os_create_unix_socket(file, sizeof(file), 1);
Jeff Dike63920f42007-07-15 23:38:52 -0700132 if (fd < 0) {
133 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
134 "errno = %d\n", -fd);
135 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 }
137
138 sprintf(title, data->title, data->device);
Jeff Dikec4399012007-07-15 23:38:56 -0700139 pid = run_helper(NULL, NULL, argv);
Jeff Dike63920f42007-07-15 23:38:52 -0700140 if (pid < 0) {
141 err = pid;
142 printk(UM_KERN_ERR "xterm_open : run_helper failed, "
143 "errno = %d\n", -err);
144 goto out_close1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 }
146
Jeff Dike63920f42007-07-15 23:38:52 -0700147 err = os_set_fd_block(fd, 0);
148 if (err < 0) {
149 printk(UM_KERN_ERR "xterm_open : failed to set descriptor "
150 "non-blocking, err = %d\n", -err);
151 goto out_kill;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Jeff Dike63920f42007-07-15 23:38:52 -0700153
154 new = xterm_fd(fd, &data->helper_pid);
155 if (new < 0) {
156 err = new;
157 printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n",
158 -err);
159 goto out_kill;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700162 err = os_set_fd_block(new, 0);
163 if (err) {
Jeff Dike63920f42007-07-15 23:38:52 -0700164 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
165 "descriptor non-blocking, err = %d\n", -err);
166 goto out_close2;
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700167 }
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 CATCH_EINTR(err = tcgetattr(new, &data->tt));
Jeff Dike63920f42007-07-15 23:38:52 -0700170 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700172 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
174
Jeff Dike63920f42007-07-15 23:38:52 -0700175 if (data->raw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 err = raw(new);
Jeff Dike63920f42007-07-15 23:38:52 -0700177 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700179 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181 }
182
Jeff Dike63920f42007-07-15 23:38:52 -0700183 unlink(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 data->pid = pid;
185 *dev_out = NULL;
Jeff Dike63920f42007-07-15 23:38:52 -0700186
187 return new;
188
189 out_close2:
190 close(new);
191 out_kill:
192 os_kill_process(pid, 1);
193 out_close1:
194 close(fd);
195
196 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
Jeff Dike63920f42007-07-15 23:38:52 -0700199static void xterm_close(int fd, void *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
201 struct xterm_chan *data = d;
Jeff Dikecb8fa612007-10-16 01:27:34 -0700202
Jeff Dike63920f42007-07-15 23:38:52 -0700203 if (data->pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 os_kill_process(data->pid, 1);
205 data->pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700206
207 if (data->helper_pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 os_kill_process(data->helper_pid, 0);
209 data->helper_pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 os_close_file(fd);
212}
213
Jeff Dike5e7672e2006-09-27 01:50:33 -0700214const struct chan_ops xterm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 .type = "xterm",
216 .init = xterm_init,
217 .open = xterm_open,
218 .close = xterm_close,
219 .read = generic_read,
220 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800221 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 .window_size = generic_window_size,
Jeff Dikee99525f2007-10-16 01:26:41 -0700223 .free = generic_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .winch = 1,
225};