blob: 20e30be44795b2d957402601180dc1684363ae91 [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"
Al Viro37185b32012-10-08 03:27:32 +010014#include <os.h>
15#include <um_malloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025};
26
Jeff Dike63920f42007-07-15 23:38:52 -070027static void *xterm_init(char *str, int device, const struct chan_opts *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -070028{
29 struct xterm_chan *data;
30
Jeff Dike43f5b302008-05-12 14:01:52 -070031 data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
Jeff Dike63920f42007-07-15 23:38:52 -070032 if (data == NULL)
33 return NULL;
34 *data = ((struct xterm_chan) { .pid = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 .helper_pid = -1,
Jeff Dike63920f42007-07-15 23:38:52 -070036 .device = device,
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 .title = opts->xterm_title,
Jeff Dike63920f42007-07-15 23:38:52 -070038 .raw = opts->raw } );
39 return data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070040}
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, ',');
Jeff Dike63920f42007-07-15 23:38:52 -070053 if (line == NULL)
54 return 0;
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 *line++ = '\0';
Jeff Dike63920f42007-07-15 23:38:52 -070057 if (*line)
58 title_switch = line;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60 line = strchr(line, ',');
Jeff Dike63920f42007-07-15 23:38:52 -070061 if (line == NULL)
62 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Jeff Dike63920f42007-07-15 23:38:52 -070064 *line++ = '\0';
65 if (*line)
66 exec_switch = line;
67
68 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
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
Jeff Dike63920f42007-07-15 23:38:52 -070084static int xterm_open(int input, int output, int primary, void *d,
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 char **dev_out)
86{
87 struct xterm_chan *data = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 int pid, fd, new, err;
89 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
Jeff Dike63920f42007-07-15 23:38:52 -070090 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
Richard Weinberger0ce451a2011-05-24 17:13:00 -070091 OS_LIB_PATH "/uml/port-helper", "-uml-socket",
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 file, NULL };
93
Jeff Dike63920f42007-07-15 23:38:52 -070094 if (access(argv[4], X_OK) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 argv[4] = "port-helper";
96
Jeff Dikecb8fa612007-10-16 01:27:34 -070097 /*
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 */
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);
Jonathan Neuschäferb40997b2011-09-14 16:21:20 -0700124 close(fd);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700125 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 }
Jeff Dike63920f42007-07-15 23:38:52 -0700127 close(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129 fd = os_create_unix_socket(file, sizeof(file), 1);
Jeff Dike63920f42007-07-15 23:38:52 -0700130 if (fd < 0) {
131 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
132 "errno = %d\n", -fd);
133 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 }
135
136 sprintf(title, data->title, data->device);
Jeff Dikec4399012007-07-15 23:38:56 -0700137 pid = run_helper(NULL, NULL, argv);
Jeff Dike63920f42007-07-15 23:38:52 -0700138 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 }
144
Jeff Dike63920f42007-07-15 23:38:52 -0700145 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 }
Jeff Dike63920f42007-07-15 23:38:52 -0700151
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
159
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700160 err = os_set_fd_block(new, 0);
161 if (err) {
Jeff Dike63920f42007-07-15 23:38:52 -0700162 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
163 "descriptor non-blocking, err = %d\n", -err);
164 goto out_close2;
Eduard-Gabriel Munteanu89df6bf2007-07-15 23:38:51 -0700165 }
166
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 CATCH_EINTR(err = tcgetattr(new, &data->tt));
Jeff Dike63920f42007-07-15 23:38:52 -0700168 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700170 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 }
172
Jeff Dike63920f42007-07-15 23:38:52 -0700173 if (data->raw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 err = raw(new);
Jeff Dike63920f42007-07-15 23:38:52 -0700175 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 new = err;
Jeff Dike63920f42007-07-15 23:38:52 -0700177 goto out_close2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 }
179 }
180
Jeff Dike63920f42007-07-15 23:38:52 -0700181 unlink(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 data->pid = pid;
183 *dev_out = NULL;
Jeff Dike63920f42007-07-15 23:38:52 -0700184
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195}
196
Jeff Dike63920f42007-07-15 23:38:52 -0700197static void xterm_close(int fd, void *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
199 struct xterm_chan *data = d;
Jeff Dikecb8fa612007-10-16 01:27:34 -0700200
Jeff Dike63920f42007-07-15 23:38:52 -0700201 if (data->pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 os_kill_process(data->pid, 1);
203 data->pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700204
205 if (data->helper_pid != -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 os_kill_process(data->helper_pid, 0);
207 data->helper_pid = -1;
Jeff Dike63920f42007-07-15 23:38:52 -0700208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 os_close_file(fd);
210}
211
Jeff Dike5e7672e2006-09-27 01:50:33 -0700212const struct chan_ops xterm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 .type = "xterm",
214 .init = xterm_init,
215 .open = xterm_open,
216 .close = xterm_close,
217 .read = generic_read,
218 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800219 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .window_size = generic_window_size,
Jeff Dikee99525f2007-10-16 01:26:41 -0700221 .free = generic_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 .winch = 1,
223};