diff --git a/src/signal_handler.c b/src/signal_handler.c
index c4526d2933c7a042fe12d52c799ea372374e2bb1..f4592c3a975488e39839a338a84db3fd9b6c6989 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -25,7 +25,7 @@
 #include "main.h"
 #include <signal.h>
 
-RCSID("$Id: signal_handler.c,v 1.160 1999/11/16 21:28:53 grubba Exp $");
+RCSID("$Id: signal_handler.c,v 1.161 2000/01/14 02:44:14 grubba Exp $");
 
 #ifdef HAVE_PASSWD_H
 # include <passwd.h>
@@ -1376,6 +1376,8 @@ struct perishables
   char **env;
   char **argv;
 
+  int *fds;
+
   int disabled;
 #ifdef HAVE_SETRLIMIT
   struct plimit *limits;
@@ -1394,6 +1396,8 @@ static void free_perishables(struct perishables *storage)
     exit_threads_disable(NULL);
   }
 
+  if (storage->fds) free(storage->fds);
+
   if(storage->env) free( storage->env );
   if(storage->argv) free( storage->argv );
   while(storage->limits) 
@@ -1432,6 +1436,7 @@ extern int pike_make_pipe(int *);
 #define PROCE_SETUID		7
 #define PROCE_EXEC		8
 #define PROCE_CLOEXEC		9
+#define PROCE_DUP		10
 
 #define PROCERROR(err, id)	do { int _l, _i; \
     buf[0] = err; buf[1] = errno; buf[2] = id; \
@@ -1629,6 +1634,7 @@ void f_set_priority( INT32 args )
  *
  * only on UNIX:
  *
+ *   fds		array(object(files.file))	fds 3-.
  *   uid		int|string
  *   gid		int|string
  *   nice		int
@@ -2020,8 +2026,11 @@ void f_create_process(INT32 args)
     int stds[3]; /* stdin, out and err */
     char *tmp_cwd; /* to CD to */
     char *priority = NULL;
+    int *fds;
+    int num_fds = 3;
 
-    stds[0] = stds[1] = stds[2] = 0;
+    stds[0] = stds[1] = stds[2] = -1;
+    fds = stds;
     nice_val = 0;
     tmp_cwd = NULL;
 
@@ -2029,6 +2038,8 @@ void f_create_process(INT32 args)
     storage.argv=0;
     storage.disabled=0;
 
+    storage.fds = NULL;
+
 #ifdef HAVE_SETRLIMIT
     storage.limits = 0;
 #endif
@@ -2093,27 +2104,47 @@ void f_create_process(INT32 args)
          tmp->type == T_STRING && !tmp->u.string->size_shift)
         tmp_cwd = tmp->u.string->str;
 
+      if ((tmp = simple_mapping_string_lookup( optional, "fds" )) &&
+	  tmp->type == T_ARRAY) {
+	struct array *a = tmp->u.array;
+	int i = a->size;
+	if (i) {
+	  /* Don't forget stdin, stdout, and stderr */
+	  num_fds = i+3;
+	  storage.fds = fds = (int *)xalloc(sizeof(int)*(num_fds));
+	  fds[0] = fds[1] = fds[2] = -1;
+	  while (i--) {
+	    if (a->item[i].type == T_OBJECT) {
+	      fds[i+3] = fd_from_object(a->item[i].u.object);
+	      /* FIXME: Error if -1? */
+	    } else {
+	      fds[i+3] = -1;
+	    }
+	  }
+	}
+      }
+
       if((tmp = simple_mapping_string_lookup( optional, "stdin" )) &&
          tmp->type == T_OBJECT)
       {
-        stds[0] = fd_from_object( tmp->u.object );
-        if(stds[0] == -1)
+        fds[0] = fd_from_object( tmp->u.object );
+        if(fds[0] == -1)
           error("Invalid stdin file\n");
       }
 
       if((tmp = simple_mapping_string_lookup( optional, "stdout" )) &&
 	 tmp->type == T_OBJECT)
       {
-        stds[1] = fd_from_object( tmp->u.object );
-        if(stds[1] == -1)
+        fds[1] = fd_from_object( tmp->u.object );
+        if(fds[1] == -1)
           error("Invalid stdout file\n");
       }
 
       if((tmp = simple_mapping_string_lookup( optional, "stderr" )) &&
 	 tmp->type == T_OBJECT)
       {
-        stds[2] = fd_from_object( tmp->u.object );
-        if(stds[2] == -1)
+        fds[2] = fd_from_object( tmp->u.object );
+        if(fds[2] == -1)
           error("Invalid stderr file\n");
       }
 
@@ -2489,6 +2520,10 @@ void f_create_process(INT32 args)
 	  error("Process.create_process(): chdir() failed. errno:%d\n",
 		buf[1]);
 	  break;
+	case PROCE_DUP:
+	  error("Process.create_process(): dup() failed. errno:%d\n",
+		buf[1]);
+	  break;
 	case PROCE_DUP2:
 	  error("Process.create_process(): dup2() failed. errno:%d\n",
 		buf[1]);
@@ -2624,18 +2659,40 @@ void f_create_process(INT32 args)
       }
 #endif
 
+      /* Perform fd remapping */
       {
         int fd;
-        for(fd=0; fd<3; fd++)
-        {
-          if(stds[fd])
-            if(dup2(stds[fd], fd) < 0)
-              PROCERROR(PROCE_DUP2, fd);
-        }
-/* Why? (Per) Because people might want to be able to close them! /Hubbe */
-	for(fd=0; fd<3; fd++)
-	  if(stds[fd] && stds[fd]>2)
-	    close( stds[fd] );
+	/* Note: This is O(n�), but that ought to be ok. */
+	for (fd=0; fd<num_fds; fd++) {
+	  int fd2;
+	  int remapped = -1;
+	  if ((fds[fd] == -1) ||
+	      (fds[fd] == fd)) continue;
+	  for (fd2 = fd+1; fd2 < num_fds; fd2++) {
+	    if (fds[fd2] == fd) {
+	      /* We need to temorarily remap this fd, since it's in the way */
+	      if (remapped == -1) {
+		if ((remapped = dup(fd)) < 0)
+		  PROCERROR(PROCE_DUP, fd);
+	      }
+	      fds[fd2] = remapped;
+	    }
+	  }
+	  if (dup2(fds[fd], fd) < 0)
+	    PROCERROR(PROCE_DUP2, fd);
+	}
+	/* Close the source fds. */
+	for (fd=0; fd<num_fds; fd++) {
+	  /* FIXME: Should it be a comparison against -1 instead? */
+	  /* Always keep stdin, stdout & stderr. */
+	  if (fds[fd] > 2) {
+	    if ((fds[fd] >= num_fds) ||
+		(fds[fds[fd]] == -1)) {
+	      close(fds[fd]);
+	    }
+	  }
+	}
+	/* FIXME: Map the fds as not close on exec? */
       }
 
       if(priority)