summaryrefslogtreecommitdiff
path: root/nt/cmdproxy.c
diff options
context:
space:
mode:
authorDaniel Colascione <dan.colascione@gmail.com>2011-04-26 03:44:03 -0700
committerDaniel Colascione <dan.colascione@gmail.com>2011-04-26 03:44:03 -0700
commit8f91bf934523d47a9f57919733d6093b2484e284 (patch)
tree788b096654044dcd66966c7d12a78e89610270fd /nt/cmdproxy.c
parent0c6b7b19e52ba18b5d4fd2d4b73b133a0a721603 (diff)
downloademacs-8f91bf934523d47a9f57919733d6093b2484e284.tar.gz
Improve Windows quoting robustness
Diffstat (limited to 'nt/cmdproxy.c')
-rw-r--r--nt/cmdproxy.c112
1 files changed, 88 insertions, 24 deletions
diff --git a/nt/cmdproxy.c b/nt/cmdproxy.c
index b9572570c5f..fe128fd17c4 100644
--- a/nt/cmdproxy.c
+++ b/nt/cmdproxy.c
@@ -309,6 +309,74 @@ make_absolute (const char *prog)
return NULL;
}
+/* Try to decode the given command line the way cmd would do it. On
+ success, return 1 with cmdline dequoted. Otherwise, when we've
+ found constructs only cmd can properly interpret, return 0 and
+ leave cmdline unchanged. */
+int
+try_dequote_cmdline (char* cmdline)
+{
+ /* Dequoting can only subtract characters, so the length of the
+ original command line is a bound on the amount of scratch space
+ we need. This length, in turn, is bounded by the 32k
+ CreateProces limit. */
+ char * old_pos = cmdline;
+ char * new_cmdline = alloca (strlen(cmdline));
+ char * new_pos = new_cmdline;
+ char c;
+
+ enum {
+ NORMAL,
+ AFTER_CARET,
+ INSIDE_QUOTE
+ } state = NORMAL;
+
+ while ((c = *old_pos++))
+ {
+ switch (state)
+ {
+ case NORMAL:
+ switch(c)
+ {
+ case '"':
+ *new_pos++ = c;
+ state = INSIDE_QUOTE;
+ break;
+ case '^':
+ state = AFTER_CARET;
+ break;
+ case '<': case '>':
+ case '&': case '|':
+ case '(': case ')':
+ case '%': case '!':
+ /* We saw an unquoted shell metacharacter and we don't
+ understand it. Bail out. */
+ return 0;
+ default:
+ *new_pos++ = c;
+ break;
+ }
+ break;
+ case AFTER_CARET:
+ *new_pos++ = c;
+ state = NORMAL;
+ break;
+ case INSIDE_QUOTE:
+ *new_pos++ = c;
+ if (c == '"')
+ state = NORMAL;
+
+ break;
+ }
+ }
+
+ /* We were able to dequote the entire string. Copy our scratch
+ buffer on top of the original buffer and return success. */
+ memcpy (cmdline, new_cmdline, new_pos - new_cmdline);
+ cmdline[new_pos - new_cmdline] = '\0';
+ return 1;
+}
+
/*****************************************************************/
#if 0
@@ -574,30 +642,26 @@ main (int argc, char ** argv)
execute the command directly ourself. */
if (cmdline)
{
- /* If no redirection or piping, and if program can be found, then
- run program directly. Otherwise invoke a real shell. */
-
- static char copout_chars[] = "|<>&";
-
- if (strpbrk (cmdline, copout_chars) == NULL)
- {
- const char *args;
-
- /* The program name is the first token of cmdline. Since
- filenames cannot legally contain embedded quotes, the value
- of escape_char doesn't matter. */
- args = cmdline;
- if (!get_next_token (path, &args))
- fail ("error: no program name specified.\n");
-
- canon_filename (path);
- progname = make_absolute (path);
-
- /* If we found the program, run it directly (if not found it
- might be an internal shell command, so don't fail). */
- if (progname != NULL)
- need_shell = FALSE;
- }
+ const char *args;
+
+ /* The program name is the first token of cmdline. Since
+ filenames cannot legally contain embedded quotes, the value
+ of escape_char doesn't matter. */
+ args = cmdline;
+ if (!get_next_token (path, &args))
+ fail ("error: no program name specified.\n");
+
+ canon_filename (path);
+ progname = make_absolute (path);
+
+ /* If we found the program and the rest of the command line does
+ not contain unquoted shell metacharacters, run the program
+ directly (if not found it might be an internal shell command,
+ so don't fail). */
+ if (progname != NULL && try_dequote_cmdline (cmdline))
+ need_shell = FALSE;
+ else
+ progname = NULL;
}
pass_to_shell: