1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
2004-05-11 23:57:15 +02:00
|
|
|
* exec.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2003-08-04 04:40:20 +02:00
|
|
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2004-05-24 22:23:50 +02:00
|
|
|
* $PostgreSQL: pgsql/src/port/exec.c,v 1.14 2004/05/24 20:23:50 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2004-05-11 23:57:15 +02:00
|
|
|
|
|
|
|
#ifndef FRONTEND
|
2001-10-21 05:43:54 +02:00
|
|
|
#include "postgres.h"
|
2004-05-11 23:57:15 +02:00
|
|
|
#else
|
|
|
|
#include "postgres_fe.h"
|
|
|
|
#endif
|
2001-10-21 05:43:54 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
1997-08-27 05:48:50 +02:00
|
|
|
#include <sys/stat.h>
|
2004-05-21 18:06:23 +02:00
|
|
|
#include <sys/wait.h>
|
1996-11-06 11:32:10 +01:00
|
|
|
#include <unistd.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2004-05-21 18:06:23 +02:00
|
|
|
#include "miscadmin.h"
|
2004-05-18 22:18:59 +02:00
|
|
|
|
2004-05-21 18:06:23 +02:00
|
|
|
#define _(x) gettext(x)
|
2004-05-18 22:18:59 +02:00
|
|
|
|
2004-05-21 18:06:23 +02:00
|
|
|
#ifdef FRONTEND
|
|
|
|
#undef pstrdup
|
|
|
|
#define pstrdup(p) strdup(p)
|
|
|
|
#define pfree(p) free(p)
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
/* $PATH (or %PATH%) path separator */
|
|
|
|
#ifdef WIN32
|
|
|
|
#define PATHSEP ';'
|
|
|
|
#else
|
|
|
|
#define PATHSEP ':'
|
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
#ifndef S_IRUSR /* XXX [TRH] should be in a header */
|
|
|
|
#define S_IRUSR S_IREAD
|
|
|
|
#define S_IWUSR S_IWRITE
|
|
|
|
#define S_IXUSR S_IEXEC
|
|
|
|
#define S_IRGRP ((S_IRUSR)>>3)
|
|
|
|
#define S_IWGRP ((S_IWUSR)>>3)
|
|
|
|
#define S_IXGRP ((S_IXUSR)>>3)
|
|
|
|
#define S_IROTH ((S_IRUSR)>>6)
|
|
|
|
#define S_IWOTH ((S_IWUSR)>>6)
|
|
|
|
#define S_IXOTH ((S_IXUSR)>>6)
|
1996-07-09 08:22:35 +02:00
|
|
|
#endif
|
|
|
|
|
2004-05-19 19:15:21 +02:00
|
|
|
#ifndef FRONTEND
|
|
|
|
/* We use only 3-parameter elog calls in this file, for simplicity */
|
|
|
|
#define log_error(str, param) elog(LOG, (str), (param))
|
|
|
|
#else
|
|
|
|
#define log_error(str, param) fprintf(stderr, (str), (param))
|
|
|
|
#endif
|
|
|
|
|
2004-05-21 18:06:23 +02:00
|
|
|
|
2004-05-11 23:57:15 +02:00
|
|
|
static void win32_make_absolute(char *path);
|
2000-06-09 00:38:00 +02:00
|
|
|
|
2004-05-21 18:06:23 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2004-05-11 23:57:15 +02:00
|
|
|
* validate_exec -- validate "path" as an executable file
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* returns 0 if the file is found and no error is encountered.
|
1997-09-07 07:04:48 +02:00
|
|
|
* -1 if the regular file "path" does not exist or cannot be executed.
|
|
|
|
* -2 if the file is otherwise valid but cannot be read.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-09 00:38:00 +02:00
|
|
|
static int
|
2004-05-24 22:23:50 +02:00
|
|
|
validate_exec(const char *path)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
struct stat buf;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-05-15 18:35:30 +02:00
|
|
|
#ifndef WIN32
|
1997-09-08 04:41:22 +02:00
|
|
|
uid_t euid;
|
|
|
|
struct group *gp;
|
|
|
|
struct passwd *pwp;
|
2004-03-15 17:18:43 +01:00
|
|
|
int i;
|
|
|
|
int in_grp = 0;
|
2003-11-12 01:04:10 +01:00
|
|
|
#else
|
2003-11-11 04:53:33 +01:00
|
|
|
char path_exe[MAXPGPATH + 2 + strlen(".exe")];
|
2003-05-15 18:35:30 +02:00
|
|
|
#endif
|
1997-09-08 04:41:22 +02:00
|
|
|
int is_r = 0;
|
|
|
|
int is_x = 0;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2003-11-11 04:53:33 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
/* Win32 requires a .exe suffix for stat() */
|
2004-05-11 23:57:15 +02:00
|
|
|
if (strlen(path) >= strlen(".exe") &&
|
|
|
|
pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
|
2003-11-11 04:53:33 +01:00
|
|
|
{
|
|
|
|
strcpy(path_exe, path);
|
|
|
|
strcat(path_exe, ".exe");
|
|
|
|
path = path_exe;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* Ensure that the file exists and is a regular file.
|
|
|
|
*
|
|
|
|
* XXX if you have a broken system where stat() looks at the symlink
|
|
|
|
* instead of the underlying file, you lose.
|
|
|
|
*/
|
|
|
|
if (stat(path, &buf) < 0)
|
1998-09-01 05:29:17 +02:00
|
|
|
return -1;
|
2001-05-09 21:28:31 +02:00
|
|
|
|
|
|
|
if ((buf.st_mode & S_IFMT) != S_IFREG)
|
1998-09-01 05:29:17 +02:00
|
|
|
return -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
2004-05-11 23:57:15 +02:00
|
|
|
* Ensure that we are using an authorized executable.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that the file is both executable and readable (required for
|
|
|
|
* dynamic loading).
|
|
|
|
*/
|
2003-05-15 18:35:30 +02:00
|
|
|
#ifdef WIN32
|
2003-08-04 02:43:34 +02:00
|
|
|
is_r = buf.st_mode & S_IRUSR;
|
|
|
|
is_x = buf.st_mode & S_IXUSR;
|
|
|
|
return is_x ? (is_r ? 0 : -2) : -1;
|
2003-05-15 18:35:30 +02:00
|
|
|
#else
|
1997-09-07 07:04:48 +02:00
|
|
|
euid = geteuid();
|
2004-05-11 23:57:15 +02:00
|
|
|
|
|
|
|
/* If owned by us, just check owner bits */
|
1997-09-07 07:04:48 +02:00
|
|
|
if (euid == buf.st_uid)
|
|
|
|
{
|
|
|
|
is_r = buf.st_mode & S_IRUSR;
|
|
|
|
is_x = buf.st_mode & S_IXUSR;
|
1998-09-01 05:29:17 +02:00
|
|
|
return is_x ? (is_r ? 0 : -2) : -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2004-05-11 23:57:15 +02:00
|
|
|
|
|
|
|
/* OK, check group bits */
|
|
|
|
|
|
|
|
pwp = getpwuid(euid); /* not thread-safe */
|
1997-09-07 07:04:48 +02:00
|
|
|
if (pwp)
|
|
|
|
{
|
2004-05-11 23:57:15 +02:00
|
|
|
if (pwp->pw_gid == buf.st_gid) /* my primary group? */
|
1997-09-07 07:04:48 +02:00
|
|
|
++in_grp;
|
|
|
|
else if (pwp->pw_name &&
|
2004-05-11 23:57:15 +02:00
|
|
|
(gp = getgrgid(buf.st_gid)) != NULL && /* not thread-safe */
|
2001-10-29 19:06:54 +01:00
|
|
|
gp->gr_mem != NULL)
|
2004-05-11 23:57:15 +02:00
|
|
|
{ /* try list of member groups */
|
1997-09-07 07:04:48 +02:00
|
|
|
for (i = 0; gp->gr_mem[i]; ++i)
|
|
|
|
{
|
|
|
|
if (!strcmp(gp->gr_mem[i], pwp->pw_name))
|
|
|
|
{
|
|
|
|
++in_grp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (in_grp)
|
|
|
|
{
|
|
|
|
is_r = buf.st_mode & S_IRGRP;
|
|
|
|
is_x = buf.st_mode & S_IXGRP;
|
1998-09-01 05:29:17 +02:00
|
|
|
return is_x ? (is_r ? 0 : -2) : -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
2004-05-11 23:57:15 +02:00
|
|
|
|
|
|
|
/* Check "other" bits */
|
1997-09-07 07:04:48 +02:00
|
|
|
is_r = buf.st_mode & S_IROTH;
|
|
|
|
is_x = buf.st_mode & S_IXOTH;
|
1998-09-01 05:29:17 +02:00
|
|
|
return is_x ? (is_r ? 0 : -2) : -1;
|
2004-05-11 23:57:15 +02:00
|
|
|
|
2003-05-15 18:35:30 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-05-12 15:38:49 +02:00
|
|
|
* find_my_exec -- find an absolute path to a valid executable
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* The reason we have to work so hard to find an absolute path is that
|
2001-10-21 05:43:54 +02:00
|
|
|
* 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.
|
2004-05-11 23:57:15 +02:00
|
|
|
*
|
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
2004-05-20 17:38:11 +02:00
|
|
|
find_my_exec(const char *argv0, char *retpath)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2004-05-20 17:35:41 +02:00
|
|
|
char cwd[MAXPGPATH];
|
1997-09-08 04:41:22 +02:00
|
|
|
char *p;
|
|
|
|
char *path,
|
|
|
|
*startp,
|
|
|
|
*endp;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-05-20 17:35:41 +02:00
|
|
|
if (!getcwd(cwd, MAXPGPATH))
|
|
|
|
cwd[0] = '\0';
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2004-05-11 23:57:15 +02:00
|
|
|
* 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
|
1997-09-07 07:04:48 +02:00
|
|
|
* wasn't in PATH, and we don't want to use incompatible executables.
|
|
|
|
*
|
2004-05-14 00:45:04 +02:00
|
|
|
* For the binary: First try: if we're given some kind of path, use it
|
1998-09-01 06:40:42 +02:00
|
|
|
* (making sure that a relative path is made absolute before returning
|
|
|
|
* it).
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2004-05-14 00:45:04 +02:00
|
|
|
/* Does argv0 have a separator? */
|
2004-05-20 17:35:41 +02:00
|
|
|
if ((p = last_path_separator(argv0)))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2004-05-14 00:45:04 +02:00
|
|
|
if (*++p == '\0')
|
|
|
|
{
|
2004-05-19 19:15:21 +02:00
|
|
|
log_error("argv[0] ends with a path separator \"%s\"", argv0);
|
2004-05-14 00:45:04 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-05-20 17:35:41 +02:00
|
|
|
|
|
|
|
if (is_absolute_path(argv0))
|
2004-05-20 17:38:11 +02:00
|
|
|
StrNCpy(retpath, argv0, MAXPGPATH);
|
2004-05-20 17:35:41 +02:00
|
|
|
else
|
2004-05-20 17:38:11 +02:00
|
|
|
snprintf(retpath, MAXPGPATH, "%s/%s", cwd, argv0);
|
2004-05-20 17:35:41 +02:00
|
|
|
|
2004-05-20 17:38:11 +02:00
|
|
|
canonicalize_path(retpath);
|
|
|
|
if (validate_exec(retpath) == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2004-05-20 17:38:11 +02:00
|
|
|
win32_make_absolute(retpath);
|
1998-09-01 05:29:17 +02:00
|
|
|
return 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2004-05-18 22:18:59 +02:00
|
|
|
else
|
|
|
|
{
|
2004-05-20 17:38:11 +02:00
|
|
|
log_error("invalid binary \"%s\"", retpath);
|
2004-05-18 22:18:59 +02:00
|
|
|
return -1;
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-05-20 17:35:41 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
/* Win32 checks the current directory first for names without slashes */
|
|
|
|
if (validate_exec(argv0) == 0)
|
|
|
|
{
|
2004-05-20 17:38:11 +02:00
|
|
|
snprintf(retpath, MAXPGPATH, "%s/%s", cwd, argv0);
|
|
|
|
win32_make_absolute(retpath);
|
2004-05-20 17:35:41 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* Second try: since no explicit path was supplied, the user must have
|
|
|
|
* been relying on PATH. We'll use the same PATH.
|
|
|
|
*/
|
|
|
|
if ((p = getenv("PATH")) && *p)
|
|
|
|
{
|
2004-05-21 18:06:23 +02:00
|
|
|
path = pstrdup(p); /* make a modifiable copy */
|
Briefly,
* configure + Makefile changes
* shared memory attaching in EXEC_BACKEND case (+ minor fix for apparent
cygwin bug under cygwin/EXEC_BACKEND case only)
* PATH env var separator differences
* missing win32 rand functions added
* placeholder replacements for sync etc under port.h
To those who are really interested, and there are a few of you: the attached
patch + file will allow the source base to be compiled (and, for some
definition, "run") under MingW, with the following caveats (I wanted to
first properly fix all but the last of these, but y'all won't quit asking
for a patch :-):
* child death: SIGCHLD not yet sent, so as a minimum, you'll need to
put in some sort of delay after StartupDatabase, and handle setting
StartupPID to 0 etc (ie. the stuff the reaper() signal function is supposed
to do)
* dirmod.c: comment out the elog calls
* dfmgr.c: some hackage required to substitute_libpath_macro
* slru/xact.c: comment out the errno checking after the readdir
(fixed by next version of MingW)
Again, this is only if you *really* want to see postgres compile and start,
and is a nice leg-up for working on the other Win32 TODO list items. Just
don't expect too much else from it at this point...
Claudio Natoli
2004-02-02 01:11:31 +01:00
|
|
|
for (startp = path, endp = strchr(path, PATHSEP);
|
1997-09-07 07:04:48 +02:00
|
|
|
startp && *startp;
|
Briefly,
* configure + Makefile changes
* shared memory attaching in EXEC_BACKEND case (+ minor fix for apparent
cygwin bug under cygwin/EXEC_BACKEND case only)
* PATH env var separator differences
* missing win32 rand functions added
* placeholder replacements for sync etc under port.h
To those who are really interested, and there are a few of you: the attached
patch + file will allow the source base to be compiled (and, for some
definition, "run") under MingW, with the following caveats (I wanted to
first properly fix all but the last of these, but y'all won't quit asking
for a patch :-):
* child death: SIGCHLD not yet sent, so as a minimum, you'll need to
put in some sort of delay after StartupDatabase, and handle setting
StartupPID to 0 etc (ie. the stuff the reaper() signal function is supposed
to do)
* dirmod.c: comment out the elog calls
* dfmgr.c: some hackage required to substitute_libpath_macro
* slru/xact.c: comment out the errno checking after the readdir
(fixed by next version of MingW)
Again, this is only if you *really* want to see postgres compile and start,
and is a nice leg-up for working on the other Win32 TODO list items. Just
don't expect too much else from it at this point...
Claudio Natoli
2004-02-02 01:11:31 +01:00
|
|
|
startp = endp + 1, endp = strchr(startp, PATHSEP))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
if (startp == endp) /* it's a "::" */
|
|
|
|
continue;
|
|
|
|
if (endp)
|
|
|
|
*endp = '\0';
|
2004-05-20 17:35:41 +02:00
|
|
|
|
|
|
|
if (is_absolute_path(startp))
|
2004-05-20 17:38:11 +02:00
|
|
|
snprintf(retpath, MAXPGPATH, "%s/%s", startp, argv0);
|
2004-05-20 17:35:41 +02:00
|
|
|
else
|
2004-05-20 17:38:11 +02:00
|
|
|
snprintf(retpath, MAXPGPATH, "%s/%s/%s", cwd, startp, argv0);
|
2004-05-20 17:35:41 +02:00
|
|
|
|
2004-05-20 17:38:11 +02:00
|
|
|
canonicalize_path(retpath);
|
|
|
|
switch (validate_exec(retpath))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case 0: /* found ok */
|
2004-05-20 17:38:11 +02:00
|
|
|
win32_make_absolute(retpath);
|
2004-05-21 18:06:23 +02:00
|
|
|
pfree(path);
|
1998-09-01 05:29:17 +02:00
|
|
|
return 0;
|
1997-09-08 04:41:22 +02:00
|
|
|
case -1: /* wasn't even a candidate, keep looking */
|
|
|
|
break;
|
|
|
|
case -2: /* found but disqualified */
|
2004-05-20 17:38:11 +02:00
|
|
|
log_error("could not read binary \"%s\"", retpath);
|
2004-05-21 18:06:23 +02:00
|
|
|
pfree(path);
|
1998-09-01 05:29:17 +02:00
|
|
|
return -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
if (!endp) /* last one */
|
|
|
|
break;
|
|
|
|
}
|
2004-05-21 18:06:23 +02:00
|
|
|
pfree(path);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2004-05-19 19:15:21 +02:00
|
|
|
log_error("could not find a \"%s\" to execute", argv0);
|
1998-09-01 05:29:17 +02:00
|
|
|
return -1;
|
2004-05-17 16:35:34 +02:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* Win32 has a native way to find the executable name, but the above
|
|
|
|
* method works too.
|
|
|
|
*/
|
2004-05-20 17:38:11 +02:00
|
|
|
if (GetModuleFileName(NULL, retpath, MAXPGPATH) == 0)
|
2004-05-20 17:35:41 +02:00
|
|
|
log_error("GetModuleFileName failed (%i)",(int)GetLastError());
|
2004-05-17 16:35:34 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2004-05-11 23:57:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find our binary directory, then make sure the "target" executable
|
|
|
|
* is the proper version.
|
|
|
|
*/
|
2004-05-21 18:06:23 +02:00
|
|
|
int
|
|
|
|
find_other_exec(const char *argv0, const char *target,
|
|
|
|
const char *versionstr, char *retpath)
|
2004-05-11 23:57:15 +02:00
|
|
|
{
|
|
|
|
char cmd[MAXPGPATH];
|
|
|
|
char line[100];
|
|
|
|
FILE *pgver;
|
|
|
|
|
2004-05-14 19:04:48 +02:00
|
|
|
if (find_my_exec(argv0, retpath) < 0)
|
2004-05-11 23:57:15 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-18 22:18:59 +02:00
|
|
|
/*
|
|
|
|
* pclose() plus useful error reporting
|
|
|
|
* Is this necessary? bjm 2004-05-11
|
|
|
|
* It is better here because pipe.c has win32 backend linkage.
|
|
|
|
*/
|
|
|
|
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))
|
|
|
|
{
|
2004-05-19 19:15:21 +02:00
|
|
|
log_error(_("child process exited with exit code %d\n"),
|
2004-05-18 22:18:59 +02:00
|
|
|
WEXITSTATUS(exitstatus));
|
|
|
|
}
|
|
|
|
else if (WIFSIGNALED(exitstatus))
|
|
|
|
{
|
2004-05-19 19:15:21 +02:00
|
|
|
log_error(_("child process was terminated by signal %d\n"),
|
2004-05-18 22:18:59 +02:00
|
|
|
WTERMSIG(exitstatus));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-05-19 19:15:21 +02:00
|
|
|
log_error(_("child process exited with unrecognized status %d\n"),
|
2004-05-18 22:18:59 +02:00
|
|
|
exitstatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-11 23:57:15 +02:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
win32_make_absolute(char *path)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
char abspath[MAXPGPATH];
|
|
|
|
|
|
|
|
if (_fullpath(abspath, path, MAXPGPATH) == NULL)
|
|
|
|
{
|
2004-05-21 18:06:23 +02:00
|
|
|
log_error("Win32 path expansion failed: %s", strerror(errno));
|
2004-05-18 05:36:45 +02:00
|
|
|
StrNCpy(abspath, path, MAXPGPATH);
|
2004-05-11 23:57:15 +02:00
|
|
|
}
|
|
|
|
canonicalize_path(abspath);
|
|
|
|
|
|
|
|
StrNCpy(path, abspath, MAXPGPATH);
|
|
|
|
#endif
|
|
|
|
}
|