1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/findbe.c,v 1.26 2002/02/08 16:30:11 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include <sys/types.h>
22 #include "miscadmin.h"
24 #ifndef S_IRUSR /* XXX [TRH] should be in a header */
25 #define S_IRUSR S_IREAD
26 #define S_IWUSR S_IWRITE
27 #define S_IXUSR S_IEXEC
28 #define S_IRGRP ((S_IRUSR)>>3)
29 #define S_IWGRP ((S_IWUSR)>>3)
30 #define S_IXGRP ((S_IXUSR)>>3)
31 #define S_IROTH ((S_IRUSR)>>6)
32 #define S_IWOTH ((S_IWUSR)>>6)
33 #define S_IXOTH ((S_IXUSR)>>6)
38 * ValidateBinary -- validate "path" as a POSTMASTER/POSTGRES executable file
40 * returns 0 if the file is found and no error is encountered.
41 * -1 if the regular file "path" does not exist or cannot be executed.
42 * -2 if the file is otherwise valid but cannot be read.
45 ValidateBinary(char *path)
57 * Ensure that the file exists and is a regular file.
59 * XXX if you have a broken system where stat() looks at the symlink
60 * instead of the underlying file, you lose.
62 if (stat(path, &buf) < 0)
65 fprintf(stderr, "ValidateBinary: can't stat \"%s\"\n",
70 if ((buf.st_mode & S_IFMT) != S_IFREG)
73 fprintf(stderr, "ValidateBinary: \"%s\" is not a regular file\n",
79 * Ensure that we are using an authorized backend.
81 * XXX I'm open to suggestions here. I would like to enforce ownership
82 * of binaries by user "postgres" but people seem to like to run as
83 * users other than "postgres"...
87 * Ensure that the file is both executable and readable (required for
91 if (euid == buf.st_uid)
93 is_r = buf.st_mode & S_IRUSR;
94 is_x = buf.st_mode & S_IXUSR;
95 if (DebugLvl > 1 && !(is_r && is_x))
96 fprintf(stderr, "ValidateBinary: \"%s\" is not user read/execute\n",
98 return is_x ? (is_r ? 0 : -2) : -1;
100 pwp = getpwuid(euid);
103 if (pwp->pw_gid == buf.st_gid)
105 else if (pwp->pw_name &&
106 (gp = getgrgid(buf.st_gid)) != NULL &&
109 for (i = 0; gp->gr_mem[i]; ++i)
111 if (!strcmp(gp->gr_mem[i], pwp->pw_name))
120 is_r = buf.st_mode & S_IRGRP;
121 is_x = buf.st_mode & S_IXGRP;
122 if (DebugLvl > 1 && !(is_r && is_x))
123 fprintf(stderr, "ValidateBinary: \"%s\" is not group read/execute\n",
125 return is_x ? (is_r ? 0 : -2) : -1;
128 is_r = buf.st_mode & S_IROTH;
129 is_x = buf.st_mode & S_IXOTH;
130 if (DebugLvl > 1 && !(is_r && is_x))
131 fprintf(stderr, "ValidateBinary: \"%s\" is not other read/execute\n",
133 return is_x ? (is_r ? 0 : -2) : -1;
137 * FindExec -- find an absolute path to a valid backend executable
139 * The reason we have to work so hard to find an absolute path is that
140 * on some platforms we can't do dynamic loading unless we know the
141 * executable's location. Also, we need a full path not a relative
142 * path because we will later change working directory.
145 FindExec(char *full_path, const char *argv0, const char *binary_name)
147 char buf[MAXPGPATH + 2];
154 * for the postmaster: First try: use the binary that's located in the
155 * same directory as the postmaster, if it was invoked with an
156 * explicit path. Presumably the user used an explicit path because it
157 * wasn't in PATH, and we don't want to use incompatible executables.
159 * This has the neat property that it works for installed binaries, old
160 * source trees (obj/support/post{master,gres}) and new marc source
161 * trees (obj/post{master,gres}) because they all put the two binaries
164 * for the binary: First try: if we're given some kind of path, use it
165 * (making sure that a relative path is made absolute before returning
168 if (argv0 && (p = strrchr(argv0, '/')) && *++p)
170 if (*argv0 == '/' || !getcwd(buf, MAXPGPATH))
175 p = strrchr(buf, '/');
176 strcpy(++p, binary_name);
177 if (ValidateBinary(buf) == 0)
179 strncpy(full_path, buf, MAXPGPATH);
181 fprintf(stderr, "FindExec: found \"%s\" using argv[0]\n",
185 fprintf(stderr, "FindExec: invalid binary \"%s\"\n",
191 * Second try: since no explicit path was supplied, the user must have
192 * been relying on PATH. We'll use the same PATH.
194 if ((p = getenv("PATH")) && *p)
197 fprintf(stderr, "FindExec: searching PATH ...\n");
198 path = strdup(p); /* make a modifiable copy */
199 for (startp = path, endp = strchr(path, ':');
201 startp = endp + 1, endp = strchr(startp, ':'))
203 if (startp == endp) /* it's a "::" */
207 if (*startp == '/' || !getcwd(buf, MAXPGPATH))
213 strcat(buf, binary_name);
214 switch (ValidateBinary(buf))
216 case 0: /* found ok */
217 strncpy(full_path, buf, MAXPGPATH);
219 fprintf(stderr, "FindExec: found \"%s\" using PATH\n",
223 case -1: /* wasn't even a candidate, keep looking */
225 case -2: /* found but disqualified */
226 fprintf(stderr, "FindExec: could not read binary \"%s\"\n",
231 if (!endp) /* last one */
237 fprintf(stderr, "FindExec: could not find a %s to execute...\n", binary_name);