#include "postgres.h"
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
Go to the source code of this file.
Defines | |
#define | log_error(str, param) elog(LOG, str, param) |
#define | log_error4(str, param, arg1) elog(LOG, str, param, arg1) |
Functions | |
static int | validate_exec (const char *path) |
static int | resolve_symlinks (char *path) |
static char * | pipe_read_line (char *cmd, char *line, int maxsize) |
int | find_my_exec (const char *argv0, char *retpath) |
int | find_other_exec (const char *argv0, const char *target, const char *versionstr, char *retpath) |
int | pclose_check (FILE *stream) |
void | set_pglocale_pgservice (const char *argv0, const char *app) |
#define log_error | ( | str, | ||
param | ||||
) | elog(LOG, str, param) |
Definition at line 31 of file exec.c.
Referenced by find_my_exec(), pclose_check(), and resolve_symlinks().
#define log_error4 | ( | str, | ||
param, | ||||
arg1 | ||||
) | elog(LOG, str, param, arg1) |
Definition at line 32 of file exec.c.
Referenced by resolve_symlinks().
int find_my_exec | ( | const char * | argv0, | |
char * | retpath | |||
) |
Definition at line 119 of file exec.c.
References _, canonicalize_path(), first_dir_separator(), first_path_var_separator(), is_absolute_path, join_path_components(), log_error, MAXPGPATH, Min, NULL, resolve_symlinks(), strerror(), StrNCpy, and validate_exec().
Referenced by AuxiliaryProcessMain(), find_other_exec(), find_other_exec_or_die(), getInstallationPaths(), main(), PostgresMain(), process_psqlrc(), set_pglocale_pgservice(), setup(), and setup_bin_paths().
{ char cwd[MAXPGPATH], test_path[MAXPGPATH]; char *path; if (!getcwd(cwd, MAXPGPATH)) { log_error(_("could not identify current directory: %s"), strerror(errno)); return -1; } /* * If argv0 contains a separator, then PATH wasn't used. */ if (first_dir_separator(argv0) != NULL) { if (is_absolute_path(argv0)) StrNCpy(retpath, argv0, MAXPGPATH); else join_path_components(retpath, cwd, argv0); canonicalize_path(retpath); if (validate_exec(retpath) == 0) return resolve_symlinks(retpath); log_error(_("invalid binary \"%s\""), retpath); return -1; } #ifdef WIN32 /* Win32 checks the current directory first for names without slashes */ join_path_components(retpath, cwd, argv0); if (validate_exec(retpath) == 0) return resolve_symlinks(retpath); #endif /* * Since no explicit path was supplied, the user must have been relying on * PATH. We'll search the same PATH. */ if ((path = getenv("PATH")) && *path) { char *startp = NULL, *endp = NULL; do { if (!startp) startp = path; else startp = endp + 1; endp = first_path_var_separator(startp); if (!endp) endp = startp + strlen(startp); /* point to end */ StrNCpy(test_path, startp, Min(endp - startp + 1, MAXPGPATH)); if (is_absolute_path(test_path)) join_path_components(retpath, test_path, argv0); else { join_path_components(retpath, cwd, test_path); join_path_components(retpath, retpath, argv0); } canonicalize_path(retpath); switch (validate_exec(retpath)) { case 0: /* found ok */ return resolve_symlinks(retpath); case -1: /* wasn't even a candidate, keep looking */ break; case -2: /* found but disqualified */ log_error(_("could not read binary \"%s\""), retpath); break; } } while (*endp); } log_error(_("could not find a \"%s\" to execute"), argv0); return -1; }
int find_other_exec | ( | const char * | argv0, | |
const char * | target, | |||
const char * | versionstr, | |||
char * | retpath | |||
) |
Definition at line 307 of file exec.c.
References canonicalize_path(), EXE, find_my_exec(), last_dir_separator(), MAXPGPATH, pipe_read_line(), snprintf(), and validate_exec().
Referenced by find_other_exec_or_die(), getInstallationPaths(), main(), and setup_bin_paths().
{ char cmd[MAXPGPATH]; char line[100]; if (find_my_exec(argv0, retpath) < 0) return -1; /* Trim off program name and keep just directory */ *last_dir_separator(retpath) = '\0'; canonicalize_path(retpath); /* Now append the other program's name */ snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath), "/%s%s", target, EXE); if (validate_exec(retpath) != 0) return -1; snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath); if (!pipe_read_line(cmd, line, sizeof(line))) return -1; if (strcmp(line, versionstr) != 0) return -2; return 0; }
int pclose_check | ( | FILE * | stream | ) |
Definition at line 510 of file exec.c.
References _, free, log_error, pfree(), strerror(), and wait_result_to_str().
Referenced by pipe_read_line().
{ int exitstatus; char *reason; exitstatus = pclose(stream); if (exitstatus == 0) return 0; /* all is well */ if (exitstatus == -1) { /* pclose() itself failed, and hopefully set errno */ log_error(_("pclose failed: %s"), strerror(errno)); } else { reason = wait_result_to_str(exitstatus); log_error("%s", reason); #ifdef FRONTEND free(reason); #else pfree(reason); #endif } return exitstatus; }
static char * pipe_read_line | ( | char * | cmd, | |
char * | line, | |||
int | maxsize | |||
) | [static] |
Definition at line 348 of file exec.c.
References FALSE, NULL, pclose_check(), and TRUE.
Referenced by find_other_exec().
{ #ifndef WIN32 FILE *pgver; /* flush output buffers in case popen does not... */ fflush(stdout); fflush(stderr); errno = 0; if ((pgver = popen(cmd, "r")) == NULL) { perror("popen failure"); return NULL; } errno = 0; if (fgets(line, maxsize, pgver) == NULL) { if (feof(pgver)) fprintf(stderr, "no data was returned by command \"%s\"\n", cmd); else perror("fgets failure"); pclose(pgver); /* no error checking */ return NULL; } if (pclose_check(pgver)) return NULL; return line; #else /* WIN32 */ SECURITY_ATTRIBUTES sattr; HANDLE childstdoutrd, childstdoutwr, childstdoutrddup; PROCESS_INFORMATION pi; STARTUPINFO si; char *retval = NULL; sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; if (!CreatePipe(&childstdoutrd, &childstdoutwr, &sattr, 0)) return NULL; if (!DuplicateHandle(GetCurrentProcess(), childstdoutrd, GetCurrentProcess(), &childstdoutrddup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { CloseHandle(childstdoutrd); CloseHandle(childstdoutwr); return NULL; } CloseHandle(childstdoutrd); ZeroMemory(&pi, sizeof(pi)); ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdError = childstdoutwr; si.hStdOutput = childstdoutwr; si.hStdInput = INVALID_HANDLE_VALUE; if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { /* Successfully started the process */ char *lineptr; ZeroMemory(line, maxsize); /* Try to read at least one line from the pipe */ /* This may require more than one wait/read attempt */ for (lineptr = line; lineptr < line + maxsize - 1;) { DWORD bytesread = 0; /* Let's see if we can read */ if (WaitForSingleObject(childstdoutrddup, 10000) != WAIT_OBJECT_0) break; /* Timeout, but perhaps we got a line already */ if (!ReadFile(childstdoutrddup, lineptr, maxsize - (lineptr - line), &bytesread, NULL)) break; /* Error, but perhaps we got a line already */ lineptr += strlen(lineptr); if (!bytesread) break; /* EOF */ if (strchr(line, '\n')) break; /* One or more lines read */ } if (lineptr != line) { /* OK, we read some data */ int len; /* If we got more than one line, cut off after the first \n */ lineptr = strchr(line, '\n'); if (lineptr) *(lineptr + 1) = '\0'; len = strlen(line); /* * If EOL is \r\n, convert to just \n. Because stdout is a * text-mode stream, the \n output by the child process is * received as \r\n, so we convert it to \n. The server main.c * sets setvbuf(stdout, NULL, _IONBF, 0) which has the effect of * disabling \n to \r\n expansion for stdout. */ if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') { line[len - 2] = '\n'; line[len - 1] = '\0'; len--; } /* * We emulate fgets() behaviour. So if there is no newline at the * end, we add one... */ if (len == 0 || line[len - 1] != '\n') strcat(line, "\n"); retval = line; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } CloseHandle(childstdoutwr); CloseHandle(childstdoutrddup); return retval; #endif /* WIN32 */ }
static int resolve_symlinks | ( | char * | path | ) | [static] |
Definition at line 219 of file exec.c.
References _, canonicalize_path(), join_path_components(), last_dir_separator(), log_error, log_error4, lstat, MAXPGPATH, and strerror().
Referenced by find_my_exec().
{ #ifdef HAVE_READLINK struct stat buf; char orig_wd[MAXPGPATH], link_buf[MAXPGPATH]; char *fname; /* * To resolve a symlink properly, we have to chdir into its directory and * then chdir to where the symlink points; otherwise we may fail to * resolve relative links correctly (consider cases involving mount * points, for example). After following the final symlink, we use * getcwd() to figure out where the heck we're at. * * One might think we could skip all this if path doesn't point to a * symlink to start with, but that's wrong. We also want to get rid of * any directory symlinks that are present in the given path. We expect * getcwd() to give us an accurate, symlink-free path. */ if (!getcwd(orig_wd, MAXPGPATH)) { log_error(_("could not identify current directory: %s"), strerror(errno)); return -1; } for (;;) { char *lsep; int rllen; lsep = last_dir_separator(path); if (lsep) { *lsep = '\0'; if (chdir(path) == -1) { log_error4(_("could not change directory to \"%s\": %s"), path, strerror(errno)); return -1; } fname = lsep + 1; } else fname = path; if (lstat(fname, &buf) < 0 || !S_ISLNK(buf.st_mode)) break; rllen = readlink(fname, link_buf, sizeof(link_buf)); if (rllen < 0 || rllen >= sizeof(link_buf)) { log_error(_("could not read symbolic link \"%s\""), fname); return -1; } link_buf[rllen] = '\0'; strcpy(path, link_buf); } /* must copy final component out of 'path' temporarily */ strcpy(link_buf, fname); if (!getcwd(path, MAXPGPATH)) { log_error(_("could not identify current directory: %s"), strerror(errno)); return -1; } join_path_components(path, path, link_buf); canonicalize_path(path); if (chdir(orig_wd) == -1) { log_error4(_("could not change directory to \"%s\": %s"), orig_wd, strerror(errno)); return -1; } #endif /* HAVE_READLINK */ return 0; }
void set_pglocale_pgservice | ( | const char * | argv0, | |
const char * | app | |||
) |
Definition at line 550 of file exec.c.
References canonicalize_path(), find_my_exec(), get_etc_path(), get_locale_path(), MAXPGPATH, my_exec_path, NULL, PG_TEXTDOMAIN, putenv, and snprintf().
Referenced by main(), and regression_main().
{ char path[MAXPGPATH]; char my_exec_path[MAXPGPATH]; char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than * PGLOCALEDIR */ /* don't set LC_ALL in the backend */ if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0) setlocale(LC_ALL, ""); if (find_my_exec(argv0, my_exec_path) < 0) return; #ifdef ENABLE_NLS get_locale_path(my_exec_path, path); bindtextdomain(app, path); textdomain(app); if (getenv("PGLOCALEDIR") == NULL) { /* set for libpq to use */ snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path); canonicalize_path(env_path + 12); putenv(strdup(env_path)); } #endif if (getenv("PGSYSCONFDIR") == NULL) { get_etc_path(my_exec_path, path); /* set for libpq to use */ snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path); canonicalize_path(env_path + 13); putenv(strdup(env_path)); } }
static int validate_exec | ( | const char * | path | ) | [static] |
Definition at line 58 of file exec.c.
References MAXPGPATH, and pg_strcasecmp().
Referenced by find_my_exec(), and find_other_exec().
{ struct stat buf; int is_r; int is_x; #ifdef WIN32 char path_exe[MAXPGPATH + sizeof(".exe") - 1]; /* Win32 requires a .exe suffix for stat() */ if (strlen(path) >= strlen(".exe") && pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0) { strcpy(path_exe, path); strcat(path_exe, ".exe"); path = path_exe; } #endif /* * 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) return -1; if (!S_ISREG(buf.st_mode)) return -1; /* * Ensure that the file is both executable and readable (required for * dynamic loading). */ #ifndef WIN32 is_r = (access(path, R_OK) == 0); is_x = (access(path, X_OK) == 0); #else is_r = buf.st_mode & S_IRUSR; is_x = buf.st_mode & S_IXUSR; #endif return is_x ? (is_r ? 0 : -2) : -1; }