summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2018-11-07 12:37:05 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2018-11-10 10:45:13 +0000
commit434c34bd8e3fe5b5dd951c74aef3f0b71d0e08c2 (patch)
tree72a5f192501f698983cfb071930545e9efa49afb /sysdeps
parent1626a1cfcd6ba1cc64721be1036c2873211d499b (diff)
downloadglibc-434c34bd8e3fe5b5dd951c74aef3f0b71d0e08c2.tar.gz
glibc-434c34bd8e3fe5b5dd951c74aef3f0b71d0e08c2.tar.xz
glibc-434c34bd8e3fe5b5dd951c74aef3f0b71d0e08c2.zip
Hurd: Implement chdir support in posix_spawn
This fixes build-many-glibcs.py on i686-gnu.

Thanks Florian Weimer for the initial version.

* sysdeps/mach/hurd/spawni.c (__spawni): Add ccwdir port. Test and use
it, free it if needed.
(reauthenticate): Test and use ccwdir.
(child_init_port): In non-resetids case, test and use ccwdir.
(child_chdir): New nested function to set ccwdir.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/mach/hurd/spawni.c87
1 files changed, 77 insertions, 10 deletions
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 9351c13e56..4fd0cdd520 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -113,6 +113,9 @@ __spawni (pid_t *pid, const char *file,
   struct hurd_userlink *ulink_dtable = NULL;
   struct hurd_sigstate *ss;
 
+  /* Child current working dir */
+  file_t ccwdir = MACH_PORT_NULL;
+
   /* For POSIX_SPAWN_RESETIDS, this reauthenticates our root/current
      directory ports with the new AUTH port.  */
   file_t rcrdir = MACH_PORT_NULL, rcwdir = MACH_PORT_NULL;
@@ -123,16 +126,25 @@ __spawni (pid_t *pid, const char *file,
       if (*result != MACH_PORT_NULL)
 	return 0;
       ref = __mach_reply_port ();
-      err = HURD_PORT_USE
-	(&_hurd_ports[which],
-	 ({
-	   err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
-	   if (!err)
-	     err = __auth_user_authenticate (auth,
-					     ref, MACH_MSG_TYPE_MAKE_SEND,
-					     result);
-	   err;
-	 }));
+      if (which == INIT_PORT_CWDIR && ccwdir != MACH_PORT_NULL)
+	{
+	  err = __io_reauthenticate (ccwdir, ref, MACH_MSG_TYPE_MAKE_SEND);
+	  if (!err)
+	    err = __auth_user_authenticate (auth,
+					    ref, MACH_MSG_TYPE_MAKE_SEND,
+					    result);
+	}
+      else
+	err = HURD_PORT_USE
+	  (&_hurd_ports[which],
+	   ({
+	     err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
+	     if (!err)
+	       err = __auth_user_authenticate (auth,
+					       ref, MACH_MSG_TYPE_MAKE_SEND,
+					       result);
+	     err;
+	   }));
       __mach_port_destroy (__mach_task_self (), ref);
       return err;
     }
@@ -177,6 +189,14 @@ __spawni (pid_t *pid, const char *file,
 	    return (reauthenticate (INIT_PORT_CWDIR, &rcwdir)
 		    ?: (*operate) (rcwdir));
 	  }
+      else
+	switch (which)
+	  {
+	  case INIT_PORT_CWDIR:
+	    if (ccwdir != MACH_PORT_NULL)
+	      return (*operate) (ccwdir);
+	    break;
+	  }
       assert (which != INIT_PORT_PROC);
       return _hurd_ports_use (which, operate);
     }
@@ -205,6 +225,40 @@ __spawni (pid_t *pid, const char *file,
       return __hurd_file_name_lookup (&child_init_port, &child_fd, 0,
 				      file, oflag, mode, result);
     }
+  auto error_t child_chdir (const char *name)
+    {
+      file_t new_ccwdir;
+
+      /* Append trailing "/." to directory name to force ENOTDIR if
+	 it's not a directory and EACCES if we don't have search
+	 permission.  */
+      len = strlen (name);
+      const char *lookup = name;
+      if (len >= 2 && name[len - 2] == '/' && name[len - 1] == '.')
+	lookup = name;
+      else if (len == 0)
+	/* Special-case empty file name according to POSIX.  */
+	return __hurd_fail (ENOENT);
+      else
+	{
+	  char *n = alloca (len + 3);
+	  memcpy (n, name, len);
+	  n[len] = '/';
+	  n[len + 1] = '.';
+	  n[len + 2] = '\0';
+	  lookup = n;
+	}
+
+      error_t err = child_lookup (lookup, 0, 0, &new_ccwdir);
+      if (!err)
+	{
+	  if (ccwdir != MACH_PORT_NULL)
+	    __mach_port_deallocate (__mach_task_self (), ccwdir);
+	  ccwdir = new_ccwdir;
+	}
+
+      return err;
+    }
 
 
   /* Do this once.  */
@@ -485,6 +539,10 @@ __spawni (pid_t *pid, const char *file,
 	      dtable_cells[fd] = NULL;
 	      break;
 	    }
+
+	  case spawn_do_chdir:
+	    err = child_chdir (action->action.chdir_action.path);
+	    break;
 	  }
 
 	if (err)
@@ -708,6 +766,11 @@ __spawni (pid_t *pid, const char *file,
 		ports[i] = rcwdir;
 		continue;
 	      }
+	    if (ccwdir != MACH_PORT_NULL)
+	      {
+		ports[i] = ccwdir;
+		continue;
+	      }
 	    break;
 	  }
 	ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
@@ -748,6 +811,8 @@ __spawni (pid_t *pid, const char *file,
 	  case INIT_PORT_CWDIR:
 	    if (flags & POSIX_SPAWN_RESETIDS)
 	      continue;
+	    if (ccwdir != MACH_PORT_NULL)
+	      continue;
 	    break;
 	  }
 	_hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
@@ -773,6 +838,8 @@ __spawni (pid_t *pid, const char *file,
     }
   __mach_port_deallocate (__mach_task_self (), auth);
   __mach_port_deallocate (__mach_task_self (), proc);
+  if (ccwdir != MACH_PORT_NULL)
+    __mach_port_deallocate (__mach_task_self (), ccwdir);
   if (rcrdir != MACH_PORT_NULL)
     __mach_port_deallocate (__mach_task_self (), rcrdir);
   if (rcwdir != MACH_PORT_NULL)