Mail Archives: cygwin-developers/1999/01/21/14:25:24
Thanks for noticing these inconsistencies and for the patch. Your
patch didn't quite do it for me. This one below did, however.
This is against the last snapshot. Sorry but I forgot to save
my previous version before making this change.
This should incorporate the majority of your changes, however.
-chris
On Thu, Jan 21, 1999 at 07:18:42PM +0900, Kazuhiro Fujieda wrote:
>>>> On Wed, 20 Jan 1999 14:46:59 -0500
>>>> Christopher Faylor <cgf AT cygnus DOT com> said:
>
>> 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.
>(snip)
>
>There is a bug in this patch. The argument parser can't convert
>arguments rightly. For example, it convert `foo "bar" foo' to
>`"foo """bar" foo"'. This should be `"foo ""bar"" foo"'.
>
>Then, It should check not only ' ' but also '\n', '\r' and '\t'
>in order to be consistent with build_argv() in dcrt0.cc.
>[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/21 22:10:42
@@ -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,43 @@ 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, " \t\n\r\"")))
+ 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, '"'))
+ {
+ one_line.add (a, ++p - a);
+ if (p[-1] == '"')
+ one_line.add ("\"", 1);
+ }
+ if (*a)
+ one_line.add (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 +461,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 +483,6 @@ skip_arg_parsing:
flags |= DETACHED_PROCESS;
}
- sig_protect (starting_here, 0);
-
/* Build windows style environment list */
char *envblock = winenv (envp);
@@ -521,7 +508,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 +520,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 +544,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 -