From e00c55d7a0204dc1d0ae316141323959e1e16162 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 24 Oct 2016 23:52:23 +0900 Subject: [PATCH] main: quote output file name before passing it to system(3) function Following command line doesn't work: $ ctags -o 'a b' ... because a shell lauched from system(3) deals a whitespace between 'a' and 'b' as a separator. The output file name is passed to system(3) to run external sort command. This commit adds code to put double and single quoets around the output file name before passing it to system(3). The issue is reported by Lorenz Hipp in a private mail. Signed-off-by: Masatake YAMATO --- Tmain/abnormal-output-file-names.d/input.c | 1 + Tmain/abnormal-output-file-names.d/run.sh | 39 ++++++++++ .../stderr-expected.txt | 0 .../stdout-expected.txt | 8 +++ main/sort.c | 72 ++++++++++++++----- 5 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 Tmain/abnormal-output-file-names.d/input.c create mode 100644 Tmain/abnormal-output-file-names.d/run.sh create mode 100644 Tmain/abnormal-output-file-names.d/stderr-expected.txt create mode 100644 Tmain/abnormal-output-file-names.d/stdout-expected.txt diff --git a/Tmain/abnormal-output-file-names.d/input.c b/Tmain/abnormal-output-file-names.d/input.c new file mode 100644 index 0000000000..6d1a0d47b7 --- /dev/null +++ b/Tmain/abnormal-output-file-names.d/input.c @@ -0,0 +1 @@ +int x; diff --git a/Tmain/abnormal-output-file-names.d/run.sh b/Tmain/abnormal-output-file-names.d/run.sh new file mode 100644 index 0000000000..b15a766c1a --- /dev/null +++ b/Tmain/abnormal-output-file-names.d/run.sh @@ -0,0 +1,39 @@ +# Copyright: 2016 Masatake YAMATO +# License: GPL-2 + +CTAGS=$1 + +rm -f ./"'" +rm -f ./'"' +rm -f ./'$(ls)' +rm -f ./'a b' + +${CTAGS} --quiet --options=NONE -o ./"'" --extra=-pF input.c +${CTAGS} --quiet --options=NONE -o ./'"' --extra=-pF input.c +${CTAGS} --quiet --options=NONE -o ./'$(ls)' --extra=-pF input.c +${CTAGS} --quiet --options=NONE -o ./'a b' --extra=-pF input.c + +echo '#' SINGLE QUOTE +if [ -e "'" ]; then + cat "'" +fi + +echo '#' DOUBLE QUOTES +if [ -e '"' ]; then + cat '"' +fi + +echo '#' PROCESS SUBSTITUTION +if [ -e '$(ls)' ]; then + cat '$(ls)' +fi + +echo '#' SPACE +if [ -e 'a b' ]; then + cat 'a b' +fi + +rm -f ./"'" +rm -f ./'"' +rm -f ./'$(ls)' +rm -f ./'a b' diff --git a/Tmain/abnormal-output-file-names.d/stderr-expected.txt b/Tmain/abnormal-output-file-names.d/stderr-expected.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tmain/abnormal-output-file-names.d/stdout-expected.txt b/Tmain/abnormal-output-file-names.d/stdout-expected.txt new file mode 100644 index 0000000000..5d1129ea84 --- /dev/null +++ b/Tmain/abnormal-output-file-names.d/stdout-expected.txt @@ -0,0 +1,8 @@ +# SINGLE QUOTE +x input.c /^int x;$/;" v typeref:typename:int +# DOUBLE QUOTES +x input.c /^int x;$/;" v typeref:typename:int +# PROCESS SUBSTITUTION +x input.c /^int x;$/;" v typeref:typename:int +# SPACE +x input.c /^int x;$/;" v typeref:typename:int diff --git a/main/sort.c b/main/sort.c index 7ee7ce0a23..46ffd48a3d 100644 --- a/main/sort.c +++ b/main/sort.c @@ -55,17 +55,44 @@ extern void catFile (MIO *mio) # define PE_CONST const #endif +/* + Output file name should not be evaluated in system(3) function. + The name must be used as is. Quotations are required to block the + evaluation. + + Normal single-quotes are used to quote a cstring: + a => 'a' + " => '"' + + If a single-quote is included in the cstring, use double quotes for quoting it. + ' => ''"'"'' +*/ +static void appendCstringWithQuotes (vString *dest, const char* cstr) +{ + const char* o; + + vStringPut (dest, '\''); + for (o = cstr; *o; o++) + { + if (*o == '\'') + vStringCatS (dest, "'\"'\"'"); + else + vStringPut (dest, *o); + } + vStringPut (dest, '\''); +} + extern void externalSortTags (const bool toStdout, MIO *tagFile) { const char *const sortNormalCommand = "sort -u"; const char *const sortFoldedCommand = "sort -u -f"; const char *sortCommand = Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand; +# ifndef HAVE_SETENV PE_CONST char *const sortOrder1 = "LC_COLLATE=C"; PE_CONST char *const sortOrder2 = "LC_ALL=C"; - const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) + - strlen (sortCommand) + (2 * strlen (tagFileName ())); - char *const cmd = (char *) malloc (length + 1); +# endif + vString *cmd = vStringNew (); int ret = -1; if (cmd != NULL) @@ -80,19 +107,29 @@ extern void externalSortTags (const bool toStdout, MIO *tagFile) putenv (sortOrder1); putenv (sortOrder2); # endif - if (toStdout) - sprintf (cmd, "%s", sortCommand); - else - sprintf (cmd, "%s -o %s %s", sortCommand, - tagFileName (), tagFileName ()); + vStringCatS (cmd, sortCommand); + if (! toStdout) + { + vStringCatS (cmd, " -o "); + appendCstringWithQuotes (cmd, tagFileName ()); + vStringPut (cmd, ' '); + appendCstringWithQuotes (cmd, tagFileName ()); + } #else - if (toStdout) - sprintf (cmd, "%s %s %s", sortOrder1, sortOrder2, sortCommand); - else - sprintf (cmd, "%s %s %s -o %s %s", sortOrder1, sortOrder2, - sortCommand, tagFileName (), tagFileName ()); + vStringCatS (cmd, sortOrder1); + vStringPut (cmd, ' '); + vStringCatS (cmd, sortOrder2); + vStringPut (cmd, ' '); + vStringCatS (cmd, sortCommand); + if (! toStdout) + { + vStringCats (cmd, " -o "); + appendCstringWithQuotes (cmd, tagFileName ()); + vStringPut (cmd, ' '); + appendCstringWithQuotes (cmd, tagFileName ()); + } #endif - verbose ("system (\"%s\")\n", cmd); + verbose ("system (\"%s\")\n", vStringValue (cmd)); if (toStdout) { const int fdstdin = 0; @@ -105,15 +142,14 @@ extern void externalSortTags (const bool toStdout, MIO *tagFile) error (FATAL | PERROR, "cannot redirect stdin"); if (lseek (fdstdin, 0, SEEK_SET) != 0) error (FATAL | PERROR, "cannot rewind tag file"); - ret = system (cmd); + ret = system (vStringValue (cmd)); if (dup2 (fdsave, fdstdin) < 0) error (FATAL | PERROR, "cannot restore stdin fd"); close (fdsave); } else - ret = system (cmd); - free (cmd); - + ret = system (vStringValue (cmd)); + vStringDelete (cmd); } if (ret != 0) error (FATAL | PERROR, "cannot sort tag file");