Bug#241485: libvte4: [PATCH] please add vte_terminal_fork_pty()

Michael Vogt Michael Vogt <mvogt@acm.org>, 241485@bugs.debian.org
Thu, 01 Apr 2004 17:00:14 +0200


This is a multi-part MIME message sent by reportbug.

--===============1541456203==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Package: libvte4
Version: 1:0.11.10-6
Severity: wishlist
Tags: patch

Please add the attached patch to libvte4. This patch is taken from
the current vte cvs. It will make it possible for synaptic (and other 
applications) to use vte instead of zvt. Having to use zvt because of 
the missing fork_pty() support in vte is a huge pain because zvt is 
_very_ buggy and causes segfaults for certain LANG settings. 

The patch is done very carefull and only touches vte.{c,h} and pty.c. In
vte.c only vte_terminal_fork_pty() is added, no existing code is
touched. 

pty.c is a bit more tricky. Existing code is modified. But I'm sure that
the code is safe too. The first chunk move the old code inside 
"if(command!=NULL)" which is always true if it is called from  
vte_terminal_fork_command(). The last chunk is also safe as argc > 1
is always true if called from vte_terminal_fork_command(). If
fork_command() is called without a command then the shell is used.
(see vte.c:6946).

I tested this patch with gnome-terminal and with the fork_pty() enabled
version of synaptic and it seems to work well. If there is anything more
I can do to convince you to apply this patch, please tell me :) 

I would really love to kick libzvt as a dependency from synaptic and
make it vte instead.

thanks,
 Michael

-- System Information:
Debian Release: testing/unstable
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: i386 (i686)
Kernel: Linux 2.4.25
Locale: LANG=C, LC_CTYPE=de_DE

Versions of packages libvte4 depends on:
ii  libatk1.0-0                 1.4.1-1      The ATK accessibility toolkit
ii  libc6                       2.3.2.ds1-11 GNU C Library: Shared libraries an
ii  libfontconfig1              2.2.2-1      generic font configuration library
ii  libfreetype6                2.1.7-2      FreeType 2 font engine, shared lib
ii  libglib2.0-0                2.2.3-1      The GLib library of C routines
ii  libgtk2.0-0                 2.2.4-3      The GTK+ graphical user interface 
ii  libice6                     4.3.0-7      Inter-Client Exchange library
ii  libncurses5                 5.4-3        Shared libraries for terminal hand
ii  libpango1.0-0               1.2.5-2.1    Layout and rendering of internatio
ii  libsm6                      4.3.0-7      X Window System Session Management
ii  libvte-common               1:0.11.10-6  Terminal emulator widget for GTK+ 
ii  libx11-6                    4.3.0-7      X Window System protocol client li
ii  libxft2                     2.1.2-6      FreeType-based font drawing librar
ii  libxrender1                 0.8.3-7      X Rendering Extension client libra
ii  xlibs                       4.3.0-7      X Window System client libraries m
ii  zlib1g                      1:1.2.1-5    compression library - runtime

-- no debconf information

--===============1541456203==
Content-Type: text/x-c; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="vte-fork-pty.diff"

--- vte-0.11.10.orig/src/vte.h
+++ vte-0.11.10/src/vte.h
@@ -158,6 +158,13 @@
 				gboolean utmp,
 				gboolean wtmp);
 
+/* Users of libzvt may find this useful. */
+pid_t vte_terminal_forkpty(VteTerminal *terminal,
+			   char **envv, const char *directory,
+			   gboolean lastlog,
+			   gboolean utmp,
+			   gboolean wtmp);
+
 /* Send data to the terminal to display, or to the terminal's forked command
  * to handle in some way.  If it's 'cat', they should be the same. */
 void vte_terminal_feed(VteTerminal *terminal, const char *data, glong length);
--- vte-0.11.10.orig/src/vte.c
+++ vte-0.11.10/src/vte.c
@@ -6791,6 +6791,122 @@
 }
 
 /**
+ * vte_terminal_forkpty:
+ * @terminal: a #VteTerminal
+ * @envv: a list of environment variables to be added to the environment before
+ * starting returning in the child process, or NULL
+ * @directory: the name of a directory the child process should change to, or
+ * NULL
+ * @lastlog: TRUE if the session should be logged to the lastlog
+ * @utmp: TRUE if the session should be logged to the utmp/utmpx log
+ * @wtmp: TRUE if the session should be logged to the wtmp/wtmpx log
+ *
+ * Starts a new child process under a newly-allocated controlling
+ * pseudo-terminal.  TERM is automatically set to reflect the terminal widget's
+ * emulation setting.  If @lastlog, @utmp, or @wtmp are TRUE, logs the session
+ * to the specified system log files.
+ *
+ * Returns: the ID of the new process in the parent, 0 in the child, and -1 if
+ * there was an error
+ *
+ * Since: 0.11.11
+ */
+pid_t
+vte_terminal_forkpty(VteTerminal *terminal,
+		     char **envv, const char *directory,
+		     gboolean lastlog, gboolean utmp, gboolean wtmp)
+{
+	char **env_add;
+	int i;
+	pid_t pid;
+	GtkWidget *widget;
+	VteReaper *reaper;
+
+	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
+
+/* 	ret = _vte_terminal_fork_basic(terminal, NULL, NULL, envv, */
+/* 				       directory, lastlog, utmp, wtmp); */
+	widget = GTK_WIDGET(terminal);
+
+	/* Duplicate the environment, and add one more variable. */
+	for (i = 0; (envv != NULL) && (envv[i] != NULL); i++) {
+		/* nothing */ ;
+	}
+	env_add = g_malloc0(sizeof(char*) * (i + 2));
+	env_add[0] = g_strdup_printf("TERM=%s", terminal->pvt->emulation);
+	for (i = 0; (envv != NULL) && (envv[i] != NULL); i++) {
+		env_add[i + 1] = g_strdup(envv[i]);
+	}
+	env_add[i + 1] = NULL;
+
+	/* Close any existing ptys. */
+	if (terminal->pvt->pty_master != -1) {
+		_vte_pty_close(terminal->pvt->pty_master);
+		close(terminal->pvt->pty_master);
+	}
+
+	/* Open the new pty. */
+	pid = -1;
+	i = _vte_pty_open(&pid, env_add, NULL, NULL, directory,
+			  terminal->column_count, terminal->row_count,
+			  lastlog, utmp, wtmp);
+	switch (i) {
+	case -1:
+		return -1;
+		break;
+	default:
+		if (pid != 0) {
+			terminal->pvt->pty_master = i;
+		}
+	}
+
+	/* If we successfully started the process, set up to listen for its
+	 * output. */
+	if ((pid != -1) && (pid != 0)) {
+		/* Set this as the child's pid. */
+		terminal->pvt->pty_pid = pid;
+
+		/* Catch a child-exited signal from the child pid. */
+		reaper = vte_reaper_get();
+		g_object_ref(G_OBJECT(reaper));
+		if (VTE_IS_REAPER(terminal->pvt->pty_reaper)) {
+			g_signal_handlers_disconnect_by_func(terminal->pvt->pty_reaper,
+							     (gpointer)vte_terminal_catch_child_exited,
+							     terminal);
+			g_object_unref(G_OBJECT(terminal->pvt->pty_reaper));
+		}
+		g_signal_connect(G_OBJECT(reaper), "child-exited",
+				 G_CALLBACK(vte_terminal_catch_child_exited),
+				 terminal);
+		terminal->pvt->pty_reaper = reaper;
+
+		/* Set the pty to be non-blocking. */
+		i = fcntl(terminal->pvt->pty_master, F_GETFL);
+		fcntl(terminal->pvt->pty_master, F_SETFL, i | O_NONBLOCK);
+
+		/* Set the PTY size. */
+		vte_terminal_set_size(terminal,
+				      terminal->column_count,
+				      terminal->row_count);
+		if (GTK_WIDGET_REALIZED(widget)) {
+			gtk_widget_queue_resize(widget);
+		}
+
+		/* Open a channel to listen for input on. */
+		_vte_terminal_connect_pty_read(terminal);
+	}
+
+	/* Clean up. */
+	for (i = 0; env_add[i] != NULL; i++) {
+		g_free(env_add[i]);
+	}
+	g_free(env_add);
+
+	return pid;
+}
+
+
+/**
  * vte_terminal_fork_command:
  * @terminal: a #VteTerminal
  * @command: the name of a binary to run
--- vte-0.11.10.orig/src/pty.c
+++ vte-0.11.10/src/pty.c
@@ -362,23 +362,26 @@
 		close(ready_reader);
 	}
 
-	/* Outta here. */
-	if (argv != NULL) {
-		for (i = 0; (argv[i] != NULL); i++) ;
-		args = g_malloc0(sizeof(char*) * (i + 1));
-		for (i = 0; (argv[i] != NULL); i++) {
-			args[i] = g_strdup(argv[i]);
-		}
-		execvp(command, args);
-	} else {
-		arg = g_strdup(command);
-		execlp(command, arg, NULL);
-	}
-
-	/* Avoid calling any atexit() code. */
-	_exit(0);
-	g_assert_not_reached();
-	return 0;
+        /* If the caller provided a command, we can't go back, ever. */
+        if (command != NULL) {
+                /* Outta here. */
+                if (argv != NULL) {
+                        for (i = 0; (argv[i] != NULL); i++) ;
+                        args = g_malloc0(sizeof(char*) * (i + 1));
+                        for (i = 0; (argv[i] != NULL); i++) {
+                                args[i] = g_strdup(argv[i]);
+                        }
+                        execvp(command, args);
+                } else {
+                        arg = g_strdup(command);
+                        execlp(command, arg, NULL);
+                } 
+
+                /* Avoid calling any atexit() code. */
+                _exit(0);
+                g_assert_not_reached();
+        }
+        return 0;
 }
 
 /* Open the named PTY slave, fork off a child (storing its PID in child),
@@ -469,6 +472,9 @@
 	/* TIOCSCTTY is defined?  Let's try that, too. */
 	ioctl(fd, TIOCSCTTY, fd);
 #endif
+	/* Store 0 as the "child"'s ID to indicate to the caller that
+	 * it is now the child. */
+	*child = 0;
 	return _vte_pty_run_on_pty(fd, ready_b[0], ready_a[1],
 				   env_add, command, argv, directory);
 }
@@ -569,6 +575,9 @@
 #endif
 	}
 
+	/* Store 0 as the "child"'s ID to indicate to the caller that
+	 * it is now the child. */
+	*child = 0;
 	return _vte_pty_run_on_pty(fd, ready_b[0], ready_a[1],
 				   env_add, command, argv, directory);
 }
@@ -1140,7 +1149,7 @@
 	signal(SIGCHLD, sigchld_handler);
 	_vte_debug_parse_string(getenv("VTE_DEBUG_FLAGS"));
 	fd = _vte_pty_open(&child, NULL,
-			   (argc > 1) ? argv[1] : "/usr/bin/tty",
+			   (argc > 1) ? argv[1]  : NULL,
 			   (argc > 1) ? argv + 1 : NULL,
 			   NULL,
 			   0, 0,

--===============1541456203==--