PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
exec.c File Reference
#include "postgres.h"
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
Include dependency graph for exec.c:

Go to the source code of this file.

Macros

#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)
 

Macro Definition Documentation

#define log_error (   str,
  param 
)    elog(LOG, str, param)

Definition at line 31 of file exec.c.

Referenced by find_my_exec(), pclose_check(), pgwin32_is_admin(), 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().

Function Documentation

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, resolve_symlinks(), strerror(), StrNCpy, and validate_exec().

Referenced by find_other_exec(), find_other_exec_or_die(), getInstallationPaths(), InitStandaloneProcess(), main(), process_psqlrc(), set_pglocale_pgservice(), setup(), setup_bin_paths(), and syncTargetDirectory().

120 {
121  char cwd[MAXPGPATH],
122  test_path[MAXPGPATH];
123  char *path;
124 
125  if (!getcwd(cwd, MAXPGPATH))
126  {
127  log_error(_("could not identify current directory: %s"),
128  strerror(errno));
129  return -1;
130  }
131 
132  /*
133  * If argv0 contains a separator, then PATH wasn't used.
134  */
135  if (first_dir_separator(argv0) != NULL)
136  {
137  if (is_absolute_path(argv0))
138  StrNCpy(retpath, argv0, MAXPGPATH);
139  else
140  join_path_components(retpath, cwd, argv0);
141  canonicalize_path(retpath);
142 
143  if (validate_exec(retpath) == 0)
144  return resolve_symlinks(retpath);
145 
146  log_error(_("invalid binary \"%s\""), retpath);
147  return -1;
148  }
149 
150 #ifdef WIN32
151  /* Win32 checks the current directory first for names without slashes */
152  join_path_components(retpath, cwd, argv0);
153  if (validate_exec(retpath) == 0)
154  return resolve_symlinks(retpath);
155 #endif
156 
157  /*
158  * Since no explicit path was supplied, the user must have been relying on
159  * PATH. We'll search the same PATH.
160  */
161  if ((path = getenv("PATH")) && *path)
162  {
163  char *startp = NULL,
164  *endp = NULL;
165 
166  do
167  {
168  if (!startp)
169  startp = path;
170  else
171  startp = endp + 1;
172 
173  endp = first_path_var_separator(startp);
174  if (!endp)
175  endp = startp + strlen(startp); /* point to end */
176 
177  StrNCpy(test_path, startp, Min(endp - startp + 1, MAXPGPATH));
178 
179  if (is_absolute_path(test_path))
180  join_path_components(retpath, test_path, argv0);
181  else
182  {
183  join_path_components(retpath, cwd, test_path);
184  join_path_components(retpath, retpath, argv0);
185  }
186  canonicalize_path(retpath);
187 
188  switch (validate_exec(retpath))
189  {
190  case 0: /* found ok */
191  return resolve_symlinks(retpath);
192  case -1: /* wasn't even a candidate, keep looking */
193  break;
194  case -2: /* found but disqualified */
195  log_error(_("could not read binary \"%s\""),
196  retpath);
197  break;
198  }
199  } while (*endp);
200  }
201 
202  log_error(_("could not find a \"%s\" to execute"), argv0);
203  return -1;
204 }
static char * argv0
Definition: pg_ctl.c:101
#define log_error(str, param)
Definition: exec.c:31
static int resolve_symlinks(char *path)
Definition: exec.c:219
#define Min(x, y)
Definition: c.h:812
void canonicalize_path(char *path)
Definition: path.c:254
#define MAXPGPATH
static int validate_exec(const char *path)
Definition: exec.c:58
#define is_absolute_path(filename)
Definition: port.h:77
char * first_dir_separator(const char *filename)
Definition: path.c:103
#define StrNCpy(dst, src, len)
Definition: c.h:836
void join_path_components(char *ret_path, const char *head, const char *tail)
Definition: path.c:218
const char * strerror(int errnum)
Definition: strerror.c:19
#define _(x)
Definition: elog.c:84
char * first_path_var_separator(const char *pathlist)
Definition: path.c:120
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(), isolation_start_test(), main(), setup_bin_paths(), and syncTargetDirectory().

309 {
310  char cmd[MAXPGPATH];
311  char line[100];
312 
313  if (find_my_exec(argv0, retpath) < 0)
314  return -1;
315 
316  /* Trim off program name and keep just directory */
317  *last_dir_separator(retpath) = '\0';
318  canonicalize_path(retpath);
319 
320  /* Now append the other program's name */
321  snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
322  "/%s%s", target, EXE);
323 
324  if (validate_exec(retpath) != 0)
325  return -1;
326 
327  snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath);
328 
329  if (!pipe_read_line(cmd, line, sizeof(line)))
330  return -1;
331 
332  if (strcmp(line, versionstr) != 0)
333  return -2;
334 
335  return 0;
336 }
static char * argv0
Definition: pg_ctl.c:101
void canonicalize_path(char *path)
Definition: path.c:254
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXPGPATH
static int validate_exec(const char *path)
Definition: exec.c:58
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:119
char * last_dir_separator(const char *filename)
Definition: path.c:138
#define EXE
Definition: port.h:113
static char * pipe_read_line(char *cmd, char *line, int maxsize)
Definition: exec.c:348
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().

511 {
512  int exitstatus;
513  char *reason;
514 
515  exitstatus = pclose(stream);
516 
517  if (exitstatus == 0)
518  return 0; /* all is well */
519 
520  if (exitstatus == -1)
521  {
522  /* pclose() itself failed, and hopefully set errno */
523  log_error(_("pclose failed: %s"), strerror(errno));
524  }
525  else
526  {
527  reason = wait_result_to_str(exitstatus);
528  log_error("%s", reason);
529 #ifdef FRONTEND
530  free(reason);
531 #else
532  pfree(reason);
533 #endif
534  }
535  return exitstatus;
536 }
#define log_error(str, param)
Definition: exec.c:31
char * wait_result_to_str(int exitstatus)
Definition: wait_error.c:32
void pfree(void *pointer)
Definition: mcxt.c:949
#define free(a)
Definition: header.h:65
const char * strerror(int errnum)
Definition: strerror.c:19
#define _(x)
Definition: elog.c:84
static char * pipe_read_line ( char *  cmd,
char *  line,
int  maxsize 
)
static

Definition at line 348 of file exec.c.

References FALSE, pclose_check(), and TRUE.

Referenced by find_other_exec().

349 {
350 #ifndef WIN32
351  FILE *pgver;
352 
353  /* flush output buffers in case popen does not... */
354  fflush(stdout);
355  fflush(stderr);
356 
357  errno = 0;
358  if ((pgver = popen(cmd, "r")) == NULL)
359  {
360  perror("popen failure");
361  return NULL;
362  }
363 
364  errno = 0;
365  if (fgets(line, maxsize, pgver) == NULL)
366  {
367  if (feof(pgver))
368  fprintf(stderr, "no data was returned by command \"%s\"\n", cmd);
369  else
370  perror("fgets failure");
371  pclose(pgver); /* no error checking */
372  return NULL;
373  }
374 
375  if (pclose_check(pgver))
376  return NULL;
377 
378  return line;
379 #else /* WIN32 */
380 
381  SECURITY_ATTRIBUTES sattr;
382  HANDLE childstdoutrd,
383  childstdoutwr,
384  childstdoutrddup;
385  PROCESS_INFORMATION pi;
386  STARTUPINFO si;
387  char *retval = NULL;
388 
389  sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
390  sattr.bInheritHandle = TRUE;
391  sattr.lpSecurityDescriptor = NULL;
392 
393  if (!CreatePipe(&childstdoutrd, &childstdoutwr, &sattr, 0))
394  return NULL;
395 
396  if (!DuplicateHandle(GetCurrentProcess(),
397  childstdoutrd,
398  GetCurrentProcess(),
399  &childstdoutrddup,
400  0,
401  FALSE,
402  DUPLICATE_SAME_ACCESS))
403  {
404  CloseHandle(childstdoutrd);
405  CloseHandle(childstdoutwr);
406  return NULL;
407  }
408 
409  CloseHandle(childstdoutrd);
410 
411  ZeroMemory(&pi, sizeof(pi));
412  ZeroMemory(&si, sizeof(si));
413  si.cb = sizeof(si);
414  si.dwFlags = STARTF_USESTDHANDLES;
415  si.hStdError = childstdoutwr;
416  si.hStdOutput = childstdoutwr;
417  si.hStdInput = INVALID_HANDLE_VALUE;
418 
419  if (CreateProcess(NULL,
420  cmd,
421  NULL,
422  NULL,
423  TRUE,
424  0,
425  NULL,
426  NULL,
427  &si,
428  &pi))
429  {
430  /* Successfully started the process */
431  char *lineptr;
432 
433  ZeroMemory(line, maxsize);
434 
435  /* Try to read at least one line from the pipe */
436  /* This may require more than one wait/read attempt */
437  for (lineptr = line; lineptr < line + maxsize - 1;)
438  {
439  DWORD bytesread = 0;
440 
441  /* Let's see if we can read */
442  if (WaitForSingleObject(childstdoutrddup, 10000) != WAIT_OBJECT_0)
443  break; /* Timeout, but perhaps we got a line already */
444 
445  if (!ReadFile(childstdoutrddup, lineptr, maxsize - (lineptr - line),
446  &bytesread, NULL))
447  break; /* Error, but perhaps we got a line already */
448 
449  lineptr += strlen(lineptr);
450 
451  if (!bytesread)
452  break; /* EOF */
453 
454  if (strchr(line, '\n'))
455  break; /* One or more lines read */
456  }
457 
458  if (lineptr != line)
459  {
460  /* OK, we read some data */
461  int len;
462 
463  /* If we got more than one line, cut off after the first \n */
464  lineptr = strchr(line, '\n');
465  if (lineptr)
466  *(lineptr + 1) = '\0';
467 
468  len = strlen(line);
469 
470  /*
471  * If EOL is \r\n, convert to just \n. Because stdout is a
472  * text-mode stream, the \n output by the child process is
473  * received as \r\n, so we convert it to \n. The server main.c
474  * sets setvbuf(stdout, NULL, _IONBF, 0) which has the effect of
475  * disabling \n to \r\n expansion for stdout.
476  */
477  if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n')
478  {
479  line[len - 2] = '\n';
480  line[len - 1] = '\0';
481  len--;
482  }
483 
484  /*
485  * We emulate fgets() behaviour. So if there is no newline at the
486  * end, we add one...
487  */
488  if (len == 0 || line[len - 1] != '\n')
489  strcat(line, "\n");
490 
491  retval = line;
492  }
493 
494  CloseHandle(pi.hProcess);
495  CloseHandle(pi.hThread);
496  }
497 
498  CloseHandle(childstdoutwr);
499  CloseHandle(childstdoutrddup);
500 
501  return retval;
502 #endif /* WIN32 */
503 }
int pclose_check(FILE *stream)
Definition: exec.c:510
#define FALSE
Definition: c.h:219
#define TRUE
Definition: c.h:215
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, strerror(), and strlcpy().

Referenced by find_my_exec().

220 {
221 #ifdef HAVE_READLINK
222  struct stat buf;
223  char orig_wd[MAXPGPATH],
224  link_buf[MAXPGPATH];
225  char *fname;
226 
227  /*
228  * To resolve a symlink properly, we have to chdir into its directory and
229  * then chdir to where the symlink points; otherwise we may fail to
230  * resolve relative links correctly (consider cases involving mount
231  * points, for example). After following the final symlink, we use
232  * getcwd() to figure out where the heck we're at.
233  *
234  * One might think we could skip all this if path doesn't point to a
235  * symlink to start with, but that's wrong. We also want to get rid of
236  * any directory symlinks that are present in the given path. We expect
237  * getcwd() to give us an accurate, symlink-free path.
238  */
239  if (!getcwd(orig_wd, MAXPGPATH))
240  {
241  log_error(_("could not identify current directory: %s"),
242  strerror(errno));
243  return -1;
244  }
245 
246  for (;;)
247  {
248  char *lsep;
249  int rllen;
250 
251  lsep = last_dir_separator(path);
252  if (lsep)
253  {
254  *lsep = '\0';
255  if (chdir(path) == -1)
256  {
257  log_error4(_("could not change directory to \"%s\": %s"), path, strerror(errno));
258  return -1;
259  }
260  fname = lsep + 1;
261  }
262  else
263  fname = path;
264 
265  if (lstat(fname, &buf) < 0 ||
266  !S_ISLNK(buf.st_mode))
267  break;
268 
269  rllen = readlink(fname, link_buf, sizeof(link_buf));
270  if (rllen < 0 || rllen >= sizeof(link_buf))
271  {
272  log_error(_("could not read symbolic link \"%s\""), fname);
273  return -1;
274  }
275  link_buf[rllen] = '\0';
276  strcpy(path, link_buf);
277  }
278 
279  /* must copy final component out of 'path' temporarily */
280  strlcpy(link_buf, fname, sizeof(link_buf));
281 
282  if (!getcwd(path, MAXPGPATH))
283  {
284  log_error(_("could not identify current directory: %s"),
285  strerror(errno));
286  return -1;
287  }
288  join_path_components(path, path, link_buf);
289  canonicalize_path(path);
290 
291  if (chdir(orig_wd) == -1)
292  {
293  log_error4(_("could not change directory to \"%s\": %s"), orig_wd, strerror(errno));
294  return -1;
295  }
296 #endif /* HAVE_READLINK */
297 
298  return 0;
299 }
#define log_error(str, param)
Definition: exec.c:31
void canonicalize_path(char *path)
Definition: path.c:254
#define MAXPGPATH
#define log_error4(str, param, arg1)
Definition: exec.c:32
static char * buf
Definition: pg_test_fsync.c:67
char * last_dir_separator(const char *filename)
Definition: path.c:138
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void join_path_components(char *ret_path, const char *head, const char *tail)
Definition: path.c:218
const char * strerror(int errnum)
Definition: strerror.c:19
#define lstat(path, sb)
Definition: win32.h:262
#define _(x)
Definition: elog.c:84
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, PG_TEXTDOMAIN, putenv, and snprintf().

Referenced by main(), and regression_main().

551 {
552  char path[MAXPGPATH];
553  char my_exec_path[MAXPGPATH];
554  char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than
555  * PGLOCALEDIR */
556  char *dup_path;
557 
558  /* don't set LC_ALL in the backend */
559  if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
560  {
561  setlocale(LC_ALL, "");
562 
563  /*
564  * One could make a case for reproducing here PostmasterMain()'s test
565  * for whether the process is multithreaded. Unlike the postmaster,
566  * no frontend program calls sigprocmask() or otherwise provides for
567  * mutual exclusion between signal handlers. While frontends using
568  * fork(), if multithreaded, are formally exposed to undefined
569  * behavior, we have not witnessed a concrete bug. Therefore,
570  * complaining about multithreading here may be mere pedantry.
571  */
572  }
573 
574  if (find_my_exec(argv0, my_exec_path) < 0)
575  return;
576 
577 #ifdef ENABLE_NLS
578  get_locale_path(my_exec_path, path);
579  bindtextdomain(app, path);
580  textdomain(app);
581 
582  if (getenv("PGLOCALEDIR") == NULL)
583  {
584  /* set for libpq to use */
585  snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path);
586  canonicalize_path(env_path + 12);
587  dup_path = strdup(env_path);
588  if (dup_path)
589  putenv(dup_path);
590  }
591 #endif
592 
593  if (getenv("PGSYSCONFDIR") == NULL)
594  {
595  get_etc_path(my_exec_path, path);
596 
597  /* set for libpq to use */
598  snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path);
599  canonicalize_path(env_path + 13);
600  dup_path = strdup(env_path);
601  if (dup_path)
602  putenv(dup_path);
603  }
604 }
static char * argv0
Definition: pg_ctl.c:101
void canonicalize_path(char *path)
Definition: path.c:254
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define putenv(x)
Definition: win32.h:411
#define MAXPGPATH
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:119
char my_exec_path[MAXPGPATH]
Definition: globals.c:64
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1018
void get_etc_path(const char *my_exec_path, char *ret_path)
Definition: path.c:713
void get_locale_path(const char *my_exec_path, char *ret_path)
Definition: path.c:767
static int validate_exec ( const char *  path)
static

Definition at line 58 of file exec.c.

References MAXPGPATH, pg_strcasecmp(), and strlcpy().

Referenced by find_my_exec(), and find_other_exec().

59 {
60  struct stat buf;
61  int is_r;
62  int is_x;
63 
64 #ifdef WIN32
65  char path_exe[MAXPGPATH + sizeof(".exe") - 1];
66 
67  /* Win32 requires a .exe suffix for stat() */
68  if (strlen(path) >= strlen(".exe") &&
69  pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
70  {
71  strlcpy(path_exe, path, sizeof(path_exe) - 4);
72  strcat(path_exe, ".exe");
73  path = path_exe;
74  }
75 #endif
76 
77  /*
78  * Ensure that the file exists and is a regular file.
79  *
80  * XXX if you have a broken system where stat() looks at the symlink
81  * instead of the underlying file, you lose.
82  */
83  if (stat(path, &buf) < 0)
84  return -1;
85 
86  if (!S_ISREG(buf.st_mode))
87  return -1;
88 
89  /*
90  * Ensure that the file is both executable and readable (required for
91  * dynamic loading).
92  */
93 #ifndef WIN32
94  is_r = (access(path, R_OK) == 0);
95  is_x = (access(path, X_OK) == 0);
96 #else
97  is_r = buf.st_mode & S_IRUSR;
98  is_x = buf.st_mode & S_IXUSR;
99 #endif
100  return is_x ? (is_r ? 0 : -2) : -1;
101 }
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:67
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45