blob: 386f8b952982e4317f5254e4016a2e7ba18597d1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <termios.h>
12#include <signal.h>
13#include <sched.h>
14#include <sys/socket.h>
15#include "kern_util.h"
16#include "chan_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "user_util.h"
18#include "user.h"
19#include "os.h"
20#include "xterm.h"
21
22struct xterm_chan {
23 int pid;
24 int helper_pid;
25 char *title;
26 int device;
27 int raw;
28 struct termios tt;
29 unsigned long stack;
30 int direct_rcv;
31};
32
33/* Not static because it's called directly by the tt mode gdb code */
Jeff Dike5e7672e2006-09-27 01:50:33 -070034void *xterm_init(char *str, int device, const struct chan_opts *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
36 struct xterm_chan *data;
37
38 data = malloc(sizeof(*data));
39 if(data == NULL) return(NULL);
40 *data = ((struct xterm_chan) { .pid = -1,
41 .helper_pid = -1,
42 .device = device,
43 .title = opts->xterm_title,
44 .raw = opts->raw,
45 .stack = opts->tramp_stack,
46 .direct_rcv = !opts->in_kernel } );
47 return(data);
48}
49
50/* Only changed by xterm_setup, which is a setup */
51static char *terminal_emulator = "xterm";
52static char *title_switch = "-T";
53static char *exec_switch = "-e";
54
55static int __init xterm_setup(char *line, int *add)
56{
57 *add = 0;
58 terminal_emulator = line;
59
60 line = strchr(line, ',');
61 if(line == NULL) return(0);
62 *line++ = '\0';
63 if(*line) title_switch = line;
64
65 line = strchr(line, ',');
66 if(line == NULL) return(0);
67 *line++ = '\0';
68 if(*line) 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
86/* XXX This badly needs some cleaning up in the error paths
87 * Not static because it's called directly by the tt mode gdb code
88 */
89int xterm_open(int input, int output, int primary, void *d,
90 char **dev_out)
91{
92 struct xterm_chan *data = d;
93 unsigned long stack;
94 int pid, fd, new, err;
95 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
96 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
97 "/usr/lib/uml/port-helper", "-uml-socket",
98 file, NULL };
99
100 if(os_access(argv[4], OS_ACC_X_OK) < 0)
101 argv[4] = "port-helper";
102
103 /* Check that DISPLAY is set, this doesn't guarantee the xterm
104 * will work but w/o it we can be pretty sure it won't. */
105 if (!getenv("DISPLAY")) {
106 printk("xterm_open: $DISPLAY not set.\n");
107 return -ENODEV;
108 }
109
110 fd = mkstemp(file);
111 if(fd < 0){
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700112 err = -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 printk("xterm_open : mkstemp failed, errno = %d\n", errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700114 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 }
116
117 if(unlink(file)){
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700118 err = -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 printk("xterm_open : unlink failed, errno = %d\n", errno);
Jeff Dikeb4fd3102005-09-16 19:27:49 -0700120 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 }
122 os_close_file(fd);
123
124 fd = os_create_unix_socket(file, sizeof(file), 1);
125 if(fd < 0){
126 printk("xterm_open : create_unix_socket failed, errno = %d\n",
127 -fd);
128 return(fd);
129 }
130
131 sprintf(title, data->title, data->device);
132 stack = data->stack;
133 pid = run_helper(NULL, NULL, argv, &stack);
134 if(pid < 0){
135 printk("xterm_open : run_helper failed, errno = %d\n", -pid);
136 return(pid);
137 }
138
139 if(data->stack == 0) free_stack(stack, 0);
140
141 if (data->direct_rcv) {
142 new = os_rcv_fd(fd, &data->helper_pid);
143 } else {
144 err = os_set_fd_block(fd, 0);
145 if(err < 0){
146 printk("xterm_open : failed to set descriptor "
147 "non-blocking, err = %d\n", -err);
148 return(err);
149 }
150 new = xterm_fd(fd, &data->helper_pid);
151 }
152 if(new < 0){
153 printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
154 goto out;
155 }
156
157 CATCH_EINTR(err = tcgetattr(new, &data->tt));
158 if(err){
159 new = err;
160 goto out;
161 }
162
163 if(data->raw){
164 err = raw(new);
165 if(err){
166 new = err;
167 goto out;
168 }
169 }
170
171 data->pid = pid;
172 *dev_out = NULL;
173 out:
174 unlink(file);
175 return(new);
176}
177
178/* Not static because it's called directly by the tt mode gdb code */
179void xterm_close(int fd, void *d)
180{
181 struct xterm_chan *data = d;
182
183 if(data->pid != -1)
184 os_kill_process(data->pid, 1);
185 data->pid = -1;
186 if(data->helper_pid != -1)
187 os_kill_process(data->helper_pid, 0);
188 data->helper_pid = -1;
189 os_close_file(fd);
190}
191
192static void xterm_free(void *d)
193{
194 free(d);
195}
196
Jeff Dike5e7672e2006-09-27 01:50:33 -0700197const struct chan_ops xterm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 .type = "xterm",
199 .init = xterm_init,
200 .open = xterm_open,
201 .close = xterm_close,
202 .read = generic_read,
203 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -0800204 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 .window_size = generic_window_size,
206 .free = xterm_free,
207 .winch = 1,
208};
209
210/*
211 * Overrides for Emacs so that we follow Linus's tabbing style.
212 * Emacs will notice this stuff at the end of the file and automatically
213 * adjust the settings for this buffer only. This must remain at the end
214 * of the file.
215 * ---------------------------------------------------------------------------
216 * Local variables:
217 * c-file-style: "linux"
218 * End:
219 */