Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xterm.c
Go to the documentation of this file.
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 <os.h>
15 #include <um_malloc.h>
16 #include "xterm.h"
17 
18 struct xterm_chan {
19  int pid;
21  char *title;
22  int device;
23  int raw;
24  struct termios tt;
25 };
26 
27 static void *xterm_init(char *str, int device, const struct chan_opts *opts)
28 {
29  struct xterm_chan *data;
30 
31  data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
32  if (data == NULL)
33  return NULL;
34  *data = ((struct xterm_chan) { .pid = -1,
35  .helper_pid = -1,
36  .device = device,
37  .title = opts->xterm_title,
38  .raw = opts->raw } );
39  return data;
40 }
41 
42 /* Only changed by xterm_setup, which is a setup */
43 static char *terminal_emulator = "xterm";
44 static char *title_switch = "-T";
45 static char *exec_switch = "-e";
46 
47 static int __init xterm_setup(char *line, int *add)
48 {
49  *add = 0;
50  terminal_emulator = line;
51 
52  line = strchr(line, ',');
53  if (line == NULL)
54  return 0;
55 
56  *line++ = '\0';
57  if (*line)
58  title_switch = line;
59 
60  line = strchr(line, ',');
61  if (line == NULL)
62  return 0;
63 
64  *line++ = '\0';
65  if (*line)
66  exec_switch = line;
67 
68  return 0;
69 }
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 
84 static int xterm_open(int input, int output, int primary, void *d,
85  char **dev_out)
86 {
87  struct xterm_chan *data = d;
88  int pid, fd, new, err;
89  char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
90  char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
91  OS_LIB_PATH "/uml/port-helper", "-uml-socket",
92  file, NULL };
93 
94  if (access(argv[4], X_OK) < 0)
95  argv[4] = "port-helper";
96 
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  */
101  if (getenv("DISPLAY") == NULL) {
102  printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
103  return -ENODEV;
104  }
105 
106  /*
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  */
112  fd = mkstemp(file);
113  if (fd < 0) {
114  err = -errno;
115  printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
116  errno);
117  return err;
118  }
119 
120  if (unlink(file)) {
121  err = -errno;
122  printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
123  errno);
124  close(fd);
125  return err;
126  }
127  close(fd);
128 
129  fd = os_create_unix_socket(file, sizeof(file), 1);
130  if (fd < 0) {
131  printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
132  "errno = %d\n", -fd);
133  return fd;
134  }
135 
136  sprintf(title, data->title, data->device);
137  pid = run_helper(NULL, NULL, argv);
138  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;
143  }
144 
145  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;
150  }
151 
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;
158  }
159 
160  err = os_set_fd_block(new, 0);
161  if (err) {
162  printk(UM_KERN_ERR "xterm_open : failed to set xterm "
163  "descriptor non-blocking, err = %d\n", -err);
164  goto out_close2;
165  }
166 
167  CATCH_EINTR(err = tcgetattr(new, &data->tt));
168  if (err) {
169  new = err;
170  goto out_close2;
171  }
172 
173  if (data->raw) {
174  err = raw(new);
175  if (err) {
176  new = err;
177  goto out_close2;
178  }
179  }
180 
181  unlink(file);
182  data->pid = pid;
183  *dev_out = NULL;
184 
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;
195 }
196 
197 static void xterm_close(int fd, void *d)
198 {
199  struct xterm_chan *data = d;
200 
201  if (data->pid != -1)
202  os_kill_process(data->pid, 1);
203  data->pid = -1;
204 
205  if (data->helper_pid != -1)
206  os_kill_process(data->helper_pid, 0);
207  data->helper_pid = -1;
208 
209  os_close_file(fd);
210 }
211 
212 const struct chan_ops xterm_ops = {
213  .type = "xterm",
214  .init = xterm_init,
215  .open = xterm_open,
216  .close = xterm_close,
217  .read = generic_read,
218  .write = generic_write,
219  .console_write = generic_console_write,
220  .window_size = generic_window_size,
221  .free = generic_free,
222  .winch = 1,
223 };