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 "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                         "/usr/lib/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                return err;
 127        }
 128        close(fd);
 129
 130        fd = os_create_unix_socket(file, sizeof(file), 1);
 131        if (fd < 0) {
 132                printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
 133                       "errno = %d\n", -fd);
 134                return fd;
 135        }
 136
 137        sprintf(title, data->title, data->device);
 138        pid = run_helper(NULL, NULL, argv);
 139        if (pid < 0) {
 140                err = pid;
 141                printk(UM_KERN_ERR "xterm_open : run_helper failed, "
 142                       "errno = %d\n", -err);
 143                goto out_close1;
 144        }
 145
 146        err = os_set_fd_block(fd, 0);
 147        if (err < 0) {
 148                printk(UM_KERN_ERR "xterm_open : failed to set descriptor "
 149                       "non-blocking, err = %d\n", -err);
 150                goto out_kill;
 151        }
 152
 153        new = xterm_fd(fd, &data->helper_pid);
 154        if (new < 0) {
 155                err = new;
 156                printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n",
 157                       -err);
 158                goto out_kill;
 159        }
 160
 161        err = os_set_fd_block(new, 0);
 162        if (err) {
 163                printk(UM_KERN_ERR "xterm_open : failed to set xterm "
 164                       "descriptor non-blocking, err = %d\n", -err);
 165                goto out_close2;
 166        }
 167
 168        CATCH_EINTR(err = tcgetattr(new, &data->tt));
 169        if (err) {
 170                new = err;
 171                goto out_close2;
 172        }
 173
 174        if (data->raw) {
 175                err = raw(new);
 176                if (err) {
 177                        new = err;
 178                        goto out_close2;
 179                }
 180        }
 181
 182        unlink(file);
 183        data->pid = pid;
 184        *dev_out = NULL;
 185
 186        return new;
 187
 188 out_close2:
 189        close(new);
 190 out_kill:
 191        os_kill_process(pid, 1);
 192 out_close1:
 193        close(fd);
 194
 195        return err;
 196}
 197
 198static void xterm_close(int fd, void *d)
 199{
 200        struct xterm_chan *data = d;
 201
 202        if (data->pid != -1)
 203                os_kill_process(data->pid, 1);
 204        data->pid = -1;
 205
 206        if (data->helper_pid != -1)
 207                os_kill_process(data->helper_pid, 0);
 208        data->helper_pid = -1;
 209
 210        os_close_file(fd);
 211}
 212
 213const struct chan_ops xterm_ops = {
 214        .type           = "xterm",
 215        .init           = xterm_init,
 216        .open           = xterm_open,
 217        .close          = xterm_close,
 218        .read           = generic_read,
 219        .write          = generic_write,
 220        .console_write  = generic_console_write,
 221        .window_size    = generic_window_size,
 222        .free           = generic_free,
 223        .winch          = 1,
 224};
 225