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