003db9d98245374e58b5172a2f2f00063ffe1796
diff --git a/src/pty.c b/src/pty.c
index 6c13abb..70639f2 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -16,7 +16,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include "../config.h"
+#include <config.h>
+
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #ifdef HAVE_SYS_TERMIOS_H
@@ -153,7 +154,11 @@ struct vte_pty_child_setup_data {
 		const char *name;
 		int fd;
 	} tty;
+        GSpawnFlags spawn_flags;
+        GSpawnChildSetupFunc child_setup;
+        gpointer child_setup_data;
 };
+
 static void
 vte_pty_child_setup (gpointer arg)
 {
@@ -246,10 +251,14 @@ vte_pty_child_setup (gpointer arg)
 		close(fd);
 	}
 
-
 	/* Reset our signals -- our parent may have done any number of
 	 * weird things to them. */
 	_vte_pty_reset_signal_handlers();
+
+        /* Now call the extra child setup */
+        if (data->child_setup) {
+                data->child_setup (data->child_setup_data);
+        }
 }
 
 /* TODO: clean up the spawning
@@ -315,6 +324,7 @@ _vte_pty_run_on_pty (struct vte_pty_child_setup_data *data,
 	if (command != NULL) {
 		gchar **arg2, **envp2;
 		gint i, argc;
+                GSpawnFlags spawn_flags;
 
 		/* push the command into argv[0] */
 		argc = argv ? g_strv_length (argv) : 0;
@@ -340,12 +350,14 @@ _vte_pty_run_on_pty (struct vte_pty_child_setup_data *data,
 					directory ? directory : "(none)");
 		}
 
+                spawn_flags = data->spawn_flags;
+                if (argv) {
+                        spawn_flags |= G_SPAWN_FILE_AND_ARGV_ZERO;
+                }
+
 		ret = g_spawn_async_with_pipes (directory,
 				arg2, envp2,
-				G_SPAWN_CHILD_INHERITS_STDIN |
-				G_SPAWN_SEARCH_PATH |
-				G_SPAWN_DO_NOT_REAP_CHILD |
-				(argv ? G_SPAWN_FILE_AND_ARGV_ZERO : 0),
+                                spawn_flags,
 				vte_pty_child_setup, data,
 				pid,
 				NULL, NULL, NULL,
@@ -358,10 +370,7 @@ _vte_pty_run_on_pty (struct vte_pty_child_setup_data *data,
 				g_clear_error (&local_error);
 				ret = g_spawn_async_with_pipes (NULL,
 						arg2, envp2,
-						G_SPAWN_CHILD_INHERITS_STDIN |
-						G_SPAWN_SEARCH_PATH |
-						G_SPAWN_DO_NOT_REAP_CHILD |
-						(argv ? G_SPAWN_FILE_AND_ARGV_ZERO : 0),
+                                                spawn_flags,
 						vte_pty_child_setup, data,
 						pid,
 						NULL, NULL, NULL,
@@ -407,12 +416,18 @@ static gboolean
 _vte_pty_fork_on_pty_name (const char *path, int parent_fd, char **envp,
 			   const char *command, char **argv,
 			   const char *directory,
-			   int columns, int rows, GPid *child)
+			   int columns, int rows,
+                           GSpawnFlags flags,
+                           GSpawnChildSetupFunc child_setup, gpointer child_setup_data,
+                           GPid *child)
 {
 	struct vte_pty_child_setup_data data;
 
 	data.mode = TTY_OPEN_BY_NAME;
 	data.tty.name = path;
+        data.spawn_flags = flags;
+        data.child_setup = child_setup;
+        data.child_setup_data = child_setup_data;
 
 	if (!_vte_pty_run_on_pty(&data,
 			command, argv, envp, directory,
@@ -431,12 +446,18 @@ static gboolean
 _vte_pty_fork_on_pty_fd (int fd, char **envp,
 			 const char *command, char **argv,
 			 const char *directory,
-			 int columns, int rows, GPid *child)
+			 int columns, int rows,
+                         GSpawnFlags flags,
+                         GSpawnChildSetupFunc child_setup, gpointer child_setup_data,
+                         GPid *child)
 {
 	struct vte_pty_child_setup_data data;
 
 	data.mode = TTY_OPEN_BY_FD;
 	data.tty.fd = fd;
+        data.spawn_flags = flags;
+        data.child_setup = child_setup;
+        data.child_setup_data = child_setup_data;
 
 	if (!_vte_pty_run_on_pty(&data,
 				command, argv, envp, directory,
@@ -603,7 +624,9 @@ _vte_pty_unlockpt(int fd)
 static int
 _vte_pty_open_unix98(GPid *child, char **env_add,
 		     const char *command, char **argv,
-		     const char *directory, int columns, int rows)
+		     const char *directory, int columns, int rows,
+                     GSpawnFlags flags,
+                     GSpawnChildSetupFunc child_setup, gpointer child_setup_data)
 {
 	int fd;
 	char *buf;
@@ -626,6 +649,8 @@ _vte_pty_open_unix98(GPid *child, char **env_add,
 						      env_add, command,
 						      argv, directory,
 						      columns, rows,
+                                                      flags,
+                                                      child_setup, child_setup_data,
 						      child)) {
 				close(fd);
 				fd = -1;
@@ -878,7 +903,9 @@ static int
 _vte_pty_open_with_helper(GPid *child, char **env_add,
 			  const char *command, char **argv,
 			  const char *directory,
-			  int columns, int rows, int op)
+			  int columns, int rows, int op,
+                          GSpawnFlags flags,
+                          GSpawnChildSetupFunc child_setup, gpointer child_setup_data)
 {
 	GnomePtyOps ops;
 	int ret;
@@ -934,7 +961,10 @@ _vte_pty_open_with_helper(GPid *child, char **env_add,
 		/* Start up a child process with the given command. */
 		if (!_vte_pty_fork_on_pty_fd(childfd, env_add, command,
 					    argv, directory,
-					    columns, rows, child)) {
+					    columns, rows,
+                                            flags,
+                                            child_setup, child_setup_data,
+                                            child)) {
 			close(parentfd);
 			close(childfd);
 			return -1;
@@ -971,7 +1001,10 @@ int
 _vte_pty_open(pid_t *child_pid, char **env_add,
 	      const char *command, char **argv, const char *directory,
 	      int columns, int rows,
-	      gboolean lastlog, gboolean utmp, gboolean wtmp)
+	      gboolean lastlog, gboolean utmp, gboolean wtmp,
+              GSpawnFlags flags,
+              GSpawnChildSetupFunc child_setup, gpointer child_setup_data)
+
 {
 	GPid child;
 	int ret = -1;
@@ -1001,12 +1034,16 @@ _vte_pty_open(pid_t *child_pid, char **env_add,
 	if (ret == -1) {
 		ret = _vte_pty_open_with_helper(&child, env_add, command, argv,
 						directory,
-						columns, rows, opmap[op]);
+						columns, rows, opmap[op],
+                                                flags,
+                                                child_setup, child_setup_data);
 	}
 #endif
 	if (ret == -1) {
 		ret = _vte_pty_open_unix98(&child, env_add, command, argv,
-					   directory, columns, rows);
+					   directory, columns, rows,
+                                           flags,
+                                           child_setup, child_setup_data);
 	}
 	if (ret != -1) {
 		*child_pid = (pid_t) child;
diff --git a/src/pty.h b/src/pty.h
index 063f92d..bc6a371 100644
--- a/src/pty.h
+++ b/src/pty.h
@@ -30,7 +30,9 @@ G_BEGIN_DECLS
 int _vte_pty_open(pid_t *child, char **env_add,
 		  const char *command, char **argv, const char *directory,
 		  int columns, int rows,
-		  gboolean lastlog, gboolean utmp, gboolean wtmp);
+		  gboolean lastlog, gboolean utmp, gboolean wtmp,
+                  GSpawnFlags flags,
+                  GSpawnChildSetupFunc child_setup, gpointer child_setup_data);
 
 /* Set or read the size of a terminal.  Returns 0 on success, -1 on failure,
  * with errno set to defined return codes from ioctl(). */
diff --git a/src/vte.c b/src/vte.c
index c658884..1fdda09 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -3221,10 +3221,17 @@ _vte_terminal_disconnect_pty_write(VteTerminal *terminal)
 
 /* Basic wrapper around _vte_pty_open, which handles the pipefitting. */
 static pid_t
-_vte_terminal_fork_basic(VteTerminal *terminal, const char *command,
-			 char **argv, char **envv,
+_vte_terminal_fork_basic(VteTerminal *terminal,
+                         const char *command,
+			 char **argv,
+                         char **envv,
 			 const char *directory,
-			 gboolean lastlog, gboolean utmp, gboolean wtmp)
+			 gboolean lastlog,
+                         gboolean utmp,
+                         gboolean wtmp,
+                         GSpawnFlags flags,
+                         GSpawnChildSetupFunc child_setup,
+                         gpointer child_setup_data)
 {
 	char **env_add;
 	int i, fd;
@@ -3259,7 +3266,8 @@ _vte_terminal_fork_basic(VteTerminal *terminal, const char *command,
 	pid = -1;
 	fd = _vte_pty_open(&pid, env_add, command, argv, directory,
 			  terminal->column_count, terminal->row_count,
-			  lastlog, utmp, wtmp);
+			  lastlog, utmp, wtmp,
+                          flags, child_setup, child_setup_data);
 	if (pid == -1 || fd == -1) {
 		g_strfreev(env_add);
 		return -1;
@@ -3299,7 +3307,7 @@ _vte_terminal_fork_basic(VteTerminal *terminal, const char *command,
 }
 
 /**
- * vte_terminal_fork_command:
+ * vte_terminal_fork_command_full:
  * @terminal: a #VteTerminal
  * @command: the name of a binary to run, or %NULL to get user's shell
  * @argv: the argument list to be passed to @command, or %NULL
@@ -3309,6 +3317,9 @@ _vte_terminal_fork_basic(VteTerminal *terminal, const char *command,
  * @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
+ * @flags: flags from #GSpawnFlags
+ * @child_setup: function to run in the child just before exec()
+ * @child_setup_data: user data for @child_setup
  *
  * Starts the specified command under a newly-allocated controlling
  * pseudo-terminal.  The @argv and @envv lists should be %NULL-terminated, and
@@ -3317,18 +3328,31 @@ _vte_terminal_fork_basic(VteTerminal *terminal, const char *command,
  * terminal widget's emulation setting.  If @lastlog, @utmp, or @wtmp are %TRUE,
  * logs the session to the specified system log files.
  *
- * Note that all file descriptors except stdin/stdout/stderr will be closed
- * before calling exec() in the child.
+ * @flags must contain at least #G_SPAWN_DO_NOT_REAP_CHILD.
+ * 
+ * Note that all unless @flags contains #G_SPAWN_LEAVE_DESCRIPTORS_OPEN, all file
+ * descriptors except stdin/stdout/stderr will be closed before calling exec()
+ * in the child.
  * 
  * Returns: the ID of the new process
+ *
+ * Since: 0.17.5
  */
 pid_t
-vte_terminal_fork_command(VteTerminal *terminal,
-			  const char *command, char **argv, char **envv,
-			  const char *directory,
-			  gboolean lastlog, gboolean utmp, gboolean wtmp)
+vte_terminal_fork_command_full(VteTerminal *terminal,
+                               const char *command,
+                               char **argv,
+                               char **envv,
+                               const char *directory,
+                               gboolean lastlog,
+                               gboolean utmp,
+                               gboolean wtmp,
+                               GSpawnFlags flags,
+                               GSpawnChildSetupFunc child_setup,
+                               gpointer child_setup_data)
 {
 	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
+        g_return_val_if_fail ((flags & G_SPAWN_DO_NOT_REAP_CHILD), -1);
 
 	/* Make the user's shell the default command. */
 	if (command == NULL) {
@@ -3361,7 +3385,101 @@ vte_terminal_fork_command(VteTerminal *terminal,
 
 	/* Start up the command and get the PTY of the master. */
 	return _vte_terminal_fork_basic(terminal, command, argv, envv,
-				        directory, lastlog, utmp, wtmp);
+				        directory, lastlog, utmp, wtmp,
+                                        flags, child_setup, child_setup_data);
+}
+
+/**
+ * vte_terminal_fork_command:
+ * @terminal: a #VteTerminal
+ * @command: the name of a binary to run, or %NULL to get user's shell
+ * @argv: the argument list to be passed to @command, or %NULL
+ * @envv: a list of environment variables to be added to the environment before
+ * starting @command, or %NULL
+ * @directory: the name of a directory the command should start in, 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 the specified command under a newly-allocated controlling
+ * pseudo-terminal.  The @argv and @envv lists should be %NULL-terminated, and
+ * argv[0] is expected to be the name of the file being run, as it would be if
+ * execve() were being called.  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.
+ *
+ * Note that all file descriptors except stdin/stdout/stderr will be closed
+ * before calling exec() in the child.
+ *
+ * This is equivalent to calling vte_terminal_fork_command_full() with 
+ * flags #G_SPAWN_CHILD_INHERITS_STDIN | #G_SPAWN_SEARCH_PATH | #G_SPAWN_DO_NOT_REAP_CHILD
+ * and NULL child setup function and data.
+ * 
+ * Returns: the ID of the new process
+ */
+pid_t
+vte_terminal_fork_command(VteTerminal *terminal,
+			  const char *command,
+                          char **argv,
+                          char **envv,
+			  const char *directory,
+			  gboolean lastlog,
+                          gboolean utmp,
+                          gboolean wtmp)
+{
+        return vte_terminal_fork_command_full(terminal, command, argv, envv, directory,
+                                              lastlog, utmp, wtmp,
+                                              G_SPAWN_CHILD_INHERITS_STDIN |
+                                              G_SPAWN_SEARCH_PATH |
+                                              G_SPAWN_DO_NOT_REAP_CHILD,
+                                              NULL, NULL);
+}
+
+/**
+ * vte_terminal_forkpty_full:
+ * @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
+ * @flags: flags from #GSpawnFlags
+ * @child_setup: function to run in the child just before exec()
+ * @child_setup_data: user data for @child_setup
+ *
+ * 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.
+ *
+ * @flags must contain at least #G_SPAWN_DO_NOT_REAP_CHILD.
+ * 
+ * Note that all unless @flags contains #G_SPAWN_LEAVE_DESCRIPTORS_OPEN, all file
+ * descriptors except stdin/stdout/stderr will be closed in the child.
+ * 
+ * Returns: the ID of the new process in the parent, 0 in the child, and -1 if
+ * there was an error
+ *
+ * Since: 0.17.5
+ */
+pid_t
+vte_terminal_forkpty_full(VteTerminal *terminal,
+                          char **envv, const char *directory,
+                          gboolean lastlog, gboolean utmp, gboolean wtmp,
+                          GSpawnFlags flags,
+                          GSpawnChildSetupFunc child_setup,
+                          gpointer child_setup_data)
+{
+	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
+
+	return _vte_terminal_fork_basic(terminal, NULL, NULL, envv,
+				       directory, lastlog, utmp, wtmp,
+                                       G_SPAWN_CHILD_INHERITS_STDIN |
+                                       G_SPAWN_SEARCH_PATH |
+                                       G_SPAWN_DO_NOT_REAP_CHILD,
+                                       NULL, NULL);
 }
 
 /**
@@ -3380,6 +3498,13 @@ vte_terminal_fork_command(VteTerminal *terminal,
  * emulation setting.  If @lastlog, @utmp, or @wtmp are %TRUE, logs the session
  * to the specified system log files.
  *
+ * Note that all file descriptors except stdin/stdout/stderr will be closed
+ * in the child.
+ *
+ * This is equivalent to calling vte_terminal_forkpty_full() with
+ * flags #G_SPAWN_CHILD_INHERITS_STDIN | #G_SPAWN_SEARCH_PATH | #G_SPAWN_DO_NOT_REAP_CHILD
+ * and NULL child setup function and data.
+ * 
  * Returns: the ID of the new process in the parent, 0 in the child, and -1 if
  * there was an error
  *
@@ -3390,10 +3515,12 @@ vte_terminal_forkpty(VteTerminal *terminal,
 		     char **envv, const char *directory,
 		     gboolean lastlog, gboolean utmp, gboolean wtmp)
 {
-	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
-
-	return _vte_terminal_fork_basic(terminal, NULL, NULL, envv,
-				       directory, lastlog, utmp, wtmp);
+        return vte_terminal_forkpty_full(terminal, envv, directory,
+                                         lastlog, utmp, wtmp,
+                                         G_SPAWN_CHILD_INHERITS_STDIN |
+                                         G_SPAWN_SEARCH_PATH |
+                                         G_SPAWN_DO_NOT_REAP_CHILD,
+                                         NULL, NULL);
 }
 
 /* Handle an EOF from the client. */
diff --git a/src/vte.h b/src/vte.h
index 9878009..7f5e644 100644
--- a/src/vte.h
+++ b/src/vte.h
@@ -227,12 +227,32 @@ pid_t vte_terminal_fork_command(VteTerminal *terminal,
 				gboolean utmp,
 				gboolean wtmp);
 
+pid_t vte_terminal_fork_command_full(VteTerminal *terminal,
+                                     const char *command,
+                                     char **argv,
+                                     char **envv,
+                                     const char *directory,
+                                     gboolean lastlog,
+                                     gboolean utmp,
+                                     gboolean wtmp,
+                                     GSpawnFlags flags,
+                                     GSpawnChildSetupFunc child_setup,
+                                     gpointer child_setup_data);
+
 /* 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);
+pid_t vte_terminal_forkpty_full(VteTerminal *terminal,
+                                char **envv, const char *directory,
+                                gboolean lastlog,
+                                gboolean utmp,
+                                gboolean wtmp,
+                                GSpawnFlags flags,
+                                GSpawnChildSetupFunc child_setup,
+                                gpointer child_setup_data);
 
 /* 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. */
