Replace direct fprintf(stderr) calls by write_stderr(), and cause this
authorTom Lane
Thu, 24 Jun 2004 21:03:42 +0000 (21:03 +0000)
committerTom Lane
Thu, 24 Jun 2004 21:03:42 +0000 (21:03 +0000)
routine to do something appropriate on Win32.  Also, add a security check
on Win32 that parallels the can't-run-as-root check on Unix.

Magnus Hagander

13 files changed:
src/backend/bootstrap/bootstrap.c
src/backend/main/main.c
src/backend/nls.mk
src/backend/port/win32/Makefile
src/backend/port/win32/security.c [new file with mode: 0644]
src/backend/port/win32/signal.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/backend/utils/error/assert.c
src/backend/utils/error/elog.c
src/backend/utils/misc/help_config.c
src/include/port/win32.h
src/include/utils/elog.h

index 553cf79dd0b332adf842564401d5d73032e76c90..ccf0595835e814430042f6cc0c537add295377fb 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.184 2004/06/06 00:41:26 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.185 2004/06/24 21:02:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -328,12 +328,11 @@ BootstrapMain(int argc, char *argv[])
    {
        if (!potential_DataDir)
        {
-           fprintf(stderr,
-                   gettext("%s does not know where to find the database system data.\n"
-                           "You must specify the directory that contains the database system\n"
-                           "either by specifying the -D invocation option or by setting the\n"
-                           "PGDATA environment variable.\n"),
-                   argv[0]);
+           write_stderr("%s does not know where to find the database system data.\n"
+                        "You must specify the directory that contains the database system\n"
+                        "either by specifying the -D invocation option or by setting the\n"
+                        "PGDATA environment variable.\n",
+                        argv[0]);
            proc_exit(1);
        }
        SetDataDir(potential_DataDir);
@@ -503,15 +502,14 @@ BootstrapMain(int argc, char *argv[])
 static void
 usage(void)
 {
-   fprintf(stderr,
-           gettext("Usage:\n"
+   write_stderr("Usage:\n"
                    "  postgres -boot [OPTION]... DBNAME\n"
                    "  -c NAME=VALUE    set run-time parameter\n"
                    "  -d 1-5           debug level\n"
                    "  -D datadir       data directory\n"
                    "  -F               turn off fsync\n"
                    "  -o file          send debug output to file\n"
-                   "  -x num           internal use\n"));
+                   "  -x num           internal use\n");
 
    proc_exit(1);
 }
index c9c377e1e946b28b3213784c667b39f922a1b57d..b293e57c90c35a9e2210cc90d562143b711796de 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/main/main.c,v 1.86 2004/06/03 00:07:36 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/main/main.c,v 1.87 2004/06/24 21:02:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -91,8 +91,8 @@ main(int argc, char *argv[])
 #if defined(__alpha)           /* no __alpha__ ? */
    if (setsysinfo(SSI_NVPAIRS, buffer, 1, (caddr_t) NULL,
                   (unsigned long) NULL) < 0)
-       fprintf(stderr, gettext("%s: setsysinfo failed: %s\n"),
-               argv[0], strerror(errno));
+       write_stderr("%s: setsysinfo failed: %s\n",
+                    argv[0], strerror(errno));
 #endif
 #endif   /* NOFIXADE || NOPRINTADE */
 
@@ -109,7 +109,7 @@ main(int argc, char *argv[])
        err = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (err != 0)
        {
-           fprintf(stderr, "%s: WSAStartup failed: %d\n",
+           write_stderr("%s: WSAStartup failed: %d\n",
                    argv[0], err);
            exit(1);
        }
@@ -212,12 +212,10 @@ main(int argc, char *argv[])
         */
        if (geteuid() == 0)
        {
-           fprintf(stderr,
-                   gettext("\"root\" execution of the PostgreSQL server is not permitted.\n"
-                           "The server must be started under an unprivileged user ID to prevent\n"
-                           "possible system security compromise.  See the documentation for\n"
-               "more information on how to properly start the server.\n"
-                           ));
+           write_stderr("\"root\" execution of the PostgreSQL server is not permitted.\n"
+                        "The server must be started under an unprivileged user ID to prevent\n"
+                        "possible system security compromise.  See the documentation for\n"
+                        "more information on how to properly start the server.\n");
            exit(1);
        }
 #endif   /* !__BEOS__ */
@@ -233,9 +231,17 @@ main(int argc, char *argv[])
         */
        if (getuid() != geteuid())
        {
-           fprintf(stderr,
-                gettext("%s: real and effective user IDs must match\n"),
-                   argv[0]);
+           write_stderr("%s: real and effective user IDs must match\n",
+                        argv[0]);
+           exit(1);
+       }
+#else /* WIN32 */
+       if (pgwin32_is_admin())
+       {
+           write_stderr("execution of PostgreSQL by a user with administrative permissions is not permitted.\n"
+                        "The server must be started under an unprivileged user ID to prevent\n"
+                        "possible system security compromise.  See the documentation for\n"
+                        "more information on how to properly start the server.\n");
            exit(1);
        }
 #endif   /* !WIN32 */
@@ -292,8 +298,8 @@ main(int argc, char *argv[])
    pw = getpwuid(geteuid());
    if (pw == NULL)
    {
-       fprintf(stderr, gettext("%s: invalid effective UID: %d\n"),
-               argv[0], (int) geteuid());
+       write_stderr("%s: invalid effective UID: %d\n",
+                    argv[0], (int) geteuid());
        exit(1);
    }
    /* Allocate new memory because later getpwuid() calls can overwrite it */
@@ -305,7 +311,7 @@ main(int argc, char *argv[])
        pw_name_persist = malloc(namesize);
        if (!GetUserName(pw_name_persist, &namesize))
        {
-           fprintf(stderr, gettext("%s: could not determine user name (GetUserName failed)\n"),
+           write_stderr("%s: could not determine user name (GetUserName failed)\n",
                    argv[0]);
            exit(1);
        }
index d4d457b871a253ce2a61d46e70fb5453fc9b1408..dff5567be59415f823e480ac0c3c1222e707b91d 100644 (file)
@@ -1,10 +1,10 @@
-# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.12 2004/06/10 17:10:24 petere Exp $
+# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.13 2004/06/24 21:02:40 tgl Exp $
 CATALOG_NAME   := postgres
 AVAIL_LANGUAGES    := af cs de es hr hu it nb pt_BR ru sv tr zh_CN zh_TW
 GETTEXT_FILES  := + gettext-files
 # you can add "elog:2" and "errmsg_internal" to this list if you want to
 # include internal messages in the translation list.
-GETTEXT_TRIGGERS:= errmsg errdetail errhint errcontext postmaster_error yyerror
+GETTEXT_TRIGGERS:= errmsg errdetail errhint errcontext write_stderr yyerror
 
 gettext-files: distprep
    find $(srcdir)/ -name '*.c' -print >$@
index 0d5b64ce36401c42bc6e54898c2a51847e9e06da..8069d590fd4fb581f06ba0e13770f4f1af0db5e1 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for port/win32
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/port/win32/Makefile,v 1.4 2004/04/12 16:19:18 momjian Exp $
+#    $PostgreSQL: pgsql/src/backend/port/win32/Makefile,v 1.5 2004/06/24 21:02:42 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/port/win32
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = sema.o shmem.o timer.o socket.o signal.o
+OBJS = sema.o shmem.o timer.o socket.o signal.o security.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/port/win32/security.c b/src/backend/port/win32/security.c
new file mode 100644 (file)
index 0000000..acc2f41
--- /dev/null
@@ -0,0 +1,184 @@
+/*-------------------------------------------------------------------------
+ *
+ * security.c
+ *    Microsoft Windows Win32 Security Support Functions
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   $PostgreSQL: pgsql/src/backend/port/win32/security.c,v 1.1 2004/06/24 21:02:42 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+
+/*
+ * Returns nonzero if the current user has administrative privileges,
+ * or zero if not.
+ *
+ * Note: this cannot use ereport() because it's called too early during
+ * startup.
+ */
+int
+pgwin32_is_admin(void)
+{
+   HANDLE AccessToken;
+   UCHAR InfoBuffer[1024];
+   PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)InfoBuffer; 
+   DWORD InfoBufferSize;
+   PSID AdministratorsSid;
+   PSID PowerUsersSid;
+   SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY }; 
+   UINT x;
+   BOOL success;
+   
+   if(!OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&AccessToken))
+   {
+       write_stderr("failed to open process token: %d\n",
+                    (int)GetLastError());
+       exit(1);
+   }
+
+   if (!GetTokenInformation(AccessToken,TokenGroups,InfoBuffer,
+                            1024, &InfoBufferSize))
+   {
+       write_stderr("failed to get token information: %d\n",
+                    (int)GetLastError());
+       exit(1);
+   }
+
+   CloseHandle(AccessToken);
+
+   if(!AllocateAndInitializeSid(&NtAuthority, 2,
+                                SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
+                                0,&AdministratorsSid))
+   {
+       write_stderr("failed to get SID for Administrators group: %d\n",
+                    (int)GetLastError());
+       exit(1);
+   }
+
+   if (!AllocateAndInitializeSid(&NtAuthority, 2,
+                                 SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
+                                 0, &PowerUsersSid))
+   {
+       write_stderr("failed to get SID for PowerUsers group: %d\n",
+                    (int)GetLastError());
+       exit(1);
+   }
+   
+   success = FALSE;
+   
+   for (x=0; xGroupCount; x++)
+   {
+       if (EqualSid(AdministratorsSid, Groups->Groups[x].Sid) ||
+           EqualSid(PowerUsersSid, Groups->Groups[x].Sid))
+       {
+           success = TRUE;
+           break;
+       }
+   }
+   
+   FreeSid(AdministratorsSid);
+   FreeSid(PowerUsersSid);
+   return success;
+}
+
+/*
+ * We consider ourselves running as a service if one of the following is
+ * true:
+ *
+ * 1) We are running as Local System (only used by services)
+ * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
+ *    process token by the SCM when starting a service)
+ *
+ * Return values:
+ *   0 = Not service
+ *   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.
+ */
+int
+pgwin32_is_service(void)
+{
+   static int _is_service = -1;
+   HANDLE AccessToken;
+   UCHAR InfoBuffer[1024];
+   PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)InfoBuffer;
+   PTOKEN_USER User = (PTOKEN_USER)InfoBuffer;
+   DWORD InfoBufferSize;
+   PSID ServiceSid;
+   PSID LocalSystemSid;
+   SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY }; 
+   UINT x;
+
+   /* Only check the first time */
+   if (_is_service != -1)
+       return _is_service;
+   
+   if (!OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&AccessToken)) {
+       fprintf(stderr,"failed to open process token: %d\n",
+               (int)GetLastError());
+       return -1;
+   }
+
+   /* First check for local system */
+   if (!GetTokenInformation(AccessToken,TokenUser,InfoBuffer,1024,&InfoBufferSize)) {
+       fprintf(stderr,"failed to get token information: %d\n",
+               (int)GetLastError());
+       return -1;
+   }
+   
+   if (!AllocateAndInitializeSid(&NtAuthority,1,
+                                 SECURITY_LOCAL_SYSTEM_RID,0,0,0,0,0,0,0,
+                                 &LocalSystemSid)) {
+       fprintf(stderr,"failed to get SID for local system account\n");
+       CloseHandle(AccessToken);
+       return -1;
+   }
+
+   if (EqualSid(LocalSystemSid, User->User.Sid)) {
+       FreeSid(LocalSystemSid);
+       CloseHandle(AccessToken);
+       _is_service = 1;
+       return _is_service;
+   }
+
+   FreeSid(LocalSystemSid);
+
+   /* Now check for group SID */
+   if (!GetTokenInformation(AccessToken,TokenGroups,InfoBuffer,1024,&InfoBufferSize)) {
+       fprintf(stderr,"failed to get token information: %d\n",
+               (int)GetLastError());
+       return -1;
+   }
+
+   if (!AllocateAndInitializeSid(&NtAuthority,1,
+                                 SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
+                                 &ServiceSid)) {
+       fprintf(stderr,"failed to get SID for service group\n");
+       CloseHandle(AccessToken);
+       return -1;
+   }
+
+   _is_service = 0;
+   for (x = 0; x < Groups->GroupCount; x++)
+   {
+       if (EqualSid(ServiceSid, Groups->Groups[x].Sid)) 
+       {
+           _is_service = 1;
+           break;
+       }
+   }
+
+   FreeSid(ServiceSid);
+
+   CloseHandle(AccessToken);
+
+   return _is_service;
+}
index fc0652a5b01b069e0b66579d18a67ffb94df1eb0..a5cc25611236ce2f2a87ecc87a301399eac552c2 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.3 2004/05/27 14:39:29 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.4 2004/06/24 21:02:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,18 +63,18 @@ pgwin32_signal_initialize(void)
    pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (pgwin32_signal_event == NULL) 
        ereport(FATAL,
-               (errmsg_internal("Failed to create signal event: %i!",(int)GetLastError())));
+               (errmsg_internal("failed to create signal event: %d", (int)GetLastError())));
 
    /* Create thread for handling signals */
    signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
    if (signal_thread_handle == NULL)
        ereport(FATAL,
-               (errmsg_internal("Failed to create signal handler thread!")));
+               (errmsg_internal("failed to create signal handler thread")));
 
    /* Create console control handle to pick up Ctrl-C etc */
    if (!SetConsoleCtrlHandler(pg_console_handler, TRUE)) 
        ereport(FATAL,
-               (errmsg_internal("Failed to set console control handler!")));
+               (errmsg_internal("failed to set console control handler")));
 }
 
 
@@ -209,7 +209,7 @@ pg_signal_thread(LPVOID param)
    char        pipename[128];
    HANDLE      pipe = INVALID_HANDLE_VALUE;
 
-   wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", GetCurrentProcessId());
+   wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId());
 
    for (;;)
    {
@@ -221,7 +221,7 @@ pg_signal_thread(LPVOID param)
                           PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
        if (pipe == INVALID_HANDLE_VALUE)
        {
-           fprintf(stderr, gettext("Failed to create signal listener pipe: %i. Retrying.\n"), (int) GetLastError());
+           write_stderr("failed to create signal listener pipe: %d. Retrying.\n", (int) GetLastError());
            SleepEx(500, FALSE);
            continue;
        }
@@ -233,7 +233,8 @@ pg_signal_thread(LPVOID param)
                      (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread,
                                   (LPVOID) pipe, 0, NULL);
            if (hThread == INVALID_HANDLE_VALUE)
-               fprintf(stderr, gettext("Failed to create signal dispatch thread: %i\n"), (int) GetLastError());
+               write_stderr("failed to create signal dispatch thread: %d\n",
+                            (int) GetLastError());
            else
                CloseHandle(hThread);
        }
index 5a591f2f491b94099f07a24e105686f8dd2c693d..5d908807b9d330542ff879c21bdb4403856d3fd8 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.404 2004/06/14 18:08:19 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.405 2004/06/24 21:02:55 tgl Exp $
  *
  * NOTES
  *
  *     The Postmaster cleans up after backends if they have an emergency
  *     exit and/or core dump.
  *
+ * Error Reporting:
+ *     Use write_stderr() only for reporting "interactive" errors
+ *     (essentially, bogus arguments on the command line).  Once the
+ *     postmaster is launched, use ereport().  In particular, don't use
+ *     write_stderr() for anything that occurs after pmdaemonize.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -260,10 +266,6 @@ static void SignalChildren(int signal);
 static int CountChildren(void);
 static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
 static pid_t StartChildProcess(int xlop);
-static void
-postmaster_error(const char *fmt,...)
-/* This lets gcc check the format string for consistency. */
-__attribute__((format(printf, 1, 2)));
 
 #ifdef EXEC_BACKEND
 
@@ -380,7 +382,7 @@ PostmasterMain(int argc, char *argv[])
 #ifdef USE_ASSERT_CHECKING
                SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV);
 #else
-               postmaster_error("assert checking is not compiled in");
+               write_stderr("%s: assert checking is not compiled in\n", progname);
 #endif
                break;
            case 'a':
@@ -503,9 +505,8 @@ PostmasterMain(int argc, char *argv[])
                }
 
            default:
-               fprintf(stderr,
-                   gettext("Try \"%s --help\" for more information.\n"),
-                       progname);
+               write_stderr("Try \"%s --help\" for more information.\n",
+                            progname);
                ExitPostmaster(1);
        }
    }
@@ -515,10 +516,10 @@ PostmasterMain(int argc, char *argv[])
     */
    if (optind < argc)
    {
-       postmaster_error("invalid argument: \"%s\"", argv[optind]);
-       fprintf(stderr,
-               gettext("Try \"%s --help\" for more information.\n"),
-               progname);
+       write_stderr("%s: invalid argument: \"%s\"\n",
+                    progname, argv[optind]);
+       write_stderr("Try \"%s --help\" for more information.\n",
+                    progname);
        ExitPostmaster(1);
    }
 
@@ -547,13 +548,13 @@ PostmasterMain(int argc, char *argv[])
         * for lack of buffers.  The specific choices here are somewhat
         * arbitrary.
         */
-       postmaster_error("the number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16");
+       write_stderr("%s: the number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16\n", progname);
        ExitPostmaster(1);
    }
 
    if (ReservedBackends >= MaxBackends)
    {
-       postmaster_error("superuser_reserved_connections must be less than max_connections");
+       write_stderr("%s: superuser_reserved_connections must be less than max_connections\n", progname);
        ExitPostmaster(1);
    }
 
@@ -562,7 +563,7 @@ PostmasterMain(int argc, char *argv[])
     */
    if (!CheckDateTokenTables())
    {
-       postmaster_error("invalid datetoken tables, please fix");
+       write_stderr("%s: invalid datetoken tables, please fix\n", progname);
        ExitPostmaster(1);
    }
 
@@ -858,12 +859,11 @@ checkDataDir(const char *checkdir)
 
    if (checkdir == NULL)
    {
-       fprintf(stderr,
-               gettext("%s does not know where to find the database system data.\n"
-                       "You must specify the directory that contains the database system\n"
-                       "either by specifying the -D invocation option or by setting the\n"
-                       "PGDATA environment variable.\n"),
-               progname);
+       write_stderr("%s does not know where to find the database system data.\n"
+                    "You must specify the directory that contains the database system\n"
+                    "either by specifying the -D invocation option or by setting the\n"
+                    "PGDATA environment variable.\n",
+                    progname);
        ExitPostmaster(2);
    }
 
@@ -905,11 +905,10 @@ checkDataDir(const char *checkdir)
    fp = AllocateFile(path, PG_BINARY_R);
    if (fp == NULL)
    {
-       fprintf(stderr,
-               gettext("%s: could not find the database system\n"
-                       "Expected to find it in the directory \"%s\",\n"
-                       "but could not open file \"%s\": %s\n"),
-               progname, checkdir, path, strerror(errno));
+       write_stderr("%s: could not find the database system\n"
+                    "Expected to find it in the directory \"%s\",\n"
+                    "but could not open file \"%s\": %s\n",
+                    progname, checkdir, path, strerror(errno));
        ExitPostmaster(2);
    }
    FreeFile(fp);
@@ -952,8 +951,8 @@ pmdaemonize(void)
    pid = fork();
    if (pid == (pid_t) -1)
    {
-       postmaster_error("could not fork background process: %s",
-                        strerror(errno));
+       write_stderr("%s: could not fork background process: %s\n",
+                    progname, strerror(errno));
        ExitPostmaster(1);
    }
    else if (pid)
@@ -974,8 +973,8 @@ pmdaemonize(void)
 #ifdef HAVE_SETSID
    if (setsid() < 0)
    {
-       postmaster_error("could not dissociate from controlling TTY: %s",
-                        strerror(errno));
+       write_stderr("%s: could not dissociate from controlling TTY: %s\n",
+                    progname, strerror(errno));
        ExitPostmaster(1);
    }
 #endif
@@ -3152,24 +3151,6 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
    return true;
 }
 
-/*
- * This should be used only for reporting "interactive" errors (essentially,
- * bogus arguments on the command line).  Once the postmaster is launched,
- * use ereport.  In particular, don't use this for anything that occurs
- * after pmdaemonize.
- */
-static void
-postmaster_error(const char *fmt,...)
-{
-   va_list     ap;
-
-   fprintf(stderr, "%s: ", progname);
-   va_start(ap, fmt);
-   vfprintf(stderr, gettext(fmt), ap);
-   va_end(ap);
-   fprintf(stderr, "\n");
-}
-
 
 #ifdef EXEC_BACKEND
 
@@ -3609,7 +3590,7 @@ win32_sigchld_waiter(LPVOID param)
    if (r == WAIT_OBJECT_0)
        pg_queue_signal(SIGCHLD);
    else
-       fprintf(stderr, "ERROR: failed to wait on child process handle: %d\n",
+       write_stderr("ERROR: failed to wait on child process handle: %d\n",
                (int) GetLastError());
    CloseHandle(procHandle);
    return 0;
index 976b417e096fa454da871dc93b40359265550a9d..9b7cfcd66814cce67dd5fefc8a15521ca7275bc5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.420 2004/06/11 01:09:00 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.421 2004/06/24 21:03:08 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -2578,12 +2578,11 @@ PostgresMain(int argc, char *argv[], const char *username)
    {
        if (!potential_DataDir)
        {
-           fprintf(stderr,
-                   gettext("%s does not know where to find the database system data.\n"
-                           "You must specify the directory that contains the database system\n"
-                           "either by specifying the -D invocation option or by setting the\n"
-                           "PGDATA environment variable.\n"),
-                   argv[0]);
+           write_stderr("%s does not know where to find the database system data.\n"
+                        "You must specify the directory that contains the database system\n"
+                        "either by specifying the -D invocation option or by setting the\n"
+                        "PGDATA environment variable.\n",
+                        argv[0]);
            proc_exit(1);
        }
        SetDataDir(potential_DataDir);
index f35636e9fecdf6a9d436bd7dde5b9fd589f13425..f740c1baa5790189221b194efaa3cc439ab36a9a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/error/assert.c,v 1.26 2004/04/19 17:42:58 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/error/assert.c,v 1.27 2004/06/24 21:03:13 tgl Exp $
  *
  * NOTE
  *   This should eventually work with elog()
@@ -31,10 +31,10 @@ ExceptionalCondition(char *conditionName,
    if (!PointerIsValid(conditionName)
        || !PointerIsValid(fileName)
        || !PointerIsValid(errorType))
-       fprintf(stderr, "TRAP: ExceptionalCondition: bad arguments\n");
+       write_stderr("TRAP: ExceptionalCondition: bad arguments\n");
    else
    {
-       fprintf(stderr, "TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n",
+       write_stderr("TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n",
                errorType, conditionName,
                fileName, lineNumber);
    }
index e47740ededad028f2fcfc44dd898f5bf69d2ed18..c70958a9de13192489e85a6a49f514e47368bef6 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.141 2004/06/21 14:12:38 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.142 2004/06/24 21:03:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1765,3 +1765,37 @@ append_with_tabs(StringInfo buf, const char *str)
            appendStringInfoCharMacro(buf, '\t');
    }
 }
+
+
+/* 
+ * Write errors to stderr (or by equal means when stderr is
+ * not available). Used before ereport/elog can be used
+ * safely (memory context, GUC load etc) 
+ */
+void
+write_stderr(const char *fmt,...)
+{
+   va_list ap;
+
+   fmt = gettext(fmt);
+
+   va_start(ap, fmt);
+#ifndef WIN32
+   /* On Unix, we just fprintf to stderr */
+   vfprintf(stderr, fmt, ap);
+#else
+   /* On Win32, we print to stderr if running on a console, or write to 
+    * eventlog if running as a service */
+   if (pgwin32_is_service()) /* Running as a service */
+   {
+       char errbuf[2048]; /* Arbitrary size? */
+
+       vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
+       
+       write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
+   }
+   else /* Not running as service, write to stderr */
+       vfprintf(stderr, fmt, ap);
+#endif
+   va_end(ap);
+}
index 21cd59161361a2f879c0b4a2e8ab0b97d1a8db24..b627d145cc671b79c67e0073473e3f70af8728cf 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/help_config.c,v 1.11 2004/06/02 18:09:32 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/help_config.c,v 1.12 2004/06/24 21:03:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -122,7 +122,7 @@ printMixedStruct(mixedStruct *structToPrint)
            break;
 
        default:
-           fprintf(stderr, "internal error: unrecognized run-time parameter type\n");
+           write_stderr("internal error: unrecognized run-time parameter type\n");
            break;
    }
 
index c10eb078c4a8a4c88226966ffea018de2a3a1052..28a583690d4c0f6c108c33f8b8cb6f4ce2271d98 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.25 2004/05/27 14:39:33 momjian Exp $ */
+/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.26 2004/06/24 21:03:33 tgl Exp $ */
 
 /* undefine and redefine after #include */
 #undef mkdir
@@ -138,6 +138,10 @@ int pgwin32_recv(SOCKET s, char* buf, int len, int flags);
 int pgwin32_send(SOCKET s, char* buf, int len, int flags);
 
 const char *pgwin32_socket_strerror(int err);
+
+/* in backend/port/win32/security.c */
+extern int pgwin32_is_admin(void);
+extern int pgwin32_is_service(void);
 #endif
 
 
index e3c8f9152abf7a11ca3e6749994c1b11a4ab26d0..84ff8bdee1e9fca811dd4603a69929593ff3cca9 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.68 2004/04/05 03:02:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.69 2004/06/24 21:03:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -186,4 +186,14 @@ extern unsigned int Log_destination;
 /* Other exported functions */
 extern void DebugFileOpen(void);
 
+/*
+ * Write errors to stderr (or by equal means when stderr is
+ * not available). Used before ereport/elog can be used
+ * safely (memory context, GUC load etc)
+ */
+extern void write_stderr(const char *fmt,...)
+/* This extension allows gcc to check the format string for consistency with
+   the supplied arguments. */
+__attribute__((format(printf, 1, 2)));
+
 #endif   /* ELOG_H */