Replace SYSTEMQUOTEs with Windows-specific wrapper functions.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 5 May 2014 13:07:40 +0000 (16:07 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 5 May 2014 13:07:40 +0000 (16:07 +0300)
It's easy to forget using SYSTEMQUOTEs when constructing command strings
for system() or popen(). Even if we fix all the places missing it now, it is
bound to be forgotten again in the future. Introduce wrapper functions that
do the the extra quoting for you, and get rid of SYSTEMQUOTEs in all the
callers.

We previosly used SYSTEMQUOTEs in all the hard-coded command strings, and
this doesn't change the behavior of those. But user-supplied commands, like
archive_command, restore_command, COPY TO/FROM PROGRAM calls, as well as
pgbench's \shell, will now gain an extra pair of quotes. That is desirable,
but if you have existing scripts or config files that include an extra
pair of quotes, those might need to be adjusted.

Reviewed by Amit Kapila and Tom Lane

18 files changed:
configure.in
contrib/pg_upgrade/check.c
contrib/pg_upgrade/controldata.c
contrib/pg_upgrade/exec.c
src/bin/initdb/initdb.c
src/bin/pg_ctl/pg_ctl.c
src/bin/pg_dump/pg_dumpall.c
src/bin/psql/command.c
src/include/port.h
src/interfaces/ecpg/test/pg_regress_ecpg.c
src/interfaces/libpq/Makefile
src/interfaces/libpq/bcc32.mak
src/interfaces/libpq/win32.mak
src/port/system.c [new file with mode: 0644]
src/test/isolation/isolation_main.c
src/test/regress/pg_regress.c
src/test/regress/pg_regress_main.c
src/tools/msvc/Mkvcbuild.pm

index fc9c52f83d2c792a76945712c86883883f7e67cf..52357a6bba3e48d1956733cfa7cae9c96666d03c 100644 (file)
@@ -1353,6 +1353,7 @@ if test "$PORTNAME" = "win32"; then
   AC_REPLACE_FUNCS(gettimeofday)
   AC_LIBOBJ(kill)
   AC_LIBOBJ(open)
+  AC_LIBOBJ(system)
   AC_LIBOBJ(win32env)
   AC_LIBOBJ(win32error)
   AC_LIBOBJ(win32setlocale)
index 56e912d8c3d9e775c371c8b1c9c09e06d5a1693a..d22b6d38e291da113c796833ec651ed57fbfc7fa 100644 (file)
@@ -970,7 +970,7 @@ get_bin_version(ClusterInfo *cluster)
    int         pre_dot,
                post_dot;
 
-   snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/pg_ctl\" --version" SYSTEMQUOTE, cluster->bindir);
+   snprintf(cmd, sizeof(cmd), "\"%s/pg_ctl\" --version", cluster->bindir);
 
    if ((output = popen(cmd, "r")) == NULL ||
        fgets(cmd_output, sizeof(cmd_output), output) == NULL)
index fa0a0053bab4bebfe24b1086774075ba06fcee1f..476c6be276e0efd317be6e98f30b8f42050dfb2b 100644 (file)
@@ -110,7 +110,7 @@ get_control_data(ClusterInfo *cluster, bool live_check)
    pg_putenv("LC_ALL", NULL);
    pg_putenv("LC_MESSAGES", "C");
 
-   snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/%s \"%s\"" SYSTEMQUOTE,
+   snprintf(cmd, sizeof(cmd), "\"%s/%s \"%s\"",
             cluster->bindir,
             live_check ? "pg_controldata\"" : "pg_resetxlog\" -n",
             cluster->pgdata);
index 7f013013a0653f9373b0be9fa665cd43cfc1a8a3..91e66e6ecf465766ef88558754d3989384d4aeae 100644 (file)
@@ -59,14 +59,14 @@ static DWORD       mainThreadId = 0;
        mainThreadId = GetCurrentThreadId();
 #endif
 
-   written = strlcpy(cmd, SYSTEMQUOTE, sizeof(cmd));
+   written = 0;
    va_start(ap, fmt);
    written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap);
    va_end(ap);
    if (written >= MAXCMDLEN)
        pg_fatal("command too long\n");
    written += snprintf(cmd + written, MAXCMDLEN - written,
-                       " >> \"%s\" 2>&1" SYSTEMQUOTE, log_file);
+                       " >> \"%s\" 2>&1", log_file);
    if (written >= MAXCMDLEN)
        pg_fatal("command too long\n");
 
index b53fa8bd088e6480625e26418ea686694c73a6f3..83b7f6e24d872ae8e796b3636f8a210c50f793c8 100644 (file)
@@ -1130,11 +1130,11 @@ test_config_settings(void)
        test_buffs = MIN_BUFS_FOR_CONNS(test_conns);
 
        snprintf(cmd, sizeof(cmd),
-                SYSTEMQUOTE "\"%s\" --boot -x0 %s "
+                "\"%s\" --boot -x0 %s "
                 "-c max_connections=%d "
                 "-c shared_buffers=%d "
                 "-c dynamic_shared_memory_type=none "
-                "< \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
+                "< \"%s\" > \"%s\" 2>&1",
                 backend_exec, boot_options,
                 test_conns, test_buffs,
                 DEVNULL, DEVNULL);
@@ -1165,11 +1165,11 @@ test_config_settings(void)
        }
 
        snprintf(cmd, sizeof(cmd),
-                SYSTEMQUOTE "\"%s\" --boot -x0 %s "
+                "\"%s\" --boot -x0 %s "
                 "-c max_connections=%d "
                 "-c shared_buffers=%d "
                 "-c dynamic_shared_memory_type=none "
-                "< \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
+                "< \"%s\" > \"%s\" 2>&1",
                 backend_exec, boot_options,
                 n_connections, test_buffs,
                 DEVNULL, DEVNULL);
@@ -1503,7 +1503,7 @@ bootstrap_template1(void)
    unsetenv("PGCLIENTENCODING");
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" --boot -x1 %s %s %s" SYSTEMQUOTE,
+            "\"%s\" --boot -x1 %s %s %s",
             backend_exec,
             data_checksums ? "-k" : "",
             boot_options, talkargs);
@@ -1544,7 +1544,7 @@ setup_auth(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -1622,7 +1622,7 @@ get_set_pwd(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -1722,7 +1722,7 @@ setup_depend(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -1755,7 +1755,7 @@ setup_sysviews(void)
     * We use -j here to avoid backslashing stuff in system_views.sql
     */
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s -j template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s -j template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -1786,7 +1786,7 @@ setup_description(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -1893,7 +1893,7 @@ setup_collation(void)
 
 #if defined(HAVE_LOCALE_T) && !defined(WIN32)
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2038,7 +2038,7 @@ setup_conversion(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2076,7 +2076,7 @@ setup_dictionary(void)
     * We use -j here to avoid backslashing stuff
     */
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s -j template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s -j template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2127,7 +2127,7 @@ setup_privileges(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2190,7 +2190,7 @@ setup_schema(void)
     * We use -j here to avoid backslashing stuff in information_schema.sql
     */
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s -j template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s -j template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2207,7 +2207,7 @@ setup_schema(void)
    PG_CMD_CLOSE;
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2241,7 +2241,7 @@ load_plpgsql(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2266,7 +2266,7 @@ vacuum_db(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2322,7 +2322,7 @@ make_template0(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
@@ -2354,7 +2354,7 @@ make_postgres(void)
    fflush(stdout);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" %s template1 >%s" SYSTEMQUOTE,
+            "\"%s\" %s template1 >%s",
             backend_exec, backend_options,
             DEVNULL);
 
index fc87e7d76ed166af23cf83fa91991211605af409..473d6534064c69ad74cbea480de6415040369d56 100644 (file)
@@ -435,11 +435,11 @@ start_postmaster(void)
     * the PID without having to rely on reading it back from the pidfile.
     */
    if (log_file != NULL)
-       snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &" SYSTEMQUOTE,
+       snprintf(cmd, MAXPGPATH, "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &",
                 exec_path, pgdata_opt, post_opts,
                 DEVNULL, log_file);
    else
-       snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1 &" SYSTEMQUOTE,
+       snprintf(cmd, MAXPGPATH, "\"%s\" %s%s < \"%s\" 2>&1 &",
                 exec_path, pgdata_opt, post_opts, DEVNULL);
 
    return system(cmd);
@@ -453,10 +453,10 @@ start_postmaster(void)
    PROCESS_INFORMATION pi;
 
    if (log_file != NULL)
-       snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE,
+       snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
                 exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
    else
-       snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1" SYSTEMQUOTE,
+       snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
                 exec_path, pgdata_opt, post_opts, DEVNULL);
 
    if (!CreateRestrictedProcess(cmd, &pi, false))
@@ -814,10 +814,10 @@ do_init(void)
        post_opts = "";
 
    if (!silent_mode)
-       snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s" SYSTEMQUOTE,
+       snprintf(cmd, MAXPGPATH, "\"%s\" %s%s",
                 exec_path, pgdata_opt, post_opts);
    else
-       snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s > \"%s\"" SYSTEMQUOTE,
+       snprintf(cmd, MAXPGPATH, "\"%s\" %s%s > \"%s\"",
                 exec_path, pgdata_opt, post_opts, DEVNULL);
 
    if (system(cmd) != 0)
@@ -2035,7 +2035,7 @@ adjust_data_dir(void)
        my_exec_path = pg_strdup(exec_path);
 
    /* it's important for -C to be the first option, see main.c */
-   snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" -C data_directory %s%s" SYSTEMQUOTE,
+   snprintf(cmd, MAXPGPATH, "\"%s\" -C data_directory %s%s",
             my_exec_path,
             pgdata_opt ? pgdata_opt : "",
             post_opts ? post_opts : "");
index 47fe6ccc07f357c36c40a162c9eb1fc83568fd6e..208e49bbcd060d1db8a917f74d161145689b897e 100644 (file)
@@ -1666,7 +1666,7 @@ runPgDump(const char *dbname)
    PQExpBuffer cmd = createPQExpBuffer();
    int         ret;
 
-   appendPQExpBuffer(cmd, SYSTEMQUOTE "\"%s\" %s", pg_dump_bin,
+   appendPQExpBuffer(cmd, "\"%s\" %s", pg_dump_bin,
                      pgdumpopts->data);
 
    /*
@@ -1687,8 +1687,6 @@ runPgDump(const char *dbname)
 
    doShellQuoting(cmd, connstrbuf->data);
 
-   appendPQExpBufferStr(cmd, SYSTEMQUOTE);
-
    if (verbose)
        fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
 
index fd64ba824f1dd4f95f25241b93489fa85dd0d91a..dabcd680fffcf7705e8b9e8c92bbe69c92d7f4f6 100644 (file)
@@ -1936,10 +1936,10 @@ editFile(const char *fname, int lineno)
                    editorName, fname);
 #else
    if (lineno > 0)
-       sys = psprintf(SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
+       sys = psprintf("\"%s\" %s%d \"%s\"",
                editorName, editor_lineno_arg, lineno, fname);
    else
-       sys = psprintf(SYSTEMQUOTE "\"%s\" \"%s\"" SYSTEMQUOTE,
+       sys = psprintf("\"%s\" \"%s\"",
                    editorName, fname);
 #endif
    result = system(sys);
@@ -2643,7 +2643,7 @@ do_shell(const char *command)
 #ifndef WIN32
        sys = psprintf("exec %s", shellName);
 #else
-       sys = psprintf(SYSTEMQUOTE "\"%s\"" SYSTEMQUOTE, shellName);
+       sys = psprintf("\"%s\"", shellName);
 #endif
        result = system(sys);
        free(sys);
index 06986858b60d88d459190f1e2ca8918618da9882..21c8a05d0baf13dbcc58813a457b55b9bc87ada2 100644 (file)
@@ -115,37 +115,6 @@ extern BOOL AddUserToTokenDacl(HANDLE hToken);
 #define DEVNULL "/dev/null"
 #endif
 
-/*
- * Win32 needs double quotes at the beginning and end of system()
- * strings.  If not, it gets confused with multiple quoted strings.
- * It also requires double-quotes around the executable name and
- * any files used for redirection.  Other args can use single-quotes.
- *
- * Generated using Win32 "CMD /?":
- *
- * 1. If all of the following conditions are met, then quote characters
- * on the command line are preserved:
- *
- *  - no /S switch
- *  - exactly two quote characters
- *  - no special characters between the two quote characters, where special
- *    is one of: &<>()@^|
- *  - there are one or more whitespace characters between the two quote
- *    characters
- *  - the string between the two quote characters is the name of an
- *    executable file.
- *
- *  2. Otherwise, old behavior is to see if the first character is a quote
- *  character and if so, strip the leading character and remove the last
- *  quote character on the command line, preserving any text after the last
- *  quote character.
- */
-#if defined(WIN32) && !defined(__CYGWIN__)
-#define SYSTEMQUOTE "\""
-#else
-#define SYSTEMQUOTE ""
-#endif
-
 /* Portable delay handling */
 extern void pg_usleep(long microsec);
 
@@ -332,12 +301,16 @@ extern FILE *pgwin32_fopen(const char *, const char *);
 #define        fopen(a,b) pgwin32_fopen(a,b)
 #endif
 
-#ifndef popen
-#define popen(a,b) _popen(a,b)
-#endif
-#ifndef pclose
+/*
+ * system() and popen() replacements to enclose the command in an extra
+ * pair of quotes.
+ */
+extern int pgwin32_system(const char *command);
+extern FILE *pgwin32_popen(const char *command, const char *type);
+
+#define system(a) pgwin32_system(a)
+#define popen(a,b) pgwin32_popen(a,b)
 #define pclose(a) _pclose(a)
-#endif
 
 /* New versions of MingW have gettimeofday, old mingw and msvc don't */
 #ifndef HAVE_GETTIMEOFDAY
index cb79b61b2d5c5a885581c0c5266dc633d9cc69e4..e9bedb5c75d30c73e44b4138817b9cd7630d317b 100644 (file)
@@ -137,7 +137,7 @@ ecpg_start_test(const char *testname,
    snprintf(inprg, sizeof(inprg), "%s/%s", inputdir, testname);
 
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "\"%s\" >\"%s\" 2>\"%s\"" SYSTEMQUOTE,
+            "\"%s\" >\"%s\" 2>\"%s\"",
             inprg,
             outfile_stdout,
             outfile_stderr);
index 7f2d901111c1559e8e0e81fb2bb7f3a8a7e45fef..2b770d0a7215a61298a829191f6c9d839c5fdc13 100644 (file)
@@ -38,7 +38,7 @@ OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
 OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
    thread.o
 # libpgport C files that are needed if identified by configure
-OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS))
+OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS))
 # backend/libpq
 OBJS += ip.o md5.o
 # utils/mb
@@ -89,7 +89,7 @@ backend_src = $(top_srcdir)/src/backend
 # For some libpgport modules, this only happens if configure decides
 # the module is needed (see filter hack in OBJS, above).
 
-chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
+chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
    rm -f $@ && $(LN_S) $< .
 
 ip.c md5.c: % : $(backend_src)/libpq/%
@@ -150,7 +150,7 @@ clean distclean: clean-lib
 # Might be left over from a Win32 client-only build
    rm -f pg_config_paths.h
    rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c pqsignal.c thread.c
-   rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c win32error.c win32setlocale.c
+   rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c system.c snprintf.c strerror.c strlcpy.c win32error.c win32setlocale.c
    rm -f pgsleep.c
    rm -f md5.c ip.c
    rm -f encnames.c wchar.c
index 8f5cd8de470d24f6f39f629c24bbcd0a6324c0f7..78102fafd45c948a93bff59100677ddd728fdf53 100644 (file)
@@ -106,6 +106,7 @@ CLEAN :
    -@erase "$(INTDIR)\dirmod.obj"
    -@erase "$(INTDIR)\pgsleep.obj"
    -@erase "$(INTDIR)\open.obj"
+   -@erase "$(INTDIR)\system.obj"
    -@erase "$(INTDIR)\win32error.obj"
    -@erase "$(OUTDIR)\$(OUTFILENAME).lib"
    -@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib"
@@ -149,6 +150,7 @@ LIB32_OBJS= \
    "$(INTDIR)\dirmod.obj" \
    "$(INTDIR)\pgsleep.obj" \
    "$(INTDIR)\open.obj" \
+   "$(INTDIR)\system.obj" \
    "$(INTDIR)\win32error.obj" \
    "$(INTDIR)\pthread-win32.obj"
 
@@ -295,6 +297,11 @@ LINK32_FLAGS = -Gn -L$(BCB)\lib;$(INTDIR); -x -Tpd -v
    $(CPP_PROJ) /I"." ..\..\port\open.c
 <<
 
+"$(INTDIR)\system.obj" : ..\..\port\system.c
+   $(CPP) @<<
+   $(CPP_PROJ) /I"." ..\..\port\system.c
+<<
+
 "$(INTDIR)\win32error.obj" : ..\..\port\win32error.c
    $(CPP) @<<
    $(CPP_PROJ) /I"." ..\..\port\win32error.c
index ee1884fe201125c9ba1b2d260a879596a0efb174..23e09e981006bf11127d58910a92953814ae3deb 100644 (file)
@@ -113,6 +113,7 @@ CLEAN :
    -@erase "$(INTDIR)\dirmod.obj"
    -@erase "$(INTDIR)\pgsleep.obj"
    -@erase "$(INTDIR)\open.obj"
+   -@erase "$(INTDIR)\system.obj"
    -@erase "$(INTDIR)\win32error.obj"
    -@erase "$(INTDIR)\win32setlocale.obj"
    -@erase "$(OUTDIR)\$(OUTFILENAME).lib"
@@ -159,6 +160,7 @@ LIB32_OBJS= \
    "$(INTDIR)\dirmod.obj" \
    "$(INTDIR)\pgsleep.obj" \
    "$(INTDIR)\open.obj" \
+   "$(INTDIR)\system.obj" \
    "$(INTDIR)\win32error.obj" \
    "$(INTDIR)\win32setlocale.obj" \
    "$(INTDIR)\pthread-win32.obj"
@@ -335,6 +337,11 @@ LINK32_OBJS= \
    $(CPP_PROJ) /I"." ..\..\port\open.c
 <<
 
+"$(INTDIR)\system.obj" : ..\..\port\system.c
+   $(CPP) @<<
+   $(CPP_PROJ) /I"." ..\..\port\system.c
+<<
+
 "$(INTDIR)\win32error.obj" : ..\..\port\win32error.c
    $(CPP) @<<
    $(CPP_PROJ) /I"." ..\..\port\win32error.c
diff --git a/src/port/system.c b/src/port/system.c
new file mode 100644 (file)
index 0000000..f9c525d
--- /dev/null
@@ -0,0 +1,117 @@
+/*-------------------------------------------------------------------------
+ *
+ * system.c
+ *    Win32 system() and popen() replacements
+ *
+ *
+ * Win32 needs double quotes at the beginning and end of system()
+ * strings.  If not, it gets confused with multiple quoted strings.
+ * It also requires double-quotes around the executable name and
+ * any files used for redirection.  Other args can use single-quotes.
+ *
+ * Generated using Win32 "CMD /?":
+ *
+ * 1. If all of the following conditions are met, then quote characters
+ * on the command line are preserved:
+ *
+ *  - no /S switch
+ *  - exactly two quote characters
+ *  - no special characters between the two quote characters, where special
+ *    is one of: &<>()@^|
+ *  - there are one or more whitespace characters between the two quote
+ *    characters
+ *  - the string between the two quote characters is the name of an
+ *    executable file.
+ *
+ *  2. Otherwise, old behavior is to see if the first character is a quote
+ *  character and if so, strip the leading character and remove the last
+ *  quote character on the command line, preserving any text after the last
+ *  quote character.
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ *
+ * src/port/system.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <windows.h>
+#include <fcntl.h>
+
+#undef system
+#undef popen
+
+int
+pgwin32_system(const char *command)
+{
+   size_t      cmdlen = strlen(command);
+   char       *buf;
+   int         save_errno;
+   int         res;
+
+   /*
+    * Create a malloc'd copy of the command string, enclosed with an extra
+    * pair of quotes
+    */
+   buf = malloc(cmdlen + 2 + 1);
+   if (buf == NULL)
+   {
+       errno = ENOMEM;
+       return -1;
+   }
+   buf[0] = '"';
+   memcpy(&buf[1], command, cmdlen);
+   buf[cmdlen + 1] = '"';
+   buf[cmdlen + 2] = '\0';
+
+   res = system(buf);
+
+   save_errno = errno;
+   free(buf);
+   errno = save_errno;
+
+   return res;
+}
+
+
+FILE *
+pgwin32_popen(const char *command, const char *type)
+{
+   size_t      cmdlen = strlen(command);
+   char       *buf;
+   int         save_errno;
+   FILE       *res;
+
+   /*
+    * Create a malloc'd copy of the command string, enclosed with an extra
+    * pair of quotes
+    */
+   buf = malloc(cmdlen + 2 + 1);
+   if (buf == NULL)
+   {
+       errno = ENOMEM;
+       return NULL;
+   }
+   buf[0] = '"';
+   memcpy(&buf[1], command, cmdlen);
+   buf[cmdlen + 1] = '"';
+   buf[cmdlen + 2] = '\0';
+
+   res = _popen(buf, type);
+
+   save_errno = errno;
+   free(buf);
+   errno = save_errno;
+
+   return res;
+}
+
+#endif
index 64c41758cbaddfbbd3d28e373c5f409402977e00..c8d431fd9530cab61f4ce7fc02dbdd5d2e47fe69 100644 (file)
@@ -77,7 +77,7 @@ isolation_start_test(const char *testname,
                           "%s ", launcher);
 
    snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset,
-            SYSTEMQUOTE "\"%s\" \"dbname=%s\" < \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
+            "\"%s\" \"dbname=%s\" < \"%s\" > \"%s\" 2>&1",
             isolation_exec,
             dblist->str,
             infile,
index 07dd8037ac3f3323a869cc8bbaa1aad37302061d..c41cf7e7711ad7ae21b6588076158492206de846 100644 (file)
@@ -293,7 +293,7 @@ stop_postmaster(void)
        fflush(stderr);
 
        snprintf(buf, sizeof(buf),
-                SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
+                "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast",
                 bindir, temp_install);
        r = system(buf);
        if (r != 0)
@@ -904,7 +904,7 @@ psql_command(const char *database, const char *query,...)
 
    /* And now we can build and execute the shell command */
    snprintf(psql_cmd, sizeof(psql_cmd),
-            SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
+            "\"%s%spsql\" -X -c \"%s\" \"%s\"",
             psqldir ? psqldir : "",
             psqldir ? "/" : "",
             query_escaped,
@@ -1033,7 +1033,7 @@ spawn_process(const char *cmdline)
        exit(2);
    }
 
-   cmdline2 = psprintf("cmd /c %s", cmdline);
+   cmdline2 = psprintf("cmd /c \"%s\"", cmdline);
 
 #ifndef __CYGWIN__
    AddUserToTokenDacl(restrictedToken);
@@ -1251,7 +1251,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
 
    /* OK, run the diff */
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
+            "diff %s \"%s\" \"%s\" > \"%s\"",
             basic_diff_opts, expectfile, resultsfile, diff);
 
    /* Is the diff file empty? */
@@ -1284,7 +1284,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
        }
 
        snprintf(cmd, sizeof(cmd),
-                SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
+                "diff %s \"%s\" \"%s\" > \"%s\"",
                 basic_diff_opts, alt_expectfile, resultsfile, diff);
 
        if (run_diff(cmd, diff) == 0)
@@ -1312,7 +1312,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
    if (platform_expectfile)
    {
        snprintf(cmd, sizeof(cmd),
-                SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
+                "diff %s \"%s\" \"%s\" > \"%s\"",
                 basic_diff_opts, default_expectfile, resultsfile, diff);
 
        if (run_diff(cmd, diff) == 0)
@@ -1336,7 +1336,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
     * append to the diffs summary file.
     */
    snprintf(cmd, sizeof(cmd),
-            SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
+            "diff %s \"%s\" \"%s\" >> \"%s\"",
             pretty_diff_opts, best_expect_file, resultsfile, difffilename);
    run_diff(cmd, difffilename);
 
@@ -2121,11 +2121,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        /* "make install" */
 #ifndef WIN32_ONLY_COMPILER
        snprintf(buf, sizeof(buf),
-                SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
+                "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1",
                 makeprog, top_builddir, temp_install, outputdir);
 #else
        snprintf(buf, sizeof(buf),
-                SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
+                "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1",
                 top_builddir, temp_install, outputdir);
 #endif
        if (system(buf))
@@ -2138,7 +2138,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        {
 #ifndef WIN32_ONLY_COMPILER
            snprintf(buf, sizeof(buf),
-                    SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
+                    "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1",
                   makeprog, top_builddir, sl->str, temp_install, outputdir);
 #else
            fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname);
@@ -2155,7 +2155,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        /* initdb */
        header(_("initializing database system"));
        snprintf(buf, sizeof(buf),
-                SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
+                "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1",
                 bindir, temp_install, datadir,
                 debug ? " --debug" : "",
                 nolocale ? " --no-locale" : "",
@@ -2206,7 +2206,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
         * Check if there is a postmaster running already.
         */
        snprintf(buf2, sizeof(buf2),
-                SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
+                "\"%s/psql\" -X postgres <%s 2>%s",
                 bindir, DEVNULL, DEVNULL);
 
        for (i = 0; i < 16; i++)
@@ -2238,7 +2238,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
         */
        header(_("starting postmaster"));
        snprintf(buf, sizeof(buf),
-                SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
+                "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1",
                 bindir, temp_install,
                 debug ? " -d 5" : "",
                 hostname ? hostname : "",
index a4f66b8a33f0bc7ec9c1b4773e5ba8aa0a81c8ef..90327b06110d53a788f82ded66339e62640943a0 100644 (file)
@@ -64,7 +64,7 @@ psql_start_test(const char *testname,
                           "%s ", launcher);
 
    snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset,
-            SYSTEMQUOTE "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
+            "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1",
             psqldir ? psqldir : "",
             psqldir ? "/" : "",
             dblist->str,
index d06d6adf6ee4b43e40e25be38b1dc39f4e3666df..1254d89c2929ec5590736e84f19e2662803d5206 100644 (file)
@@ -69,7 +69,7 @@ sub mkvcbuild
      srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
      erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
      pgcheckdir.c pg_crc.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
-     qsort.c qsort_arg.c quotes.c
+     qsort.c qsort_arg.c quotes.c system.c
      sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
      win32env.c win32error.c win32setlocale.c);