Windows: Make pg_ctl reliably detect service status
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 7 Jan 2016 14:59:08 +0000 (11:59 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 7 Jan 2016 14:59:08 +0000 (11:59 -0300)
pg_ctl is using isatty() to verify whether the process is running in a
terminal, and if not it sends its output to Windows' Event Log ... which
does the wrong thing when the output has been redirected to a pipe, as
reported in bug #13592.

To fix, make pg_ctl use the code we already have to detect service-ness:
in the master branch, move src/backend/port/win32/security.c to src/port
(with suitable tweaks so that it runs properly in backend and frontend
environments); pg_ctl already has access to pgport so it Just Works.  In
older branches, that's likely to cause trouble, so instead duplicate the
required code in pg_ctl.c.

Author: Michael Paquier
Bug report and diagnosis: Egon Kocjan
Backpatch: all supported branches

src/backend/port/win32/Makefile
src/bin/pg_ctl/pg_ctl.c
src/include/port/win32.h
src/port/win32security.c [moved from src/backend/port/win32/security.c with 73% similarity]
src/tools/msvc/Mkvcbuild.pm

index 820a3b3753ec2cd595c5a1c0e7f72fdac129d8b1..a6ace93e261a71c789b713d861d0b75c86beb4f4 100644 (file)
@@ -12,7 +12,7 @@ subdir = src/backend/port/win32
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = timer.o socket.o signal.o security.o mingwcompat.o
+OBJS = timer.o socket.o signal.o mingwcompat.o
 ifeq ($(have_win32_dbghelp), yes)
 OBJS += crashdump.o
 endif
index bd82a059a04b4e50e8a97a1af28117cb3ee432ac..28d3cf2a8f9a4250110117674932aa70a320a4dc 100644 (file)
@@ -216,7 +216,7 @@ write_stderr(const char *fmt,...)
     * On Win32, we print to stderr if running on a console, or write to
     * eventlog if running as a service
     */
-   if (!isatty(fileno(stderr)))    /* Running as a service */
+   if (!pgwin32_is_service())  /* Running as a service */
    {
        char        errbuf[2048];       /* Arbitrary size? */
 
index 4cb51ec7bea68476a25402c58dc8b2f1d0e75534..69cd1c41e154331de76e19d446774d932ca057d2 100644 (file)
@@ -382,9 +382,6 @@ int         pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout);
 
 extern int pgwin32_noblock;
 
-/* in backend/port/win32/security.c */
-extern int pgwin32_is_admin(void);
-extern int pgwin32_is_service(void);
 #endif
 
 /* in backend/port/win32_shmem.c */
@@ -400,6 +397,10 @@ extern void _dosmaperr(unsigned long);
 extern int pgwin32_putenv(const char *);
 extern void pgwin32_unsetenv(const char *);
 
+/* in port/win32security.c */
+extern int pgwin32_is_service(void);
+extern int pgwin32_is_admin(void);
+
 #define putenv(x) pgwin32_putenv(x)
 #define unsetenv(x) pgwin32_unsetenv(x)
 
similarity index 73%
rename from src/backend/port/win32/security.c
rename to src/port/win32security.c
index 327ed404fdc5f577cce73e376bbfa5b5c1a2320c..66796e0e286bdc0e03064eea4c890db1f9753f68 100644 (file)
@@ -1,22 +1,47 @@
 /*-------------------------------------------------------------------------
  *
- * security.c
+ * win32security.c
  *   Microsoft Windows Win32 Security Support Functions
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   src/backend/port/win32/security.c
+ *   src/port/win32security.c
  *
  *-------------------------------------------------------------------------
  */
 
+#ifndef FRONTEND
 #include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
 
 
 static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
-                           TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
-                             char *errbuf, int errsize);
+                             TOKEN_INFORMATION_CLASS class,
+                             char **InfoBuffer, char *errbuf, int errsize);
+
+
+/*
+ * Utility wrapper for frontend and backend when reporting an error
+ * message.
+ */
+static
+pg_attribute_printf(1, 2)
+void
+log_error(const char *fmt,...)
+{
+   va_list     ap;
+
+   va_start(fmt, ap);
+#ifndef FRONTEND
+   write_stderr(fmt, ap);
+#else
+   fprintf(stderr, fmt, ap);
+#endif
+   va_end(ap);
+}
 
 /*
  * Returns nonzero if the current user has administrative privileges,
@@ -40,15 +65,15 @@ pgwin32_is_admin(void)
 
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
    {
-       write_stderr("could not open process token: error code %lu\n",
-                    GetLastError());
+       log_error("could not open process token: error code %lu\n",
+                 GetLastError());
        exit(1);
    }
 
    if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
                                       &InfoBuffer, errbuf, sizeof(errbuf)))
    {
-       write_stderr("%s", errbuf);
+       log_error("%s", errbuf);
        exit(1);
    }
 
@@ -57,20 +82,22 @@ pgwin32_is_admin(void)
    CloseHandle(AccessToken);
 
    if (!AllocateAndInitializeSid(&NtAuthority, 2,
-        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
+                                 SECURITY_BUILTIN_DOMAIN_RID,
+                                 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
                                  0, &AdministratorsSid))
    {
-       write_stderr("could not get SID for Administrators group: error code %lu\n",
-                    GetLastError());
+       log_error("could not get SID for Administrators group: error code %lu\n",
+                 GetLastError());
        exit(1);
    }
 
    if (!AllocateAndInitializeSid(&NtAuthority, 2,
-   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
+                                 SECURITY_BUILTIN_DOMAIN_RID,
+                                 DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
                                  0, &PowerUsersSid))
    {
-       write_stderr("could not get SID for PowerUsers group: error code %lu\n",
-                    GetLastError());
+       log_error("could not get SID for PowerUsers group: error code %lu\n",
+                 GetLastError());
        exit(1);
    }
 
@@ -78,8 +105,10 @@ pgwin32_is_admin(void)
 
    for (x = 0; x < Groups->GroupCount; x++)
    {
-       if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
-           (EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
+       if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) &&
+            (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
+           (EqualSid(PowerUsersSid, Groups->Groups[x].Sid) &&
+            (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
        {
            success = TRUE;
            break;
@@ -105,9 +134,10 @@ pgwin32_is_admin(void)
  *  1 = Service
  * -1 = Error
  *
- * Note: we can't report errors via either ereport (we're called too early)
- * or write_stderr (because that calls this).  We are therefore reduced to
- * writing directly on stderr, which sucks, but we have few alternatives.
+ * Note: we can't report errors via either ereport (we're called too early
+ * in the backend) or write_stderr (because that calls this).  We are
+ * therefore reduced to writing directly on stderr, which sucks, but we
+ * have few alternatives.
  */
 int
 pgwin32_is_service(void)
@@ -217,13 +247,15 @@ pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
 
    if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
    {
-       snprintf(errbuf, errsize, "could not get token information: got zero size\n");
+       snprintf(errbuf, errsize,
+                "could not get token information: got zero size\n");
        return FALSE;
    }
 
    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    {
-       snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
+       snprintf(errbuf, errsize,
+                "could not get token information: error code %lu\n",
                 GetLastError());
        return FALSE;
    }
@@ -231,7 +263,8 @@ pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
    *InfoBuffer = malloc(InfoBufferSize);
    if (*InfoBuffer == NULL)
    {
-       snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n",
+       snprintf(errbuf, errsize,
+                "could not allocate %d bytes for token information\n",
                 (int) InfoBufferSize);
        return FALSE;
    }
@@ -239,7 +272,8 @@ pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
    if (!GetTokenInformation(token, class, *InfoBuffer,
                             InfoBufferSize, &InfoBufferSize))
    {
-       snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
+       snprintf(errbuf, errsize,
+                "could not get token information: error code %lu\n",
                 GetLastError());
        return FALSE;
    }
index c122f0259c9c677b36d34d243cfa4c7d9d5344c7..1dba7d9662ee9bd5d54ebc9d8cb55b0e39b89eb1 100644 (file)
@@ -90,7 +90,7 @@ sub mkvcbuild
      pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
      mkdtemp.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);
+     win32env.c win32error.c win32security.c win32setlocale.c);
 
    push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00');