Loading...
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4 */
5
6#include <stddef.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <errno.h>
11#include <string.h>
12#include <termios.h>
13#include "chan_user.h"
14#include <os.h>
15#include <um_malloc.h>
16#include "xterm.h"
17
18struct xterm_chan {
19 int pid;
20 int helper_pid;
21 int chan_fd;
22 char *title;
23 int device;
24 int raw;
25 struct termios tt;
26};
27
28static void *xterm_init(char *str, int device, const struct chan_opts *opts)
29{
30 struct xterm_chan *data;
31
32 data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
33 if (data == NULL)
34 return NULL;
35 *data = ((struct xterm_chan) { .pid = -1,
36 .helper_pid = -1,
37 .chan_fd = -1,
38 .device = device,
39 .title = opts->xterm_title,
40 .raw = opts->raw } );
41 return data;
42}
43
44/* Only changed by xterm_setup, which is a setup */
45static char *terminal_emulator = CONFIG_XTERM_CHAN_DEFAULT_EMULATOR;
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, ',');
55 if (line == NULL)
56 return 0;
57
58 *line++ = '\0';
59 if (*line)
60 title_switch = line;
61
62 line = strchr(line, ',');
63 if (line == NULL)
64 return 0;
65
66 *line++ = '\0';
67 if (*line)
68 exec_switch = line;
69
70 return 0;
71}
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=" CONFIG_XTERM_CHAN_DEFAULT_EMULATOR
83 ",-T,-e'.\n"
84" Values for gnome-terminal are 'xterm=gnome-terminal,-t,-x'.\n\n"
85);
86
87static int xterm_open(int input, int output, int primary, void *d,
88 char **dev_out)
89{
90 struct xterm_chan *data = d;
91 int pid, fd, new, err;
92 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
93 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
94 OS_LIB_PATH "/uml/port-helper", "-uml-socket",
95 file, NULL };
96
97 if (access(argv[4], X_OK) < 0)
98 argv[4] = "port-helper";
99
100 /*
101 * Check that DISPLAY is set, this doesn't guarantee the xterm
102 * will work but w/o it we can be pretty sure it won't.
103 */
104 if (getenv("DISPLAY") == NULL) {
105 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
106 return -ENODEV;
107 }
108
109 /*
110 * This business of getting a descriptor to a temp file,
111 * deleting the file and closing the descriptor is just to get
112 * a known-unused name for the Unix socket that we really
113 * want.
114 */
115 fd = mkstemp(file);
116 if (fd < 0) {
117 err = -errno;
118 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
119 errno);
120 return err;
121 }
122
123 if (unlink(file)) {
124 err = -errno;
125 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
126 errno);
127 close(fd);
128 return err;
129 }
130 close(fd);
131
132 fd = os_create_unix_socket(file, sizeof(file), 1);
133 if (fd < 0) {
134 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
135 "errno = %d\n", -fd);
136 return fd;
137 }
138
139 sprintf(title, data->title, data->device);
140 pid = run_helper(NULL, NULL, argv);
141 if (pid < 0) {
142 err = pid;
143 printk(UM_KERN_ERR "xterm_open : run_helper failed, "
144 "errno = %d\n", -err);
145 goto out_close1;
146 }
147
148 err = os_set_fd_block(fd, 0);
149 if (err < 0) {
150 printk(UM_KERN_ERR "xterm_open : failed to set descriptor "
151 "non-blocking, err = %d\n", -err);
152 goto out_kill;
153 }
154
155 data->chan_fd = fd;
156 new = xterm_fd(fd, &data->helper_pid);
157 if (new < 0) {
158 err = new;
159 printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n",
160 -err);
161 goto out_kill;
162 }
163
164 err = os_set_fd_block(new, 0);
165 if (err) {
166 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
167 "descriptor non-blocking, err = %d\n", -err);
168 goto out_close2;
169 }
170
171 CATCH_EINTR(err = tcgetattr(new, &data->tt));
172 if (err) {
173 new = err;
174 goto out_close2;
175 }
176
177 if (data->raw) {
178 err = raw(new);
179 if (err) {
180 new = err;
181 goto out_close2;
182 }
183 }
184
185 unlink(file);
186 data->pid = pid;
187 *dev_out = NULL;
188
189 return new;
190
191 out_close2:
192 close(new);
193 out_kill:
194 os_kill_process(pid, 1);
195 out_close1:
196 close(fd);
197
198 return err;
199}
200
201static void xterm_close(int fd, void *d)
202{
203 struct xterm_chan *data = d;
204
205 if (data->pid != -1)
206 os_kill_process(data->pid, 1);
207 data->pid = -1;
208
209 if (data->helper_pid != -1)
210 os_kill_process(data->helper_pid, 0);
211 data->helper_pid = -1;
212
213 if (data->chan_fd != -1)
214 os_close_file(data->chan_fd);
215 os_close_file(fd);
216}
217
218const struct chan_ops xterm_ops = {
219 .type = "xterm",
220 .init = xterm_init,
221 .open = xterm_open,
222 .close = xterm_close,
223 .read = generic_read,
224 .write = generic_write,
225 .console_write = generic_console_write,
226 .window_size = generic_window_size,
227 .free = generic_free,
228 .winch = 1,
229};
1/*
2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL
4 */
5
6#include <stddef.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <errno.h>
11#include <string.h>
12#include <termios.h>
13#include "chan_user.h"
14#include "kern_constants.h"
15#include "os.h"
16#include "um_malloc.h"
17#include "user.h"
18#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;
27};
28
29static void *xterm_init(char *str, int device, const struct chan_opts *opts)
30{
31 struct xterm_chan *data;
32
33 data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
34 if (data == NULL)
35 return NULL;
36 *data = ((struct xterm_chan) { .pid = -1,
37 .helper_pid = -1,
38 .device = device,
39 .title = opts->xterm_title,
40 .raw = opts->raw } );
41 return data;
42}
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, ',');
55 if (line == NULL)
56 return 0;
57
58 *line++ = '\0';
59 if (*line)
60 title_switch = line;
61
62 line = strchr(line, ',');
63 if (line == NULL)
64 return 0;
65
66 *line++ = '\0';
67 if (*line)
68 exec_switch = line;
69
70 return 0;
71}
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
86static int xterm_open(int input, int output, int primary, void *d,
87 char **dev_out)
88{
89 struct xterm_chan *data = d;
90 int pid, fd, new, err;
91 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
92 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
93 OS_LIB_PATH "/uml/port-helper", "-uml-socket",
94 file, NULL };
95
96 if (access(argv[4], X_OK) < 0)
97 argv[4] = "port-helper";
98
99 /*
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 */
103 if (getenv("DISPLAY") == NULL) {
104 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
105 return -ENODEV;
106 }
107
108 /*
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 */
114 fd = mkstemp(file);
115 if (fd < 0) {
116 err = -errno;
117 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
118 errno);
119 return err;
120 }
121
122 if (unlink(file)) {
123 err = -errno;
124 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
125 errno);
126 close(fd);
127 return err;
128 }
129 close(fd);
130
131 fd = os_create_unix_socket(file, sizeof(file), 1);
132 if (fd < 0) {
133 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
134 "errno = %d\n", -fd);
135 return fd;
136 }
137
138 sprintf(title, data->title, data->device);
139 pid = run_helper(NULL, NULL, argv);
140 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;
145 }
146
147 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;
152 }
153
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;
160 }
161
162 err = os_set_fd_block(new, 0);
163 if (err) {
164 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
165 "descriptor non-blocking, err = %d\n", -err);
166 goto out_close2;
167 }
168
169 CATCH_EINTR(err = tcgetattr(new, &data->tt));
170 if (err) {
171 new = err;
172 goto out_close2;
173 }
174
175 if (data->raw) {
176 err = raw(new);
177 if (err) {
178 new = err;
179 goto out_close2;
180 }
181 }
182
183 unlink(file);
184 data->pid = pid;
185 *dev_out = NULL;
186
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;
197}
198
199static void xterm_close(int fd, void *d)
200{
201 struct xterm_chan *data = d;
202
203 if (data->pid != -1)
204 os_kill_process(data->pid, 1);
205 data->pid = -1;
206
207 if (data->helper_pid != -1)
208 os_kill_process(data->helper_pid, 0);
209 data->helper_pid = -1;
210
211 os_close_file(fd);
212}
213
214const struct chan_ops xterm_ops = {
215 .type = "xterm",
216 .init = xterm_init,
217 .open = xterm_open,
218 .close = xterm_close,
219 .read = generic_read,
220 .write = generic_write,
221 .console_write = generic_console_write,
222 .window_size = generic_window_size,
223 .free = generic_free,
224 .winch = 1,
225};