Commit fda15b35 authored by Bruce Momjian's avatar Bruce Momjian

As part of the work for making relocatable installs, I have re-factored

all the code that looks for other binaries.  I move FindExec into
port/exec.c (and renamed it to find_my_binary()).  I also added
find_other_binary that looks for another binary in the same directory as
the calling program, and checks the version string.

The only behavior change was that initdb and pg_dump would look in the
hard-coded bindir directory if it can't find the requested binary in the
same directory as the caller.  The new code throws an error.  The old
behavior seemed too error prone for version mismatches.
parent 270c9aa3
......@@ -12011,7 +12011,6 @@ case $host_os in mingw*)
LIBOBJS="$LIBOBJS copydir.$ac_objext"
LIBOBJS="$LIBOBJS gettimeofday.$ac_objext"
LIBOBJS="$LIBOBJS open.$ac_objext"
LIBOBJS="$LIBOBJS pipe.$ac_objext"
LIBOBJS="$LIBOBJS rand.$ac_objext"
cat >>confdefs.h <<\_ACEOF
......
dnl Process this file with autoconf to produce a configure script.
dnl $PostgreSQL: pgsql/configure.in,v 1.345 2004/05/07 00:24:57 tgl Exp $
dnl $PostgreSQL: pgsql/configure.in,v 1.346 2004/05/11 21:57:13 momjian Exp $
dnl
dnl Developers, please strive to achieve this order:
dnl
......@@ -892,7 +892,6 @@ case $host_os in mingw*)
AC_LIBOBJ(copydir)
AC_LIBOBJ(gettimeofday)
AC_LIBOBJ(open)
AC_LIBOBJ(pipe)
AC_LIBOBJ(rand)
AC_DEFINE(USE_PGTZ, 1,
[Define to 1 to use our own timezone library])
......
# -*-makefile-*-
# $PostgreSQL: pgsql/src/Makefile.global.in,v 1.181 2004/05/07 00:24:57 tgl Exp $
# $PostgreSQL: pgsql/src/Makefile.global.in,v 1.182 2004/05/11 21:57:14 momjian Exp $
#------------------------------------------------------------------------------
# All PostgreSQL makefiles include this file and use the variables it sets,
......@@ -339,7 +339,7 @@ endif
#
# substitute implementations of the C library
LIBOBJS = @LIBOBJS@ noblock.o path.o pgsleep.o pgstrcasecmp.o sprompt.o thread.o
LIBOBJS = @LIBOBJS@ exec.o noblock.o path.o pipe.o pgsleep.o pgstrcasecmp.o sprompt.o thread.o
ifneq (,$(LIBOBJS))
LIBS += -lpgport
......
......@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.382 2004/05/06 19:23:25 momjian Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.383 2004/05/11 21:57:14 momjian Exp $
*
* NOTES
*
......@@ -692,7 +692,7 @@ PostmasterMain(int argc, char *argv[])
/*
* On some systems our dynloader code needs the executable's pathname.
*/
if (FindExec(pg_pathname, progname, "postgres") < 0)
if (find_my_binary(pg_pathname, progname, "postgres") < 0)
ereport(FATAL,
(errmsg("%s: could not locate postgres executable",
progname)));
......@@ -3222,7 +3222,7 @@ CreateOptsFile(int argc, char *argv[])
FILE *fp;
int i;
if (FindExec(fullprogname, argv[0], "postmaster") < 0)
if (find_my_binary(fullprogname, argv[0], "postmaster") < 0)
{
elog(LOG, "could not locate postmaster");
return false;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.402 2004/05/07 01:53:41 momjian Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.403 2004/05/11 21:57:14 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -2649,7 +2649,7 @@ PostgresMain(int argc, char *argv[], const char *username)
* On some systems our dynloader code needs the executable's
* pathname. (If under postmaster, this was done already.)
*/
if (FindExec(pg_pathname, argv[0], "postgres") < 0)
if (find_my_binary(pg_pathname, argv[0], "postgres") < 0)
ereport(FATAL,
(errmsg("%s: could not locate postgres executable",
argv[0])));
......
......@@ -4,7 +4,7 @@
# Makefile for utils/init
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.16 2003/11/29 19:52:01 pgsql Exp $
# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.17 2004/05/11 21:57:14 momjian Exp $
#
#-------------------------------------------------------------------------
......@@ -12,7 +12,7 @@ subdir = src/backend/utils/init
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = findbe.o globals.o miscinit.o postinit.o
OBJS = globals.o miscinit.o postinit.o
all: SUBSYS.o
......
......@@ -5,7 +5,7 @@
# Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql/src/bin/initdb/Makefile,v 1.36 2004/04/26 17:40:48 momjian Exp $
# $PostgreSQL: pgsql/src/bin/initdb/Makefile,v 1.37 2004/05/11 21:57:14 momjian Exp $
#
#-------------------------------------------------------------------------
......@@ -13,15 +13,19 @@ subdir = src/bin/initdb
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -DPGBINDIR=\"$(bindir)\" -DPGDATADIR=\"$(datadir)\" -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
override CPPFLAGS := -DPGDATADIR=\"$(datadir)\" -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
OBJS= initdb.o
OBJS= initdb.o \
$(filter exec.o, $(LIBOBJS))
all: submake-libpq submake-libpgport initdb
initdb: $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
install: all installdirs
$(INSTALL_PROGRAM) initdb$(X) $(DESTDIR)$(bindir)/initdb$(X)
......@@ -32,8 +36,8 @@ uninstall:
rm -f $(DESTDIR)$(bindir)/initdb$(X)
clean distclean maintainer-clean:
rm -f initdb$(X) $(OBJS)
rm -f initdb$(X) $(OBJS) exec.c
# ensure that changes in bindir etc. propagate into object file
# ensure that changes in datadir propagate into object file
initdb.o: initdb.c $(top_builddir)/src/Makefile.global
This diff is collapsed.
......@@ -5,7 +5,7 @@
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql/src/bin/pg_dump/Makefile,v 1.46 2004/04/30 20:01:39 momjian Exp $
# $PostgreSQL: pgsql/src/bin/pg_dump/Makefile,v 1.47 2004/05/11 21:57:14 momjian Exp $
#
#-------------------------------------------------------------------------
......@@ -18,10 +18,11 @@ override CPPFLAGS += -DFRONTEND
OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
pg_backup_files.o pg_backup_null.o pg_backup_tar.o \
dumputils.o
PG_DUMPALL_OBJS = $(filter exec.o, $(LIBOBJS))
EXTRA_OBJS = $(top_builddir)/src/backend/parser/keywords.o
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\"
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
all: submake-libpq submake-libpgport submake-backend pg_dump pg_restore pg_dumpall
......@@ -32,8 +33,11 @@ pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(libpq_builddir)/libpq.a
pg_restore: pg_restore.o $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) pg_restore.o $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
pg_dumpall: pg_dumpall.o dumputils.o $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
pg_dumpall: pg_dumpall.o dumputils.o $(PG_DUMPALL_OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(PG_DUMPALL_OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
.PHONY: submake-backend
submake-backend:
......@@ -52,8 +56,4 @@ uninstall:
rm -f $(addprefix $(DESTDIR)$(bindir)/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
clean distclean maintainer-clean:
rm -f pg_dump$(X) pg_restore$(X) pg_dumpall$(X) $(OBJS) pg_dump.o common.o pg_dump_sort.o pg_restore.o pg_dumpall.o
# ensure that changes in bindir etc. propagate into object file
pg_dumpall.o: pg_dumpall.c $(top_builddir)/src/Makefile.global
rm -f pg_dump$(X) pg_restore$(X) pg_dumpall$(X) $(OBJS) pg_dump.o common.o pg_dump_sort.o pg_restore.o pg_dumpall.o exec.c
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.30 2004/01/22 19:09:32 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.31 2004/05/11 21:57:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -35,6 +35,9 @@ int optreset;
#define _(x) gettext((x))
/* version string we expect back from postgres */
#define PG_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
static char *progname;
......@@ -52,10 +55,9 @@ static int runPgDump(const char *dbname);
static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
const char *pguser, bool require_password);
static PGresult *executeQuery(PGconn *conn, const char *query);
static char *findPgDump(const char *argv0);
char *pgdumploc;
char pg_dump_bin[MAXPGPATH];
PQExpBuffer pgdumpopts;
bool output_clean = false;
bool skip_acls = false;
......@@ -75,7 +77,7 @@ main(int argc, char *argv[])
bool globals_only = false;
bool schema_only = false;
PGconn *conn;
int c;
int c, ret;
static struct option long_options[] = {
{"data-only", no_argument, NULL, 'a'},
......@@ -121,7 +123,24 @@ main(int argc, char *argv[])
}
}
pgdumploc = findPgDump(argv[0]);
if ((ret = find_other_binary(pg_dump_bin, argv[0], progname, "pg_dump",
PG_VERSIONSTR)) < 0)
{
if (ret == -1)
fprintf(stderr,
_("The program \"pg_dump\" is needed by %s "
"but was not found in the same directory as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
else
fprintf(stderr,
_("The program \"pg_dump\" was found by %s "
"but was not the same version as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
exit(1);
}
pgdumpopts = createPQExpBuffer();
while ((c = getopt_long(argc, argv, "acdDgh:iop:sU:vWx", long_options, &optindex)) != -1)
......@@ -667,7 +686,7 @@ runPgDump(const char *dbname)
const char *p;
int ret;
appendPQExpBuffer(cmd, "%s %s -Fp '", pgdumploc, pgdumpopts->data);
appendPQExpBuffer(cmd, "\"%s\" %s -Fp '", pg_dump_bin, pgdumpopts->data);
/* Shell quoting is not quite like SQL quoting, so can't use fmtId */
for (p = dbname; *p; p++)
......@@ -792,51 +811,3 @@ executeQuery(PGconn *conn, const char *query)
return res;
}
/*
* Find location of pg_dump executable.
*/
static char *
findPgDump(const char *argv0)
{
char *last;
PQExpBuffer cmd;
static char *result = NULL;
if (result)
return result;
cmd = createPQExpBuffer();
last = last_path_separator(argv0);
if (!last)
appendPQExpBuffer(cmd, "pg_dump");
else
{
char *dir = strdup(argv0);
*(dir + (last - argv0)) = '\0';
appendPQExpBuffer(cmd, "%s/pg_dump", dir);
}
result = strdup(cmd->data);
appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
if (system(cmd->data) == 0)
goto end;
result = BINDIR "/pg_dump";
if (system(BINDIR "/pg_dump -V >/dev/null 2>&1") == 0)
goto end;
fprintf(stderr, _("%s: could not find pg_dump\n"
"Make sure it is in the path or in the same directory as %s.\n"),
progname, progname);
exit(1);
end:
destroyPQExpBuffer(cmd);
return result;
}
......@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.156 2004/04/12 16:19:18 momjian Exp $
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.157 2004/05/11 21:57:15 momjian Exp $
*
* NOTES
* some of the information in this file should be moved to
......@@ -254,10 +254,6 @@ extern void SetSessionAuthorization(AclId userid, bool is_superuser);
extern void SetDataDir(const char *dir);
extern int FindExec(char *full_path, const char *argv0,
const char *binary_name);
extern int CheckPathAccess(char *path, char *name, int open_mode);
/* in utils/misc/superuser.c */
extern bool superuser(void); /* current user is superuser */
extern bool superuser_arg(AclId userid); /* given user is superuser */
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/port.h,v 1.28 2004/05/07 00:24:58 tgl Exp $
* $PostgreSQL: pgsql/src/include/port.h,v 1.29 2004/05/11 21:57:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -27,6 +27,20 @@ extern char *last_path_separator(const char *filename);
extern void canonicalize_path(char *path);
extern char *get_progname(char *argv0);
/* Portable way to find binaries */
extern int find_my_binary(char *full_path, const char *argv0,
const char *binary_name);
extern int find_other_binary(char *retpath, const char *argv0, const char *progname,
char const *target, const char *versionstr);
#if defined(__CYGWIN__) || defined(WIN32)
#define EXE ".exe"
#define DEVNULL "nul"
#else
#define EXE ""
#define DEVNULL "/dev/null"
#endif
/* Portable delay handling */
extern void pg_usleep(long microsec);
......@@ -57,6 +71,7 @@ extern int pgpipe(int handles[2]);
extern int piperead(int s, char* buf, int len);
#define pipewrite(a,b,c) send(a,b,c,0)
#endif
extern int pclose_check(FILE *stream);
#if defined(__MINGW32__) || defined(__CYGWIN__)
/*
......
/*-------------------------------------------------------------------------
*
* findbe.c
* exec.c
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/findbe.c,v 1.42 2004/03/15 16:18:43 momjian Exp $
* $PostgreSQL: pgsql/src/port/exec.c,v 1.1 2004/05/11 21:57:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif
#include <grp.h>
#include <pwd.h>
......@@ -32,16 +37,24 @@
#define S_IXOTH ((S_IXUSR)>>6)
#endif
#ifndef FRONTEND
/* We use only 3-parameter elog calls in this file, for simplicity */
#define log_debug(str, param) elog(DEBUG2, str, param)
#else
#define log_debug(str, param) {} /* do nothing */
#endif
static void win32_make_absolute(char *path);
/*
* ValidateBinary -- validate "path" as a POSTMASTER/POSTGRES executable file
* validate_exec -- validate "path" as an executable file
*
* returns 0 if the file is found and no error is encountered.
* -1 if the regular file "path" does not exist or cannot be executed.
* -2 if the file is otherwise valid but cannot be read.
*/
static int
ValidateBinary(char *path)
validate_exec(char *path)
{
struct stat buf;
......@@ -59,7 +72,8 @@ ValidateBinary(char *path)
#ifdef WIN32
/* Win32 requires a .exe suffix for stat() */
if (strlen(path) >= 4 && strcmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
if (strlen(path) >= strlen(".exe") &&
pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
{
strcpy(path_exe, path);
strcat(path_exe, ".exe");
......@@ -75,22 +89,18 @@ ValidateBinary(char *path)
*/
if (stat(path, &buf) < 0)
{
elog(DEBUG3, "could not stat \"%s\": %m", path);
log_debug("could not stat \"%s\": %m", path);
return -1;
}
if ((buf.st_mode & S_IFMT) != S_IFREG)
{
elog(DEBUG3, "\"%s\" is not a regular file", path);
log_debug("\"%s\" is not a regular file", path);
return -1;
}
/*
* Ensure that we are using an authorized backend.
*
* XXX I'm open to suggestions here. I would like to enforce ownership
* of binaries by user "postgres" but people seem to like to run as
* users other than "postgres"...
* Ensure that we are using an authorized executable.
*/
/*
......@@ -103,23 +113,28 @@ ValidateBinary(char *path)
return is_x ? (is_r ? 0 : -2) : -1;
#else
euid = geteuid();
/* If owned by us, just check owner bits */
if (euid == buf.st_uid)
{
is_r = buf.st_mode & S_IRUSR;
is_x = buf.st_mode & S_IXUSR;
if (!(is_r && is_x))
elog(DEBUG3, "\"%s\" is not user read/execute", path);
log_debug("\"%s\" is not user read/execute", path);
return is_x ? (is_r ? 0 : -2) : -1;
}
pwp = getpwuid(euid);
/* OK, check group bits */
pwp = getpwuid(euid); /* not thread-safe */
if (pwp)
{
if (pwp->pw_gid == buf.st_gid)
if (pwp->pw_gid == buf.st_gid) /* my primary group? */
++in_grp;
else if (pwp->pw_name &&
(gp = getgrgid(buf.st_gid)) != NULL &&
(gp = getgrgid(buf.st_gid)) != NULL && /* not thread-safe */
gp->gr_mem != NULL)
{
{ /* try list of member groups */
for (i = 0; gp->gr_mem[i]; ++i)
{
if (!strcmp(gp->gr_mem[i], pwp->pw_name))
......@@ -134,28 +149,35 @@ ValidateBinary(char *path)
is_r = buf.st_mode & S_IRGRP;
is_x = buf.st_mode & S_IXGRP;
if (!(is_r && is_x))
elog(DEBUG3, "\"%s\" is not group read/execute", path);
log_debug("\"%s\" is not group read/execute", path);
return is_x ? (is_r ? 0 : -2) : -1;
}
}
/* Check "other" bits */
is_r = buf.st_mode & S_IROTH;
is_x = buf.st_mode & S_IXOTH;
if (!(is_r && is_x))
elog(DEBUG3, "\"%s\" is not other read/execute", path);
log_debug("\"%s\" is not other read/execute", path);
return is_x ? (is_r ? 0 : -2) : -1;
#endif
}
/*
* FindExec -- find an absolute path to a valid backend executable
* find_my_binary -- find an absolute path to a valid executable
*
* The reason we have to work so hard to find an absolute path is that
* on some platforms we can't do dynamic loading unless we know the
* executable's location. Also, we need a full path not a relative
* path because we will later change working directory.
*
* This function is not thread-safe because of it calls validate_exec(),
* which calls getgrgid(). This function should be used only in
* non-threaded binaries, not in library routines.
*/
int
FindExec(char *full_path, const char *argv0, const char *binary_name)
find_my_binary(char *full_path, const char *argv0, const char *binary_name)
{
char buf[MAXPGPATH + 2];
char *p;
......@@ -164,13 +186,13 @@ FindExec(char *full_path, const char *argv0, const char *binary_name)
*endp;
/*
* for the postmaster: First try: use the binary that's located in the
* same directory as the postmaster, if it was invoked with an
* explicit path. Presumably the user used an explicit path because it
* First try: use the binary that's located in the
* same directory if it was invoked with an explicit path.
* Presumably the user used an explicit path because it
* wasn't in PATH, and we don't want to use incompatible executables.
*
* This has the neat property that it works for installed binaries, old
* source trees (obj/support/post{master,gres}) and new marc source
* source trees (obj/support/post{master,gres}) and new source
* trees (obj/post{master,gres}) because they all put the two binaries
* in the same place.
*
......@@ -187,13 +209,14 @@ FindExec(char *full_path, const char *argv0, const char *binary_name)
strcat(buf, argv0);
p = last_path_separator(buf);
strcpy(++p, binary_name);
if (ValidateBinary(buf) == 0)
if (validate_exec(buf) == 0)
{
strncpy(full_path, buf, MAXPGPATH);
elog(DEBUG2, "found \"%s\" using argv[0]", full_path);
win32_make_absolute(full_path);
log_debug("found \"%s\" using argv[0]", full_path);
return 0;
}
elog(DEBUG2, "invalid binary \"%s\"", buf);
log_debug("invalid binary \"%s\"", buf);
return -1;
}
......@@ -203,7 +226,7 @@ FindExec(char *full_path, const char *argv0, const char *binary_name)
*/
if ((p = getenv("PATH")) && *p)
{
elog(DEBUG2, "searching PATH for executable");
log_debug("searching PATH for executable%s", "");
path = strdup(p); /* make a modifiable copy */
for (startp = path, endp = strchr(path, PATHSEP);
startp && *startp;
......@@ -220,17 +243,18 @@ FindExec(char *full_path, const char *argv0, const char *binary_name)
strcat(buf, startp);
strcat(buf, "/");
strcat(buf, binary_name);
switch (ValidateBinary(buf))
switch (validate_exec(buf))
{
case 0: /* found ok */
strncpy(full_path, buf, MAXPGPATH);
elog(DEBUG2, "found \"%s\" using PATH", full_path);
win32_make_absolute(full_path);
log_debug("found \"%s\" using PATH", full_path);
free(path);
return 0;
case -1: /* wasn't even a candidate, keep looking */
break;
case -2: /* found but disqualified */
elog(DEBUG2, "could not read binary \"%s\"", buf);
log_debug("could not read binary \"%s\"", buf);
free(path);
return -1;
}
......@@ -240,6 +264,77 @@ FindExec(char *full_path, const char *argv0, const char *binary_name)
free(path);
}
elog(DEBUG2, "could not find a \"%s\" to execute", binary_name);
log_debug("could not find a \"%s\" to execute", binary_name);
return -1;
}
/*
* Find our binary directory, then make sure the "target" executable
* is the proper version.
*/
int find_other_binary(char *retpath, const char *argv0, const char *progname,
char const *target, const char *versionstr)
{
char cmd[MAXPGPATH];
char line[100];
FILE *pgver;
if (find_my_binary(retpath, argv0, progname) < 0)
return -1;
/* Trim off program name and keep just directory */
*last_path_separator(retpath) = '\0';
snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
"/%s%s", target, EXE);
if (validate_exec(retpath))
return -1;
snprintf(cmd, sizeof(cmd), "\"%s\" -V 2>%s", retpath, DEVNULL);
/* flush output buffers in case popen does not... */
fflush(stdout);
fflush(stderr);
if ((pgver = popen(cmd, "r")) == NULL)
return -1;
if (fgets(line, sizeof(line), pgver) == NULL)
perror("fgets failure");
if (pclose_check(pgver))
return -1;
if (strcmp(line, versionstr) != 0)
return -2;
return 0;
}
/*
* Windows doesn't like relative paths to executables (other things work fine)
* so we call its builtin function to expand them. Elsewhere this is a NOOP
*
* Returns malloc'ed memory.
*/
static void
win32_make_absolute(char *path)
{
#ifdef WIN32
char abspath[MAXPGPATH];
if (_fullpath(abspath, path, MAXPGPATH) == NULL)
{
log_debug("Win32 path expansion failed: %s", strerror());
return path;
}
canonicalize_path(abspath);
StrNCpy(path, abspath, MAXPGPATH);
#endif
return;
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/port/path.c,v 1.5 2004/03/09 04:49:02 momjian Exp $
* $PostgreSQL: pgsql/src/port/path.c,v 1.6 2004/05/11 21:57:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -121,3 +121,4 @@ get_progname(char *argv0)
else
return last_path_separator(argv0) + 1;
}
......@@ -10,13 +10,18 @@
* must be replaced with recv/send.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/port/pipe.c,v 1.2 2004/04/19 17:42:59 momjian Exp $
* $PostgreSQL: pgsql/src/port/pipe.c,v 1.3 2004/05/11 21:57:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <sys/wait.h>
#define _(x) gettext((x))
#ifdef WIN32
int
pgpipe(int handles[2])
{
......@@ -63,3 +68,42 @@ int piperead(int s, char* buf, int len)
ret = 0;
return ret;
}
#endif
/*
* pclose() plus useful error reporting
* Is this necessary? bjm 2004-05-11
*/
int
pclose_check(FILE *stream)
{
int exitstatus;
exitstatus = pclose(stream);
if (exitstatus == 0)
return 0; /* all is well */
if (exitstatus == -1)
{
/* pclose() itself failed, and hopefully set errno */
perror("pclose failed");
}
else if (WIFEXITED(exitstatus))
{
fprintf(stderr, _("child process exited with exit code %d\n"),
WEXITSTATUS(exitstatus));
}
else if (WIFSIGNALED(exitstatus))
{
fprintf(stderr, _("child process was terminated by signal %d\n"),
WTERMSIG(exitstatus));
}
else
{
fprintf(stderr, _("child process exited with unrecognized status %d\n"),
exitstatus);
}
return -1;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment