linux/arch/um/drivers/xterm.c
<<
>>
Prefs
   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
  18struct xterm_chan {
  19        int pid;
  20        int helper_pid;
  21        char *title;
  22        int device;
  23        int raw;
  24        struct termios tt;
  25};
  26
  27static 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 */
  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, ',');
  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
  84static 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
 197static 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
 212const 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};
 224