This patch implements "magic" lookup for "pid/…", as used when looking up
/proc/self.

The patch comes from the 't/magic-pid' branch
at <https://git.savannah.gnu.org/cgit/hurd/glibc.git>.  It squashes
commit 392e52286a302ca6157fbd221295e64ab6b6d8ba (by Justus Winter)
and commit 392e52286a302ca6157fbd221295e64ab6b6d8ba (a subsequent fix by
Samuel Thibault).

From: Justus Winter <4winter@informatik.uni-hamburg.de>
Subject: [PATCH] hurd: Handle `pid' magical lookup retry

        * hurd/lookup-retry.c: Handle `pid' magical lookup
        retry.

diff --git a/hurd/lookup-retry.c b/hurd/lookup-retry.c
index aee2ba8f93..6ed8de1653 100644
--- a/hurd/lookup-retry.c
+++ b/hurd/lookup-retry.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <_itoa.h>
 #include <eloop-threshold.h>
+#include <unistd.h>
 
 /* Translate the error from dir_lookup into the error the user sees.  */
 static inline error_t
@@ -59,6 +60,7 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
   error_t err;
   char *file_name;
   int nloops;
+  file_t lastdir = MACH_PORT_NULL;
 
   error_t lookup_op (file_t startdir)
     {
@@ -107,14 +109,15 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 	{
 	case FS_RETRY_REAUTH:
 	  if (err = reauthenticate (*result))
-	    return err;
+	    goto out;
 	  /* Fall through.  */
 
 	case FS_RETRY_NORMAL:
 	  if (nloops++ >= __eloop_threshold ())
 	    {
 	      __mach_port_deallocate (__mach_task_self (), *result);
-	      return ELOOP;
+	      err = ELOOP;
+	      goto out;
 	    }
 
 	  /* An empty RETRYNAME indicates we have the final port.  */
@@ -174,7 +177,7 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 
 	      if (err)
 		__mach_port_deallocate (__mach_task_self (), *result);
-	      return err;
+	      goto out;
 	    }
 
 	  startdir = *result;
@@ -189,7 +192,10 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 	      if (*result != MACH_PORT_NULL)
 		__mach_port_deallocate (__mach_task_self (), *result);
 	      if (nloops++ >= __eloop_threshold ())
-		return ELOOP;
+		{
+		  err = ELOOP;
+		  goto out;
+		}
 	      file_name = &retryname[1];
 	      break;
 
@@ -208,7 +214,8 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		      (*end != '/' && *end != '\0'))
 		    {
 		      errno = save;
-		      return ENOENT;
+		      err = ENOENT;
+		      goto out;
 		    }
 		  if (! get_dtable_port)
 		    err = EGRATUITOUS;
@@ -226,9 +233,12 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		    }
 		  errno = save;
 		  if (err)
-		    return err;
+		    goto out;
 		  if (*end == '\0')
-		    return 0;
+		    {
+		      err = 0;
+		      goto out;
+		    }
 		  else
 		    {
 		      /* Do a normal retry on the remaining components.  */
@@ -255,9 +265,12 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		  if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
 					 (integer_t *) &hostinfo,
 					 &hostinfocnt))
-		    return err;
+		    goto out;
 		  if (hostinfocnt != HOST_BASIC_INFO_COUNT)
-		    return EGRATUITOUS;
+		    {
+		      err = EGRATUITOUS;
+		      goto out;
+		    }
 		  p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
 		  *--p = '/';
 		  p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
@@ -293,10 +306,11 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		      }
 
 		  case '\0':
-		    return opentty (result);
+		    err = opentty (result);
+		    goto out;
 		  case '/':
 		    if (err = opentty (&startdir))
-		      return err;
+		      goto out;
 		    strcpy (retryname, &retryname[4]);
 		    break;
 		  default:
@@ -306,14 +320,48 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		goto bad_magic;
 	      break;
 
+	    case 'p':
+	      if (retryname[1] == 'i' && retryname[2] == 'd' &&
+		  (retryname[3] == '/' || retryname[3] == 0))
+		{
+		  char *p, buf[1024];  /* XXX */
+		  size_t len;
+		  p = _itoa (__getpid (), &buf[sizeof buf], 10, 0);
+		  len = &buf[sizeof buf] - p;
+		  memcpy (buf, p, len);
+		  strcpy (buf + len, &retryname[3]);
+		  strcpy (retryname, buf);
+
+		  /* Do a normal retry on the remaining components.  */
+		  __mach_port_mod_refs (__mach_task_self (), lastdir,
+					MACH_PORT_RIGHT_SEND, 1);
+		  startdir = lastdir;
+		  file_name = retryname;
+		}
+	      else
+		goto bad_magic;
+	      break;
+
 	    default:
 	    bad_magic:
-	      return EGRATUITOUS;
+	      err = EGRATUITOUS;
+	      goto out;
 	    }
 	  break;
 
 	default:
-	  return EGRATUITOUS;
+	  err = EGRATUITOUS;
+	  goto out;
+	}
+
+      if (MACH_PORT_VALID (*result) && *result != lastdir)
+	{
+	  if (MACH_PORT_VALID (lastdir))
+	    __mach_port_deallocate (__mach_task_self (), lastdir);
+
+	  lastdir = *result;
+	  __mach_port_mod_refs (__mach_task_self (), lastdir,
+				MACH_PORT_RIGHT_SEND, 1);
 	}
 
       if (startdir != MACH_PORT_NULL)
@@ -326,6 +374,10 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 	err = (*use_init_port) (dirport, &lookup_op);
     } while (! err);
 
+out:
+  if (MACH_PORT_VALID (lastdir))
+    __mach_port_deallocate (__mach_task_self (), lastdir);
+
   return err;
 }
 weak_alias (__hurd_file_name_lookup_retry, hurd_file_name_lookup_retry)
