^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <termios.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "chan_user.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <os.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <um_malloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "xterm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct xterm_chan {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) int pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int helper_pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int chan_fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) char *title;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int raw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct termios tt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static void *xterm_init(char *str, int device, const struct chan_opts *opts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct xterm_chan *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (data == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) *data = ((struct xterm_chan) { .pid = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .helper_pid = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .chan_fd = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .device = device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) .title = opts->xterm_title,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .raw = opts->raw } );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* Only changed by xterm_setup, which is a setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static char *terminal_emulator = "xterm";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static char *title_switch = "-T";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static char *exec_switch = "-e";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static int __init xterm_setup(char *line, int *add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *add = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) terminal_emulator = line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) line = strchr(line, ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (line == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *line++ = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (*line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) title_switch = line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) line = strchr(line, ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (line == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *line++ = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (*line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) exec_switch = line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) __uml_setup("xterm=", xterm_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) "xterm=<terminal emulator>,<title switch>,<exec switch>\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) " Specifies an alternate terminal emulator to use for the debugger,\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) " consoles, and serial lines when they are attached to the xterm channel.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) " The values are the terminal emulator binary, the switch it uses to set\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) " its title, and the switch it uses to execute a subprocess,\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) " respectively. The title switch must have the form '<switch> title',\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) " not '<switch>=title'. Similarly, the exec switch must have the form\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) " '<switch> command arg1 arg2 ...'.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) " The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) " are 'xterm=gnome-terminal,-t,-x'.\n\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int xterm_open(int input, int output, int primary, void *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) char **dev_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct xterm_chan *data = d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int pid, fd, new, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) OS_LIB_PATH "/uml/port-helper", "-uml-socket",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) file, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (access(argv[4], X_OK) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) argv[4] = "port-helper";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Check that DISPLAY is set, this doesn't guarantee the xterm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * will work but w/o it we can be pretty sure it won't.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (getenv("DISPLAY") == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * This business of getting a descriptor to a temp file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * deleting the file and closing the descriptor is just to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * a known-unused name for the Unix socket that we really
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * want.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) fd = mkstemp(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (fd < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) err = -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) errno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (unlink(file)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) err = -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) errno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) fd = os_create_unix_socket(file, sizeof(file), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (fd < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) "errno = %d\n", -fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) sprintf(title, data->title, data->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pid = run_helper(NULL, NULL, argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (pid < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) err = pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) printk(UM_KERN_ERR "xterm_open : run_helper failed, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) "errno = %d\n", -err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) goto out_close1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) err = os_set_fd_block(fd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) printk(UM_KERN_ERR "xterm_open : failed to set descriptor "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) "non-blocking, err = %d\n", -err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) goto out_kill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) data->chan_fd = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) new = xterm_fd(fd, &data->helper_pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (new < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) err = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) -err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) goto out_kill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) err = os_set_fd_block(new, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) printk(UM_KERN_ERR "xterm_open : failed to set xterm "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) "descriptor non-blocking, err = %d\n", -err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) goto out_close2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) CATCH_EINTR(err = tcgetattr(new, &data->tt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) new = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) goto out_close2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (data->raw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) err = raw(new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) new = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) goto out_close2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) unlink(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) data->pid = pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) *dev_out = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) out_close2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) close(new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) out_kill:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) os_kill_process(pid, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) out_close1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static void xterm_close(int fd, void *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct xterm_chan *data = d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (data->pid != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) os_kill_process(data->pid, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) data->pid = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (data->helper_pid != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) os_kill_process(data->helper_pid, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) data->helper_pid = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (data->chan_fd != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) os_close_file(data->chan_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) os_close_file(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) const struct chan_ops xterm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) .type = "xterm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) .init = xterm_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .open = xterm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .close = xterm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .read = generic_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .write = generic_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .console_write = generic_console_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .window_size = generic_window_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .free = generic_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .winch = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) };