diff --git a/configure b/configure index 9403fa4537..9deb026c4a 100755 --- a/configure +++ b/configure @@ -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 diff --git a/configure.in b/configure.in index 1cad0dbe28..8947a81583 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ 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]) diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 9dda9bf8b0..e87c1ba8ef 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -1,5 +1,5 @@ # -*-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 diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 1d781d0bb5..e3df517d1e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -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; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 89ec36287c..caeef3cd57 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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]))); diff --git a/src/backend/utils/init/Makefile b/src/backend/utils/init/Makefile index d5dc43ca5c..8415de8b2a 100644 --- a/src/backend/utils/init/Makefile +++ b/src/backend/utils/init/Makefile @@ -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 diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile index 5bcaae92f7..d709f60766 100644 --- a/src/bin/initdb/Makefile +++ b/src/bin/initdb/Makefile @@ -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 diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 7b03c404ea..fa8bf28da8 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -25,10 +25,6 @@ * * template0 is made just by copying the completed template1. * - * - * TODO: - * - clean up find_postgres code and return values - * * Note: * The program has some memory leakage - it isn't worth cleaning it up. * @@ -43,7 +39,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * Portions taken from FreeBSD. * - * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.26 2004/05/10 20:51:58 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.27 2004/05/11 21:57:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -52,7 +48,6 @@ #include #include -#include #include #include #include @@ -78,7 +73,6 @@ int optreset; * Note that "datadir" is not the directory we're going to initialize, * it's merely how Autoconf names PREFIX/share. */ -char *bindir = PGBINDIR; char *datadir = PGDATADIR; /* values to be obtained from arguments */ @@ -100,7 +94,6 @@ bool show_setting = false; /* internal vars */ char *progname; -char *self_path; char *postgres; char *encodingid = "0"; char *bki_file; @@ -135,25 +128,9 @@ static const char *boot_options = "-F"; static const char *backend_options = "-F -O -c search_path=pg_catalog -c exit_on_error=true"; -/* platform specific path stuff */ -#if defined(__CYGWIN__) || defined(WIN32) -#define EXE ".exe" -#define DEVNULL "nul" -#else -#define EXE "" -#define DEVNULL "/dev/null" -#endif - - -/* detected path to postgres and (we assume) friends */ -char *pgpath; - -/* forward declare all our functions */ -#ifdef WIN32 -static char *expanded_path(char *); -#else -#define expanded_path(x) (x) -#endif +/* path to 'initdb' binary directory */ +char bindir[MAXPGPATH]; +char backendbin[MAXPGPATH]; static void *xmalloc(size_t size); static char *xstrdup(const char *s); @@ -161,7 +138,6 @@ static bool rmtree(char *path, bool rmtopdir); static char **replace_token(char **lines, char *token, char *replacement); static char **readfile(char *path); static void writefile(char *path, char **lines); -static void pclose_check(FILE *stream); static int mkdir_p(char *path, mode_t omode); static void exit_nicely(void); static char *get_id(void); @@ -171,8 +147,6 @@ static int check_data_dir(void); static bool mkdatadir(char *subdir); static void set_input(char **dest, char *filename); static void check_input(char *path); -static int find_postgres(char *path); -static int set_paths(void); static void set_short_version(char *short_version, char *extrapath); static void set_null_conf(void); static void test_connections(void); @@ -216,7 +190,8 @@ do { \ #define PG_CMD_CLOSE \ do { \ - pclose_check(pg); \ + if (pclose_check(pg)) \ + exit_nicely(); \ } while (0) #define PG_CMD_PUTLINE \ @@ -437,41 +412,6 @@ writefile(char *path, char **lines) exit_nicely(); } -/* pclose() plus useful error reporting */ -static void -pclose_check(FILE *stream) -{ - int exitstatus; - - exitstatus = pclose(stream); - - if (exitstatus == 0) - return; /* all is well */ - - if (exitstatus == -1) - { - /* pclose() itself failed, and hopefully set errno */ - perror("pclose failed"); - } - else if (WIFEXITED(exitstatus)) - { - fprintf(stderr, _("%s: child process exited with exit code %d\n"), - progname, WEXITSTATUS(exitstatus)); - } - else if (WIFSIGNALED(exitstatus)) - { - fprintf(stderr, _("%s: child process was terminated by signal %d\n"), - progname, WTERMSIG(exitstatus)); - } - else - { - fprintf(stderr, _("%s: child process exited with unrecognized status %d\n"), - progname, exitstatus); - } - - exit_nicely(); -} - /* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */ /* @@ -814,193 +754,6 @@ check_input(char *path) } -/* - * TODO - clean this up and handle the errors properly - * don't overkill - */ -#define FIND_SUCCESS 0 -#define FIND_NOT_FOUND 1 -#define FIND_STAT_ERR 2 -#define FIND_NOT_REGFILE 3 -#define FIND_BAD_PERM 4 -#define FIND_EXEC_ERR 5 -#define FIND_WRONG_VERSION 6 - -/* - * see if there is a postgres executable in the given path, and giving the - * right version number - */ -static int -find_postgres(char *path) -{ - char fn[MAXPGPATH]; - char cmd[MAXPGPATH]; - char line[100]; - -#ifndef WIN32 - int permmask = S_IROTH | S_IXOTH; -#endif - - struct stat statbuf; - FILE *pgver; - int plen = strlen(path); - - if (plen > 0 && path[plen - 1] != '/') - snprintf(fn, sizeof(fn), "%s/postgres%s", path, EXE); - else - snprintf(fn, sizeof(fn), "%spostgres%s", path, EXE); - - if (stat(fn, &statbuf) != 0) - { - if (errno == ENOENT) - return FIND_NOT_FOUND; - else - return FIND_STAT_ERR; - } - if (!S_ISREG(statbuf.st_mode)) - return FIND_NOT_REGFILE; - -#ifndef WIN32 - - /* - * Only unix requires this test, on WIN32 an .exe file should be - * executable - */ - if ((statbuf.st_mode & permmask) != permmask) - return FIND_BAD_PERM; -#endif - - snprintf(cmd, sizeof(cmd), "\"%s/postgres\" -V 2>%s", path, DEVNULL); - - /* flush output buffers in case popen does not... */ - fflush(stdout); - fflush(stderr); - - if ((pgver = popen(cmd, "r")) == NULL) - return FIND_EXEC_ERR; - - if (fgets(line, sizeof(line), pgver) == NULL) - perror("fgets failure"); - - pclose_check(pgver); - - if (strcmp(line, PG_VERSIONSTR) != 0) - return FIND_WRONG_VERSION; - - return FIND_SUCCESS; -} - -/* - * 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 - */ -#ifdef WIN32 -static char * -expanded_path(char *path) -{ - char abspath[MAXPGPATH]; - - if (_fullpath(abspath, path, sizeof(abspath)) == NULL) - { - perror("expanded path"); - return path; - } - canonicalize_path(abspath); - return xstrdup(abspath); -} -#endif - -/* - * set the paths pointing to postgres - * - * look for it in the same place we found this program, or in the environment - * path, or in the configured bindir. - * We do it in this order because during upgrades users might move - * their trees to backup places, so the hard-wired bindir might be inaccurate. - * - * XXX this needs work, as its error handling is vastly inferior to the - * shell-script version, in particular the case where a postgres executable - * is failing - */ -static int -set_paths(void) -{ - if (testpath && !self_path) - { - char *path, - *cursor; - int pathlen, - i, - pathsegs; - char **pathbits; - char buf[MAXPGPATH]; - struct stat statbuf; - - path = xstrdup(getenv("PATH")); - pathlen = strlen(path); - - for (i = 0, pathsegs = 1; i < pathlen; i++) - { - if (path[i] == PATHSEP) - pathsegs++; - } - - pathbits = (char **) xmalloc(pathsegs * sizeof(char *)); - for (i = 0, pathsegs = 0, cursor = path; i <= pathlen; i++) - { - if (path[i] == PATHSEP || path[i] == 0) - { - path[i] = 0; - if (strlen(cursor) == 0) - { - /* empty path segment means current directory */ - pathbits[pathsegs] = xstrdup("."); - } - else - { - canonicalize_path(cursor); - pathbits[pathsegs] = cursor; - } - pathsegs++; - cursor = path + i + 1; - } - } - - for (i = 0; i < pathsegs; i++) - { - snprintf(buf, sizeof(buf), "%s/%s%s", pathbits[i], progname, EXE); - if (stat(buf, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) - { - self_path = pathbits[i]; - break; - } - } - } - - if (testpath && self_path && - (find_postgres(expanded_path(self_path)) == 0)) - { - /* we found postgres on out own path */ - pgpath = expanded_path(self_path); - } - else - { - /* look in the hardcoded bindir */ - int res; - char *cbindir; - - cbindir = xstrdup(bindir); - canonicalize_path(cbindir); - res = find_postgres(expanded_path(cbindir)); - if (res == 0) - pgpath = expanded_path(cbindir); - else - return 1; - } - - return 0; -} - /* * write out the PG_VERSION file in the data dir, or its subdirectory * if extrapath is not NULL @@ -1063,10 +816,10 @@ test_connections(void) for (i = 0; i < len; i++) { snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" -boot -x0 %s " + "\"%s\" -boot -x0 %s " "-c shared_buffers=%d -c max_connections=%d template1 " "<%s >%s 2>&1", - pgpath, boot_options, + backendbin, boot_options, conns[i] * 5, conns[i], DEVNULL, DEVNULL); status = system(cmd); @@ -1099,10 +852,10 @@ test_buffers(void) for (i = 0; i < len; i++) { snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" -boot -x0 %s " + "\"%s\" -boot -x0 %s " "-c shared_buffers=%d -c max_connections=%d template1 " "<%s >%s 2>&1", - pgpath, boot_options, + backendbin, boot_options, bufs[i], n_connections, DEVNULL, DEVNULL); status = system(cmd); @@ -1250,8 +1003,8 @@ bootstrap_template1(char *short_version) unsetenv("PGCLIENTENCODING"); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" -boot -x1 %s %s template1", - pgpath, boot_options, talkargs); + "\"%s\" -boot -x1 %s %s template1", + backendbin, boot_options, talkargs); PG_CMD_OPEN; @@ -1300,8 +1053,8 @@ setup_shadow(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1340,8 +1093,8 @@ get_set_pwd(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1394,8 +1147,8 @@ unlimit_systables(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1467,8 +1220,8 @@ setup_depend(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1500,8 +1253,8 @@ setup_sysviews(void) * We use -N here to avoid backslashing stuff in system_views.sql */ snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s -N template1 >%s", - pgpath, backend_options, + "\"%s\" %s -N template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1532,8 +1285,8 @@ setup_description(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1580,8 +1333,8 @@ setup_conversion(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1636,8 +1389,8 @@ setup_privileges(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1699,8 +1452,8 @@ setup_schema(void) * We use -N here to avoid backslashing stuff in information_schema.sql */ snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s -N template1 >%s", - pgpath, backend_options, + "\"%s\" %s -N template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1716,8 +1469,8 @@ setup_schema(void) PG_CMD_CLOSE; snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1756,8 +1509,8 @@ vacuum_db(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -1812,8 +1565,8 @@ make_template0(void) fflush(stdout); snprintf(cmd, sizeof(cmd), - "\"%s/postgres\" %s template1 >%s", - pgpath, backend_options, + "\"%s\" %s template1 >%s", + backendbin, backend_options, DEVNULL); PG_CMD_OPEN; @@ -2043,48 +1796,17 @@ main(int argc, char *argv[]) }; int c, - i; + i, + ret; int option_index; char *short_version; char *pgdenv; /* PGDATA value got from sent to * environment */ char *subdirs[] = {"global", "pg_xlog", "pg_clog", "base", "base/1"}; - char *lastsep; - char *carg0; -#if defined(__CYGWIN__) || defined(WIN32) - char *exe; /* location of exe suffix in progname */ -#endif - init_nls(); - /* parse argv[0] - detect explicit path if there was one */ - carg0 = xstrdup(argv[0]); - canonicalize_path(carg0); - - lastsep = strrchr(carg0, '/'); - progname = lastsep ? xstrdup(lastsep + 1) : carg0; - -#if defined(__CYGWIN__) || defined(WIN32) - if (strlen(progname) > 4 && - (exe = progname + (strlen(progname) - 4)) && - stricmp(exe, EXE) == 0) - { - /* strip .exe suffix, regardless of case */ - *exe = '\0'; - } -#endif - - if (lastsep) - { - self_path = carg0; - *lastsep = '\0'; - } - else - { - /* no path known to ourselves from argv[0] */ - self_path = NULL; - } + progname = get_progname(argv[0]); if (argc > 1) { @@ -2210,16 +1932,28 @@ main(int argc, char *argv[]) sprintf(pgdenv, "PGDATA=%s", pg_data); putenv(pgdenv); - if (set_paths() != 0) + if ((ret = find_other_binary(backendbin, argv[0], progname, "postgres", + PG_VERSIONSTR)) < 0) { - fprintf(stderr, - _("The program \"postgres\" is needed by %s " - "but was not found in \n" - "the directory \"%s\". Check your installation.\n"), - progname, bindir); + if (ret == -1) + fprintf(stderr, + _("The program \"postgres\" 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 \"postgres\" was found by %s " + "but was not the same version as \"%s\".\n" + "Check your installation.\n"), + progname, progname); exit(1); } + /* store binary directory */ + strcpy(bindir, backendbin); + *last_path_separator(bindir) = '\0'; + if ((short_version = get_short_version()) == NULL) { fprintf(stderr, _("%s: could not determine valid short version string\n"), progname); @@ -2255,7 +1989,7 @@ main(int argc, char *argv[]) "POSTGRES_DESCR=%s\nPOSTGRESQL_CONF_SAMPLE=%s\n" "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n", PG_VERSION, - pg_data, datadir, pgpath, + pg_data, datadir, bindir, encoding, encodingid, username, bki_file, desc_file, conf_file, @@ -2448,8 +2182,8 @@ main(int argc, char *argv[]) " %s%s%s/postmaster -D %s%s%s\n" "or\n" " %s%s%s/pg_ctl -D %s%s%s -l logfile start\n\n"), - QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH, - QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH); + QUOTE_PATH, bindir, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH, + QUOTE_PATH, bindir, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH); return 0; } diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 59722363a5..414194cd30 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -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 diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index f15ddc206d..0817cabfb9 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.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; -} diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 76f2d086ae..fc312b3d74 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -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 */ diff --git a/src/include/port.h b/src/include/port.h index 2f5123483b..177c82f8c4 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -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__) /* diff --git a/src/backend/utils/init/findbe.c b/src/port/exec.c similarity index 55% rename from src/backend/utils/init/findbe.c rename to src/port/exec.c index 035ff0553a..27e66cc0c8 100644 --- a/src/backend/utils/init/findbe.c +++ b/src/port/exec.c @@ -1,17 +1,22 @@ /*------------------------------------------------------------------------- * - * 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 #include @@ -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; +} + diff --git a/src/port/path.c b/src/port/path.c index 3f672d5b22..965d63ea33 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -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; } + diff --git a/src/port/pipe.c b/src/port/pipe.c index 4a707f7335..9fdab8ca73 100644 --- a/src/port/pipe.c +++ b/src/port/pipe.c @@ -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 + +#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; +}