2010-05-12 10:19:11 +08:00
|
|
|
/*
|
|
|
|
* util.c
|
|
|
|
*
|
|
|
|
* utility functions
|
2010-07-03 22:23:14 +08:00
|
|
|
*
|
2013-01-02 06:15:01 +08:00
|
|
|
* Copyright (c) 2010-2013, PostgreSQL Global Development Group
|
2010-09-21 04:08:53 +08:00
|
|
|
* contrib/pg_upgrade/util.c
|
2010-05-12 10:19:11 +08:00
|
|
|
*/
|
|
|
|
|
2011-08-27 09:16:24 +08:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
#include "pg_upgrade.h"
|
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
|
2011-04-10 23:42:00 +08:00
|
|
|
LogOpts log_opts;
|
2010-10-20 05:38:16 +08:00
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
/*
|
|
|
|
* report_status()
|
|
|
|
*
|
|
|
|
* Displays the result of an operation (ok, failed, error message,...)
|
|
|
|
*/
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
report_status(eLogType type, const char *fmt,...)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char message[MAX_STRING];
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(message, sizeof(message), fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(type, "%s\n", message);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-01 05:30:13 +08:00
|
|
|
/* force blank output for progress display */
|
|
|
|
void
|
|
|
|
end_progress_output(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In case nothing printed; pass a space so gcc doesn't complain about
|
|
|
|
* empty format string.
|
|
|
|
*/
|
|
|
|
prep_status(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
/*
|
2010-10-20 05:38:16 +08:00
|
|
|
* prep_status
|
2010-05-12 10:19:11 +08:00
|
|
|
*
|
|
|
|
* Displays a message that describes an operation we are about to begin.
|
|
|
|
* We pad the message out to MESSAGE_WIDTH characters so that all of the "ok" and
|
|
|
|
* "failed" indicators line up nicely.
|
|
|
|
*
|
|
|
|
* A typical sequence would look like this:
|
2010-10-20 05:38:16 +08:00
|
|
|
* prep_status("about to flarb the next %d files", fileCount );
|
2010-05-12 10:19:11 +08:00
|
|
|
*
|
|
|
|
* if(( message = flarbFiles(fileCount)) == NULL)
|
2010-10-20 05:38:16 +08:00
|
|
|
* report_status(PG_REPORT, "ok" );
|
2010-05-12 10:19:11 +08:00
|
|
|
* else
|
2011-05-07 09:47:12 +08:00
|
|
|
* pg_log(PG_FATAL, "failed - %s\n", message );
|
2010-05-12 10:19:11 +08:00
|
|
|
*/
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
prep_status(const char *fmt,...)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char message[MAX_STRING];
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(message, sizeof(message), fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (strlen(message) > 0 && message[strlen(message) - 1] == '\n')
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "%s", message);
|
2010-05-12 10:19:11 +08:00
|
|
|
else
|
2012-12-08 01:26:13 +08:00
|
|
|
/* trim strings that don't end in a newline */
|
|
|
|
pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(eLogType type, char *fmt,...)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char message[MAX_STRING];
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(message, sizeof(message), fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
2012-12-08 01:26:13 +08:00
|
|
|
/* PG_VERBOSE and PG_STATUS are only output in verbose mode */
|
2012-08-11 05:14:48 +08:00
|
|
|
/* fopen() on log_opts.internal might have failed, so check it */
|
2012-12-08 01:26:13 +08:00
|
|
|
if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
|
|
|
|
log_opts.internal != NULL)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2012-12-08 01:26:13 +08:00
|
|
|
if (type == PG_STATUS)
|
|
|
|
/* status messages need two leading spaces and a newline */
|
|
|
|
fprintf(log_opts.internal, " %s\n", message);
|
|
|
|
else
|
|
|
|
fprintf(log_opts.internal, "%s", message);
|
2012-03-13 07:47:54 +08:00
|
|
|
fflush(log_opts.internal);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
2012-03-13 07:47:54 +08:00
|
|
|
case PG_VERBOSE:
|
2010-10-20 10:31:17 +08:00
|
|
|
if (log_opts.verbose)
|
2010-05-12 10:19:11 +08:00
|
|
|
printf("%s", _(message));
|
|
|
|
break;
|
|
|
|
|
2012-12-08 01:26:13 +08:00
|
|
|
case PG_STATUS:
|
|
|
|
/* for output to a display, do leading truncation and append \r */
|
|
|
|
if (isatty(fileno(stdout)))
|
|
|
|
/* -2 because we use a 2-space indent */
|
|
|
|
printf(" %s%-*.*s\r",
|
|
|
|
/* prefix with "..." if we do leading truncation */
|
|
|
|
strlen(message) <= MESSAGE_WIDTH - 2 ? "" : "...",
|
|
|
|
MESSAGE_WIDTH - 2, MESSAGE_WIDTH - 2,
|
|
|
|
/* optional leading truncation */
|
|
|
|
strlen(message) <= MESSAGE_WIDTH - 2 ? message :
|
|
|
|
message + strlen(message) - MESSAGE_WIDTH + 3 + 2);
|
|
|
|
else
|
|
|
|
printf(" %s\n", _(message));
|
|
|
|
break;
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
case PG_REPORT:
|
|
|
|
case PG_WARNING:
|
|
|
|
printf("%s", _(message));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PG_FATAL:
|
2011-05-07 09:47:12 +08:00
|
|
|
printf("\n%s", _(message));
|
2011-04-07 04:00:44 +08:00
|
|
|
printf("Failure, exiting\n");
|
|
|
|
exit(1);
|
2010-05-12 10:19:11 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
check_ok(void)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
/* all seems well */
|
2010-10-20 05:38:16 +08:00
|
|
|
report_status(PG_REPORT, "ok");
|
2010-05-12 10:19:11 +08:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* quote_identifier()
|
|
|
|
* Properly double-quote a SQL identifier.
|
|
|
|
*
|
|
|
|
* The result should be pg_free'd, but most callers don't bother because
|
|
|
|
* memory leakage is not a big deal in this program.
|
|
|
|
*/
|
|
|
|
char *
|
2010-10-20 05:38:16 +08:00
|
|
|
quote_identifier(const char *s)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
char *result = pg_malloc(strlen(s) * 2 + 3);
|
2010-05-12 10:19:11 +08:00
|
|
|
char *r = result;
|
|
|
|
|
|
|
|
*r++ = '"';
|
|
|
|
while (*s)
|
|
|
|
{
|
|
|
|
if (*s == '"')
|
|
|
|
*r++ = *s;
|
|
|
|
*r++ = *s;
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
*r++ = '"';
|
|
|
|
*r++ = '\0';
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_user_info()
|
|
|
|
* (copied from initdb.c) find the current user
|
|
|
|
*/
|
|
|
|
int
|
2010-10-20 05:38:16 +08:00
|
|
|
get_user_info(char **user_name)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-07-07 03:19:02 +08:00
|
|
|
int user_id;
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
#ifndef WIN32
|
|
|
|
struct passwd *pw = getpwuid(geteuid());
|
|
|
|
|
|
|
|
user_id = geteuid();
|
|
|
|
#else /* the windows code */
|
|
|
|
struct passwd_win32
|
|
|
|
{
|
|
|
|
int pw_uid;
|
|
|
|
char pw_name[128];
|
|
|
|
} pass_win32;
|
|
|
|
struct passwd_win32 *pw = &pass_win32;
|
|
|
|
DWORD pwname_size = sizeof(pass_win32.pw_name) - 1;
|
|
|
|
|
|
|
|
GetUserName(pw->pw_name, &pwname_size);
|
|
|
|
|
|
|
|
user_id = 1;
|
|
|
|
#endif
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
*user_name = pg_strdup(pw->pw_name);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
return user_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *
|
2012-10-03 05:31:40 +08:00
|
|
|
pg_malloc(size_t size)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2012-10-03 05:31:40 +08:00
|
|
|
void *p;
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2012-10-03 05:31:40 +08:00
|
|
|
/* Avoid unportable behavior of malloc(0) */
|
|
|
|
if (size == 0)
|
|
|
|
size = 1;
|
|
|
|
p = malloc(size);
|
2010-05-12 10:19:11 +08:00
|
|
|
if (p == NULL)
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
|
2010-05-12 10:19:11 +08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2012-07-18 13:13:20 +08:00
|
|
|
void *
|
2012-10-03 05:31:40 +08:00
|
|
|
pg_realloc(void *ptr, size_t size)
|
2012-07-18 13:13:20 +08:00
|
|
|
{
|
2012-10-03 05:31:40 +08:00
|
|
|
void *p;
|
2012-07-18 13:13:20 +08:00
|
|
|
|
2012-10-03 05:31:40 +08:00
|
|
|
/* Avoid unportable behavior of realloc(NULL, 0) */
|
|
|
|
if (ptr == NULL && size == 0)
|
|
|
|
size = 1;
|
|
|
|
p = realloc(ptr, size);
|
2012-07-18 13:13:20 +08:00
|
|
|
if (p == NULL)
|
|
|
|
pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
void
|
2012-10-03 05:31:40 +08:00
|
|
|
pg_free(void *ptr)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2012-10-03 05:31:40 +08:00
|
|
|
if (ptr != NULL)
|
|
|
|
free(ptr);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_strdup(const char *s)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
char *result = strdup(s);
|
|
|
|
|
|
|
|
if (result == NULL)
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* getErrorText()
|
|
|
|
*
|
|
|
|
* Returns the text of the error message for the given error number
|
|
|
|
*
|
|
|
|
* This feature is factored into a separate function because it is
|
|
|
|
* system-dependent.
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
getErrorText(int errNum)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
_dosmaperr(GetLastError());
|
|
|
|
#endif
|
2011-07-21 04:37:17 +08:00
|
|
|
return pg_strdup(strerror(errNum));
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
2010-09-29 05:41:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* str2uint()
|
|
|
|
*
|
|
|
|
* convert string to oid
|
|
|
|
*/
|
|
|
|
unsigned int
|
|
|
|
str2uint(const char *str)
|
|
|
|
{
|
2010-09-29 10:40:25 +08:00
|
|
|
return strtoul(str, NULL, 10);
|
2010-09-29 05:41:03 +08:00
|
|
|
}
|
2011-05-16 22:46:52 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_putenv()
|
|
|
|
*
|
|
|
|
* This is like putenv(), but takes two arguments.
|
|
|
|
* It also does unsetenv() if val is NULL.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pg_putenv(const char *var, const char *val)
|
|
|
|
{
|
|
|
|
if (val)
|
|
|
|
{
|
|
|
|
#ifndef WIN32
|
|
|
|
char *envstr = (char *) pg_malloc(strlen(var) +
|
|
|
|
strlen(val) + 2);
|
|
|
|
|
|
|
|
sprintf(envstr, "%s=%s", var, val);
|
|
|
|
putenv(envstr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not free envstr because it becomes part of the environment on
|
|
|
|
* some operating systems. See port/unsetenv.c::unsetenv.
|
|
|
|
*/
|
|
|
|
#else
|
|
|
|
SetEnvironmentVariableA(var, val);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifndef WIN32
|
|
|
|
unsetenv(var);
|
|
|
|
#else
|
|
|
|
SetEnvironmentVariableA(var, "");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|