delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin-developers/1999/01/20/11:54:54

From: cgf AT cygnus DOT com (Christopher Faylor)
Subject: Re: relative path script
20 Jan 1999 11:54:54 -0800 :
Message-ID: <19990120144659.A13057.cygnus.cygwin32.developers@cygnus.com>
References: <ubtjx80o1 DOT fsf AT parvati DOT will DOT or DOT jp>
Mime-Version: 1.0
To: Kazuhiro Fujieda <fujieda AT jaist DOT ac DOT jp>, cygwin32-developers AT cygnus DOT com

I've actually been checking this out in my spare time.  I've
rewritten the section of code that deals with this.  It's a major
change, so I could have broken something, but here it is.

If this breaks things for people then I'll just check in Kazuhiro's
change while I play with my changes.

I'd appreciate it if people could check this out.

-chris

On Wed, Jan 20, 1999 at 01:20:33PM +0900, Kazuhiro Fujieda wrote:
>>>> On 18 Jan 1999 17:06:54 +0900
>>>> Kazuhiro Fujieda <fujieda AT jaist DOT ac DOT jp> said:
>
>> For example,
>> $ echo '#!/bin/sh' > foo
>> $ mkdir bar
>> $ cd bar
>> $ ../foo
>> ../../foo: Can't open ../../foo
>(snip)
>
>The following patch fixes this problem.  Either script found
>through a relative search path or directly specified by a
>relative path works fine.
>[snip]

Index: spawn.cc
===================================================================
RCS file: /cvs/cvsfiles/devo/winsup/spawn.cc,v
retrieving revision 1.99
diff -u -p -r1.99 spawn.cc
--- spawn.cc	1999/01/17 06:08:43	1.99
+++ spawn.cc	1999/01/20 19:41:20
@@ -167,12 +167,56 @@ iscmd (const char *argv0, const char *wh
 	 (n == 0 || isdirsep (argv0[n - 1]));
 }
 
+class linebuf
+{
+  size_t alloc;
+public:
+  size_t ix;
+  char *buf;
+  linebuf ()
+  {
+    ix = 0;
+    alloc = 0;
+    buf = NULL;
+  }
+  ~linebuf () {if (buf) free (buf);}
+  void add (const char *what, int len);
+  void add (const char *what) {add (what, strlen (what));}
+  void prepend (const char *what, int len);
+};
+
+void
+linebuf::add (const char *what, int len)
+{
+  size_t newix;
+  if ((newix = ix + len) >= alloc)
+    {
+      alloc += MAX_PATH * 2;
+      buf = (char *) realloc (buf, alloc + 1);
+    }
+  memcpy (buf + ix, what, len);
+  ix = newix;
+}
+
+void
+linebuf::prepend (const char *what, int len)
+{
+  size_t newix;
+  if ((newix = ix + len) >= alloc)
+    {
+      alloc += MAX_PATH * 2;
+      buf = (char *) realloc (buf, alloc + 1);
+    }
+  memmove (buf + len, buf, strlen (buf));
+  memcpy (buf, what, len);
+  ix += len;
+}
+
 int
 spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
 	    const char *const envp[], pinfo *child, int mode)
 {
   int i;
-  char *copy;
   BOOL rc;
   int argc;
 
@@ -196,36 +240,23 @@ spawn_guts (HANDLE hToken, const char * 
 
   /* CreateProcess takes one long string that is the command line (sigh).
      We need to quote any argument that has whitespace or embedded "'s.  */
-    int clen, last_clen;
 
   for (argc = 0; argv[argc]; argc++)
-debug_printf ("argv[%d] = '%s'", argc, argv[argc]);
     /* nothing */;
 
-  /* See how much space we need.  Note that "'s are doubled. */
-  clen = 0;
-  if (argc == 0)
-    {
-      /* Hmm - nasty - no prog name, - fill one up for us */
-      /* FIXME: what about argv[1]??? */
-      small_printf ("spawn_guts: NO ARG0");
-      char **tmp;
-      tmp = (char **) &argv[0];
-      *tmp = (char *) prog_arg;
-    }
-
   char *real_path;
   char real_path_buf[MAX_PATH];
+
+  sig_protect (starting_here, 0);
+  linebuf one_line;
+
   if (argc == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
       (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
     {
-      copy = (char *) alloca (strlen (argv[0]) + strlen (argv[1]) +
-			      strlen (argv[2]) + 3);
-      strcpy (copy, argv[0]);
-      strcat (copy, " ");
-      strcat (copy, argv[1]);
-      strcat (copy, " ");
-      strcat (copy, argv[2]);
+      one_line.add (argv[0]);
+      one_line.add (" ");
+      one_line.add (argv[1]);
+      one_line.add (" ");
       real_path = NULL;
       strcpy (real_path_buf, argv[0]);
       goto skip_arg_parsing;
@@ -233,83 +264,21 @@ debug_printf ("argv[%d] = '%s'", argc, a
 
   real_path = real_path_buf;
 
-  for (argc = 0; argv[argc]; argc++)
-    {
-      int needquote = 0;
-      const char *str;
-      /* Zero length args need quotes. */
-      if (!argv[argc][0])
-	needquote = 1;
-
-      for (str = argv[argc]; *str; str++)
-	{
-	  if (*str == '"')
-	    clen++;
-	  if (issep (*str) || *str == '"')
-	    needquote = 1;
-	  clen++;
-	}
-      if (needquote)
-	clen += 2;		/* space for quotes */
-      clen++;			/* space for separating space */
-    }
-
-  if ((copy = (char *) alloca (clen + 1)) == NULL)
-    {
-      syscall_printf ("couldn't allocate %d characters", clen + 1);
-      set_errno (ENAMETOOLONG);
-      return -1;
-    }
-  syscall_printf ("total arg length %d, copy %p", clen, copy);
-  last_clen = clen + 1;
-  clen = 0;
-
-  for (i = 0, argc--; i <= argc; i++)
-    {
-      int needquote = 0;
-      const char *str;
-
-      /* Extra space after `in' intentional. */
-      syscall_printf ("argv[%d] in  `%s'", i, argv[i]);
-
-      if (!argv[i][0])
-	needquote = 1;
-
-      for (str = argv[i]; *str; str++)
-	if (issep (*str) || *str == '"')
-	  needquote = 1;
-
-      if (needquote)
-	copy[clen++] = '"';
-
-      for (str = argv[i]; *str; str++)
-	{
-	  if (*str=='"')
-	    copy[clen++] = '"';
-	  copy[clen++] = *str;
-	}
-
-      if (needquote)
-	copy[clen++] = '"';
-      copy[clen++] = (i == argc) ? '\0' : ' ';
-      syscall_printf ("argv[%d] out`%s'", i, argv[i]);
-    }
-  if (clen > last_clen)
-    system_printf ("Hey! clen %d, last_clen %d", clen, last_clen);
-
   const char *saved_prog_arg;
+  const char *newargv0, **firstarg;
   const char *ext;
 
-  saved_prog_arg = prog_arg;
   if ((ext = perhaps_suffix (prog_arg, real_path)) == NULL)
     {
       set_errno (ENOENT);
       return -1;
     }
 
-  /* Check if it's a script.  */
+  saved_prog_arg = prog_arg;
+  newargv0 = argv[0];
+  firstarg = &newargv0;
 
-  /* if the file name ends in either .exe, .com, .bat, or .cmd we assume
+  /* If the file name ends in either .exe, .com, .bat, or .cmd we assume
      that it is NOT a script file */
   while (*ext == '\0')
     {
@@ -355,46 +324,42 @@ debug_printf ("argv[%d] = '%s'", argc, a
       else
 	{
 	  pgm = buf + 2;
-	  pgm += strspn(pgm, " \t");
+	  pgm += strspn (pgm, " \t");
 	  for (ptr = pgm, arg1 = NULL;
 	       *ptr && *ptr != '\r' && *ptr != '\n';
 	       ptr++)
 	    if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
 	      {
-		*ptr = '\0';
-		do
-		  arg1 = ++ptr;
-		while (*ptr && (*ptr == ' ' || *ptr == '\t'));
-		ptr--;
+		arg1 = ptr;
+		*arg1++ = '\0';
+		ptr = (arg1 += strspn (arg1, " \t"));
 	      }
 
 	
 	  *ptr = '\0';
-	  if (arg1 == NULL)
-	    arg1 = ptr;
 	}
 
-      char prog_arg1[MAX_PATH];
+      char buf2[MAX_PATH + 1];
 
       /* pointers:
        * pgm	interpreter name
        * arg1	optional string
        * ptr	end of string
        */ 
-      find_exec (pgm, (char *) real_path, "PATH=", 0, &ext);
-      cygwin_conv_to_posix_path (real_path, prog_arg1);
-      char *f = (char *) alloca (strlen (copy) + strlen (prog_arg1) +
-				 (ptr - arg1) + 8 + strlen (saved_prog_arg));
-      strcpy (f, prog_arg1);
-      if (ptr == arg1)
-	strcat (f, " ");
+
+      if (!arg1)
+	one_line.prepend (" ", 1);
       else
 	{
-	  strcat (f, " \"");
-	  strcat (f, arg1);
-	  strcat (f, "\" ");
+	  one_line.prepend ("\" ", 1);
+	  one_line.prepend (arg1, strlen (arg1));
+	  one_line.prepend (" \"", 2);
 	}
 
+      find_exec (pgm, real_path, "PATH=", 0, &ext);
+      cygwin_conv_to_posix_path (real_path, buf2);
+      one_line.prepend (buf2, strlen (buf2));
+
       /* If script had absolute path, add it to script name now!
        * This is necessary if script has been found via PATH.
        * For example, /usr/local/bin/tkman started as "tkman":
@@ -404,19 +369,44 @@ debug_printf ("argv[%d] = '%s'", argc, a
        * but not /usr/local/bin/wish -f tkman!
        * We don't modify anything, if script has qulified path.
        */
-      if (strpbrk (saved_prog_arg, "\\/") && !isabspath (copy))
+      if (firstarg)
+	*firstarg = saved_prog_arg;
+
+      debug_printf ("prog_arg '%s', copy '%s'", prog_arg, one_line.buf);
+      firstarg = NULL;
+    }
+  
+  for (; *argv; argv++)
+    {
+      char *p = NULL;
+      const char *a = newargv0 ?: *argv;
+
+      newargv0 = NULL;
+      int len = strlen (a);
+      if (len != 0 && !(p = strpbrk (a, " \"")))
+	one_line.add (a, len);
+      else
 	{
-	  debug_printf ("getting path of %s, copy %s", saved_prog_arg, buf);
-	  cygwin_split_path (saved_prog_arg, strchr(f, '\0'), buf);
-	  strcat (f, "/");
+	  one_line.add ("\"", 1);
+	  for (; p; a = p, p = strchr (p, '"'))
+	    {
+	      if (*p++ == '"')
+		one_line.add ("\"", 1);
+	      one_line.add (a, p - a);
+	      a = p;
+	    }
+	  if (*a)
+	    one_line.add (a, strlen (a));
+	  one_line.add ("\"", 1);
 	}
-
-      strcat (f, copy);
-      copy = f;
-
-      debug_printf ("prog_arg '%s', copy '%s'", prog_arg, copy);
+      one_line.add (" ", 1);
     }
 
+  if (one_line.ix)
+    one_line.buf[one_line.ix - 1] = '\0';
+  else
+    one_line.add ("", 1);
+
 skip_arg_parsing:
   PROCESS_INFORMATION pi = {0};
 
@@ -472,7 +462,7 @@ skip_arg_parsing:
 
   /* We print the translated program and arguments here so the user can see
      what was done to it.  */
-  syscall_printf ("spawn_guts (%s, %.132s)", real_path, copy);
+  syscall_printf ("spawn_guts (%s, %.132s)", real_path, one_line.buf);
 
   int flags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED |
 	      GetPriorityClass (GetCurrentProcess ());
@@ -494,8 +484,6 @@ skip_arg_parsing:
 	flags |= DETACHED_PROCESS;
     }
 
-  sig_protect (starting_here, 0);
-
   /* Build windows style environment list */
   char *envblock = winenv (envp);
 
@@ -521,7 +509,7 @@ skip_arg_parsing:
       myself->uid = USHRT_MAX;
       rc = CreateProcessAsUser (hToken,
 		       real_path,	/* image name - with full path */
-		       copy,	/* what was passed to exec */
+		       one_line.buf,	/* what was passed to exec */
 		       &sec_all_nih,	/* process security attrs */
 		       &sec_all_nih,	/* thread security attrs */
 		       TRUE,	/* inherit handles from parent */
@@ -533,7 +521,7 @@ skip_arg_parsing:
     }
   else
     rc = CreateProcessA (real_path,	/* image name - with full path */
-		       copy,	/* what was passed to exec */
+		       one_line.buf,	/* what was passed to exec */
 		       &sec_all_nih,	/* process security attrs */
 		       &sec_all_nih,	/* thread security attrs */
 		       TRUE,	/* inherit handles from parent */
@@ -557,7 +545,7 @@ skip_arg_parsing:
   /* We print the original program name here so the user can see that too.  */
   syscall_printf ("%d = spawn_guts (%s, %.132s)",
 		  rc ? pi.dwProcessId : (unsigned int) -1,
-		  prog_arg, copy);
+		  prog_arg, one_line.buf);
 
   if (!rc)
     {

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019