From a692ee5870f0f442565b4c4bff367094599e9bdf Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas <heikki.linnakangas@iki.fi> Date: Mon, 5 May 2014 16:07:40 +0300 Subject: [PATCH] Replace SYSTEMQUOTEs with Windows-specific wrapper functions. 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 --- configure.in | 1 + contrib/pg_upgrade/check.c | 2 +- contrib/pg_upgrade/controldata.c | 2 +- contrib/pg_upgrade/exec.c | 4 +- src/bin/initdb/initdb.c | 40 +++---- src/bin/pg_ctl/pg_ctl.c | 14 +-- src/bin/pg_dump/pg_dumpall.c | 4 +- src/bin/psql/command.c | 6 +- src/include/port.h | 45 ++------ src/interfaces/ecpg/test/pg_regress_ecpg.c | 2 +- src/interfaces/libpq/Makefile | 6 +- src/interfaces/libpq/bcc32.mak | 7 ++ src/interfaces/libpq/win32.mak | 7 ++ src/port/system.c | 117 +++++++++++++++++++++ src/test/isolation/isolation_main.c | 2 +- src/test/regress/pg_regress.c | 26 ++--- src/test/regress/pg_regress_main.c | 2 +- src/tools/msvc/Mkvcbuild.pm | 2 +- 18 files changed, 196 insertions(+), 93 deletions(-) create mode 100644 src/port/system.c diff --git a/configure.in b/configure.in index fc9c52f83d2..52357a6bba3 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/contrib/pg_upgrade/check.c b/contrib/pg_upgrade/check.c index 56e912d8c3d..d22b6d38e29 100644 --- a/contrib/pg_upgrade/check.c +++ b/contrib/pg_upgrade/check.c @@ -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) diff --git a/contrib/pg_upgrade/controldata.c b/contrib/pg_upgrade/controldata.c index fa0a0053bab..476c6be276e 100644 --- a/contrib/pg_upgrade/controldata.c +++ b/contrib/pg_upgrade/controldata.c @@ -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); diff --git a/contrib/pg_upgrade/exec.c b/contrib/pg_upgrade/exec.c index 7f013013a06..91e66e6ecf4 100644 --- a/contrib/pg_upgrade/exec.c +++ b/contrib/pg_upgrade/exec.c @@ -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"); diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index b53fa8bd088..83b7f6e24d8 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -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); diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index fc87e7d76ed..473d6534064 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -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 : ""); diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 47fe6ccc07f..208e49bbcd0 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -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); diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index fd64ba824f1..dabcd680fff 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -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); diff --git a/src/include/port.h b/src/include/port.h index 06986858b60..21c8a05d0ba 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -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 diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c index cb79b61b2d5..e9bedb5c75d 100644 --- a/src/interfaces/ecpg/test/pg_regress_ecpg.c +++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c @@ -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); diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 7f2d901111c..2b770d0a721 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -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 diff --git a/src/interfaces/libpq/bcc32.mak b/src/interfaces/libpq/bcc32.mak index 8f5cd8de470..78102fafd45 100644 --- a/src/interfaces/libpq/bcc32.mak +++ b/src/interfaces/libpq/bcc32.mak @@ -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 diff --git a/src/interfaces/libpq/win32.mak b/src/interfaces/libpq/win32.mak index ee1884fe201..23e09e98100 100644 --- a/src/interfaces/libpq/win32.mak +++ b/src/interfaces/libpq/win32.mak @@ -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 index 00000000000..f9c525dfbfc --- /dev/null +++ b/src/port/system.c @@ -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 diff --git a/src/test/isolation/isolation_main.c b/src/test/isolation/isolation_main.c index 64c41758cba..c8d431fd953 100644 --- a/src/test/isolation/isolation_main.c +++ b/src/test/isolation/isolation_main.c @@ -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, diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 07dd8037ac3..c41cf7e7711 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -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 : "", diff --git a/src/test/regress/pg_regress_main.c b/src/test/regress/pg_regress_main.c index a4f66b8a33f..90327b06110 100644 --- a/src/test/regress/pg_regress_main.c +++ b/src/test/regress/pg_regress_main.c @@ -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, diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index d06d6adf6ee..1254d89c292 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -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); -- GitLab