Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <termios.h>
12#include "chan_user.h"
13#include "os.h"
14#include "init.h"
15#include "user.h"
16#include "xterm.h"
17#include "kern_constants.h"
18
19struct xterm_chan {
20 int pid;
21 int helper_pid;
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 = malloc(sizeof(*data));
33 if (data == NULL)
34 return NULL;
35 *data = ((struct xterm_chan) { .pid = -1,
36 .helper_pid = -1,
37 .device = device,
38 .title = opts->xterm_title,
39 .raw = opts->raw } );
40 return data;
41}
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, ',');
54 if (line == NULL)
55 return 0;
56
57 *line++ = '\0';
58 if (*line)
59 title_switch = line;
60
61 line = strchr(line, ',');
62 if (line == NULL)
63 return 0;
64
65 *line++ = '\0';
66 if (*line)
67 exec_switch = line;
68
69 return 0;
70}
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
85static int xterm_open(int input, int output, int primary, void *d,
86 char **dev_out)
87{
88 struct xterm_chan *data = d;
89 int pid, fd, new, err;
90 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
91 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
92 "/usr/lib/uml/port-helper", "-uml-socket",
93 file, NULL };
94
95 if (access(argv[4], X_OK) < 0)
96 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. */
100 if (getenv("DISPLAY") == NULL) {
101 printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
102 return -ENODEV;
103 }
104
105 /*
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 */
111 fd = mkstemp(file);
112 if (fd < 0) {
113 err = -errno;
114 printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
115 errno);
116 return err;
117 }
118
119 if (unlink(file)) {
120 err = -errno;
121 printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
122 errno);
123 return err;
124 }
125 close(fd);
126
127 fd = os_create_unix_socket(file, sizeof(file), 1);
128 if (fd < 0) {
129 printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
130 "errno = %d\n", -fd);
131 return fd;
132 }
133
134 sprintf(title, data->title, data->device);
135 pid = run_helper(NULL, NULL, argv);
136 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;
141 }
142
143 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;
148 }
149
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;
156 }
157
158 err = os_set_fd_block(new, 0);
159 if (err) {
160 printk(UM_KERN_ERR "xterm_open : failed to set xterm "
161 "descriptor non-blocking, err = %d\n", -err);
162 goto out_close2;
163 }
164
165 CATCH_EINTR(err = tcgetattr(new, &data->tt));
166 if (err) {
167 new = err;
168 goto out_close2;
169 }
170
171 if (data->raw) {
172 err = raw(new);
173 if (err) {
174 new = err;
175 goto out_close2;
176 }
177 }
178
179 unlink(file);
180 data->pid = pid;
181 *dev_out = NULL;
182
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;
193}
194
195static void xterm_close(int fd, void *d)
196{
197 struct xterm_chan *data = d;
198
199 if (data->pid != -1)
200 os_kill_process(data->pid, 1);
201 data->pid = -1;
202
203 if (data->helper_pid != -1)
204 os_kill_process(data->helper_pid, 0);
205 data->helper_pid = -1;
206
207 os_close_file(fd);
208}
209
210static void xterm_free(void *d)
211{
212 free(d);
213}
214
215const struct chan_ops xterm_ops = {
216 .type = "xterm",
217 .init = xterm_init,
218 .open = xterm_open,
219 .close = xterm_close,
220 .read = generic_read,
221 .write = generic_write,
222 .console_write = generic_console_write,
223 .window_size = generic_window_size,
224 .free = xterm_free,
225 .winch = 1,
226};