Replace direct fprintf(stderr) calls by write_stderr(), and cause this

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
This commit is contained in:
Tom Lane 2004-06-24 21:03:42 +00:00
parent b5b9e33564
commit b15f9b08ef
13 changed files with 319 additions and 102 deletions

View 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);
}

View 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);
}

View 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 >$@

View 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

View File

@ -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; x<Groups->GroupCount; 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;
}

View 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);
}

View 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
*
@ -55,6 +55,12 @@
* 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;

View 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);

View 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);
}

View 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);
}

View 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;
}

View 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

View 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 */