xref: /openbmc/linux/arch/um/drivers/xterm.c (revision 5e7672ec3f059f764fcc5c78216e24bb16c44dba)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
31da177e4SLinus Torvalds  * Licensed under the GPL
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <stdio.h>
71da177e4SLinus Torvalds #include <stdlib.h>
81da177e4SLinus Torvalds #include <unistd.h>
91da177e4SLinus Torvalds #include <string.h>
101da177e4SLinus Torvalds #include <errno.h>
111da177e4SLinus Torvalds #include <termios.h>
121da177e4SLinus Torvalds #include <signal.h>
131da177e4SLinus Torvalds #include <sched.h>
141da177e4SLinus Torvalds #include <sys/socket.h>
151da177e4SLinus Torvalds #include "kern_util.h"
161da177e4SLinus Torvalds #include "chan_user.h"
171da177e4SLinus Torvalds #include "user_util.h"
181da177e4SLinus Torvalds #include "user.h"
191da177e4SLinus Torvalds #include "os.h"
201da177e4SLinus Torvalds #include "xterm.h"
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds struct xterm_chan {
231da177e4SLinus Torvalds 	int pid;
241da177e4SLinus Torvalds 	int helper_pid;
251da177e4SLinus Torvalds 	char *title;
261da177e4SLinus Torvalds 	int device;
271da177e4SLinus Torvalds 	int raw;
281da177e4SLinus Torvalds 	struct termios tt;
291da177e4SLinus Torvalds 	unsigned long stack;
301da177e4SLinus Torvalds 	int direct_rcv;
311da177e4SLinus Torvalds };
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds /* Not static because it's called directly by the tt mode gdb code */
34*5e7672ecSJeff Dike void *xterm_init(char *str, int device, const struct chan_opts *opts)
351da177e4SLinus Torvalds {
361da177e4SLinus Torvalds 	struct xterm_chan *data;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	data = malloc(sizeof(*data));
391da177e4SLinus Torvalds 	if(data == NULL) return(NULL);
401da177e4SLinus Torvalds 	*data = ((struct xterm_chan) { .pid 		= -1,
411da177e4SLinus Torvalds 				       .helper_pid 	= -1,
421da177e4SLinus Torvalds 				       .device 		= device,
431da177e4SLinus Torvalds 				       .title 		= opts->xterm_title,
441da177e4SLinus Torvalds 				       .raw  		= opts->raw,
451da177e4SLinus Torvalds 				       .stack 		= opts->tramp_stack,
461da177e4SLinus Torvalds 				       .direct_rcv 	= !opts->in_kernel } );
471da177e4SLinus Torvalds 	return(data);
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds /* Only changed by xterm_setup, which is a setup */
511da177e4SLinus Torvalds static char *terminal_emulator = "xterm";
521da177e4SLinus Torvalds static char *title_switch = "-T";
531da177e4SLinus Torvalds static char *exec_switch = "-e";
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds static int __init xterm_setup(char *line, int *add)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	*add = 0;
581da177e4SLinus Torvalds 	terminal_emulator = line;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	line = strchr(line, ',');
611da177e4SLinus Torvalds 	if(line == NULL) return(0);
621da177e4SLinus Torvalds 	*line++ = '\0';
631da177e4SLinus Torvalds 	if(*line) title_switch = line;
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	line = strchr(line, ',');
661da177e4SLinus Torvalds 	if(line == NULL) return(0);
671da177e4SLinus Torvalds 	*line++ = '\0';
681da177e4SLinus Torvalds 	if(*line) exec_switch = line;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	return(0);
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds __uml_setup("xterm=", xterm_setup,
741da177e4SLinus Torvalds "xterm=<terminal emulator>,<title switch>,<exec switch>\n"
751da177e4SLinus Torvalds "    Specifies an alternate terminal emulator to use for the debugger,\n"
761da177e4SLinus Torvalds "    consoles, and serial lines when they are attached to the xterm channel.\n"
771da177e4SLinus Torvalds "    The values are the terminal emulator binary, the switch it uses to set\n"
781da177e4SLinus Torvalds "    its title, and the switch it uses to execute a subprocess,\n"
791da177e4SLinus Torvalds "    respectively.  The title switch must have the form '<switch> title',\n"
801da177e4SLinus Torvalds "    not '<switch>=title'.  Similarly, the exec switch must have the form\n"
811da177e4SLinus Torvalds "    '<switch> command arg1 arg2 ...'.\n"
821da177e4SLinus Torvalds "    The default values are 'xterm=xterm,-T,-e'.  Values for gnome-terminal\n"
831da177e4SLinus Torvalds "    are 'xterm=gnome-terminal,-t,-x'.\n\n"
841da177e4SLinus Torvalds );
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds /* XXX This badly needs some cleaning up in the error paths
871da177e4SLinus Torvalds  * Not static because it's called directly by the tt mode gdb code
881da177e4SLinus Torvalds  */
891da177e4SLinus Torvalds int xterm_open(int input, int output, int primary, void *d,
901da177e4SLinus Torvalds 		      char **dev_out)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds 	struct xterm_chan *data = d;
931da177e4SLinus Torvalds 	unsigned long stack;
941da177e4SLinus Torvalds 	int pid, fd, new, err;
951da177e4SLinus Torvalds 	char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
961da177e4SLinus Torvalds 	char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
971da177e4SLinus Torvalds 			 "/usr/lib/uml/port-helper", "-uml-socket",
981da177e4SLinus Torvalds 			 file, NULL };
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	if(os_access(argv[4], OS_ACC_X_OK) < 0)
1011da177e4SLinus Torvalds 		argv[4] = "port-helper";
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	/* Check that DISPLAY is set, this doesn't guarantee the xterm
1041da177e4SLinus Torvalds 	 * will work but w/o it we can be pretty sure it won't. */
1051da177e4SLinus Torvalds 	if (!getenv("DISPLAY")) {
1061da177e4SLinus Torvalds 		printk("xterm_open: $DISPLAY not set.\n");
1071da177e4SLinus Torvalds 		return -ENODEV;
1081da177e4SLinus Torvalds 	}
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds 	fd = mkstemp(file);
1111da177e4SLinus Torvalds 	if(fd < 0){
112b4fd310eSJeff Dike 		err = -errno;
1131da177e4SLinus Torvalds 		printk("xterm_open : mkstemp failed, errno = %d\n", errno);
114b4fd310eSJeff Dike 		return err;
1151da177e4SLinus Torvalds 	}
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	if(unlink(file)){
118b4fd310eSJeff Dike 		err = -errno;
1191da177e4SLinus Torvalds 		printk("xterm_open : unlink failed, errno = %d\n", errno);
120b4fd310eSJeff Dike 		return err;
1211da177e4SLinus Torvalds 	}
1221da177e4SLinus Torvalds 	os_close_file(fd);
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	fd = os_create_unix_socket(file, sizeof(file), 1);
1251da177e4SLinus Torvalds 	if(fd < 0){
1261da177e4SLinus Torvalds 		printk("xterm_open : create_unix_socket failed, errno = %d\n",
1271da177e4SLinus Torvalds 		       -fd);
1281da177e4SLinus Torvalds 		return(fd);
1291da177e4SLinus Torvalds 	}
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	sprintf(title, data->title, data->device);
1321da177e4SLinus Torvalds 	stack = data->stack;
1331da177e4SLinus Torvalds 	pid = run_helper(NULL, NULL, argv, &stack);
1341da177e4SLinus Torvalds 	if(pid < 0){
1351da177e4SLinus Torvalds 		printk("xterm_open : run_helper failed, errno = %d\n", -pid);
1361da177e4SLinus Torvalds 		return(pid);
1371da177e4SLinus Torvalds 	}
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	if(data->stack == 0) free_stack(stack, 0);
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	if (data->direct_rcv) {
1421da177e4SLinus Torvalds 		new = os_rcv_fd(fd, &data->helper_pid);
1431da177e4SLinus Torvalds 	} else {
1441da177e4SLinus Torvalds 		err = os_set_fd_block(fd, 0);
1451da177e4SLinus Torvalds 		if(err < 0){
1461da177e4SLinus Torvalds 			printk("xterm_open : failed to set descriptor "
1471da177e4SLinus Torvalds 			       "non-blocking, err = %d\n", -err);
1481da177e4SLinus Torvalds 			return(err);
1491da177e4SLinus Torvalds 		}
1501da177e4SLinus Torvalds 		new = xterm_fd(fd, &data->helper_pid);
1511da177e4SLinus Torvalds 	}
1521da177e4SLinus Torvalds 	if(new < 0){
1531da177e4SLinus Torvalds 		printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
1541da177e4SLinus Torvalds 		goto out;
1551da177e4SLinus Torvalds 	}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	CATCH_EINTR(err = tcgetattr(new, &data->tt));
1581da177e4SLinus Torvalds 	if(err){
1591da177e4SLinus Torvalds 		new = err;
1601da177e4SLinus Torvalds 		goto out;
1611da177e4SLinus Torvalds 	}
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	if(data->raw){
1641da177e4SLinus Torvalds 		err = raw(new);
1651da177e4SLinus Torvalds 		if(err){
1661da177e4SLinus Torvalds 			new = err;
1671da177e4SLinus Torvalds 			goto out;
1681da177e4SLinus Torvalds 		}
1691da177e4SLinus Torvalds 	}
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	data->pid = pid;
1721da177e4SLinus Torvalds 	*dev_out = NULL;
1731da177e4SLinus Torvalds  out:
1741da177e4SLinus Torvalds 	unlink(file);
1751da177e4SLinus Torvalds 	return(new);
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds /* Not static because it's called directly by the tt mode gdb code */
1791da177e4SLinus Torvalds void xterm_close(int fd, void *d)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	struct xterm_chan *data = d;
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	if(data->pid != -1)
1841da177e4SLinus Torvalds 		os_kill_process(data->pid, 1);
1851da177e4SLinus Torvalds 	data->pid = -1;
1861da177e4SLinus Torvalds 	if(data->helper_pid != -1)
1871da177e4SLinus Torvalds 		os_kill_process(data->helper_pid, 0);
1881da177e4SLinus Torvalds 	data->helper_pid = -1;
1891da177e4SLinus Torvalds 	os_close_file(fd);
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds static void xterm_free(void *d)
1931da177e4SLinus Torvalds {
1941da177e4SLinus Torvalds 	free(d);
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds 
197*5e7672ecSJeff Dike const struct chan_ops xterm_ops = {
1981da177e4SLinus Torvalds 	.type		= "xterm",
1991da177e4SLinus Torvalds 	.init		= xterm_init,
2001da177e4SLinus Torvalds 	.open		= xterm_open,
2011da177e4SLinus Torvalds 	.close		= xterm_close,
2021da177e4SLinus Torvalds 	.read		= generic_read,
2031da177e4SLinus Torvalds 	.write		= generic_write,
204fd9bc53bSPaolo 'Blaisorblade' Giarrusso 	.console_write	= generic_console_write,
2051da177e4SLinus Torvalds 	.window_size	= generic_window_size,
2061da177e4SLinus Torvalds 	.free		= xterm_free,
2071da177e4SLinus Torvalds 	.winch		= 1,
2081da177e4SLinus Torvalds };
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /*
2111da177e4SLinus Torvalds  * Overrides for Emacs so that we follow Linus's tabbing style.
2121da177e4SLinus Torvalds  * Emacs will notice this stuff at the end of the file and automatically
2131da177e4SLinus Torvalds  * adjust the settings for this buffer only.  This must remain at the end
2141da177e4SLinus Torvalds  * of the file.
2151da177e4SLinus Torvalds  * ---------------------------------------------------------------------------
2161da177e4SLinus Torvalds  * Local variables:
2171da177e4SLinus Torvalds  * c-file-style: "linux"
2181da177e4SLinus Torvalds  * End:
2191da177e4SLinus Torvalds  */
220