PostgreSQL Source Code  git master
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(errcodefn, ...)   ereport(LOG, (errcodefn, errmsg_internal(__VA_ARGS__)))
 

Functions

static int validate_exec (const char *path)
 
static int resolve_symlinks (char *path)
 
int find_my_exec (const char *argv0, char *retpath)
 
int find_other_exec (const char *argv0, const char *target, const char *versionstr, char *retpath)
 
char * pipe_read_line (char *cmd, char *line, int maxsize)
 
int pclose_check (FILE *stream)
 
void set_pglocale_pgservice (const char *argv0, const char *app)
 

Macro Definition Documentation

◆ log_error

#define log_error (   errcodefn,
  ... 
)    ereport(LOG, (errcodefn, errmsg_internal(__VA_ARGS__)))

Function Documentation

◆ find_my_exec()

int find_my_exec ( const char *  argv0,
char *  retpath 
)

Definition at line 128 of file exec.c.

References _, canonicalize_path(), errcode(), errcode_for_file_access(), first_dir_separator(), first_path_var_separator(), is_absolute_path, join_path_components(), log_error, MAXPGPATH, Min, resolve_symlinks(), strlcpy(), and validate_exec().

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

129 {
130  char cwd[MAXPGPATH],
131  test_path[MAXPGPATH];
132  char *path;
133 
134  if (!getcwd(cwd, MAXPGPATH))
135  {
137  _("could not identify current directory: %m"));
138  return -1;
139  }
140 
141  /*
142  * If argv0 contains a separator, then PATH wasn't used.
143  */
144  if (first_dir_separator(argv0) != NULL)
145  {
146  if (is_absolute_path(argv0))
147  strlcpy(retpath, argv0, MAXPGPATH);
148  else
149  join_path_components(retpath, cwd, argv0);
150  canonicalize_path(retpath);
151 
152  if (validate_exec(retpath) == 0)
153  return resolve_symlinks(retpath);
154 
155  log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
156  _("invalid binary \"%s\""), retpath);
157  return -1;
158  }
159 
160 #ifdef WIN32
161  /* Win32 checks the current directory first for names without slashes */
162  join_path_components(retpath, cwd, argv0);
163  if (validate_exec(retpath) == 0)
164  return resolve_symlinks(retpath);
165 #endif
166 
167  /*
168  * Since no explicit path was supplied, the user must have been relying on
169  * PATH. We'll search the same PATH.
170  */
171  if ((path = getenv("PATH")) && *path)
172  {
173  char *startp = NULL,
174  *endp = NULL;
175 
176  do
177  {
178  if (!startp)
179  startp = path;
180  else
181  startp = endp + 1;
182 
183  endp = first_path_var_separator(startp);
184  if (!endp)
185  endp = startp + strlen(startp); /* point to end */
186 
187  strlcpy(test_path, startp, Min(endp - startp + 1, MAXPGPATH));
188 
189  if (is_absolute_path(test_path))
190  join_path_components(retpath, test_path, argv0);
191  else
192  {
193  join_path_components(retpath, cwd, test_path);
194  join_path_components(retpath, retpath, argv0);
195  }
196  canonicalize_path(retpath);
197 
198  switch (validate_exec(retpath))
199  {
200  case 0: /* found ok */
201  return resolve_symlinks(retpath);
202  case -1: /* wasn't even a candidate, keep looking */
203  break;
204  case -2: /* found but disqualified */
205  log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
206  _("could not read binary \"%s\""),
207  retpath);
208  break;
209  }
210  } while (*endp);
211  }
212 
213  log_error(errcode(ERRCODE_UNDEFINED_FILE),
214  _("could not find a \"%s\" to execute"), argv0);
215  return -1;
216 }
static char * argv0
Definition: pg_ctl.c:97
static int resolve_symlinks(char *path)
Definition: exec.c:231
#define Min(x, y)
Definition: c.h:927
void canonicalize_path(char *path)
Definition: path.c:254
int errcode(int sqlerrcode)
Definition: elog.c:610
#define log_error(errcodefn,...)
Definition: exec.c:41
#define MAXPGPATH
static int validate_exec(const char *path)
Definition: exec.c:67
int errcode_for_file_access(void)
Definition: elog.c:633
#define is_absolute_path(filename)
Definition: port.h:86
char * first_dir_separator(const char *filename)
Definition: path.c:103
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
#define _(x)
Definition: elog.c:88
char * first_path_var_separator(const char *pathlist)
Definition: path.c:120

◆ find_other_exec()

int find_other_exec ( const char *  argv0,
const char *  target,
const char *  versionstr,
char *  retpath 
)

Definition at line 323 of file exec.c.

References canonicalize_path(), EXE, find_my_exec(), last_dir_separator(), MAXPGPATH, pipe_read_line(), snprintf, and validate_exec().

Referenced by do_kill(), ensureCleanShutdown(), find_other_exec_or_die(), getInstallationPaths(), getRestoreCommand(), isolation_start_test(), main(), and setup_bin_paths().

325 {
326  char cmd[MAXPGPATH];
327  char line[MAXPGPATH];
328 
329  if (find_my_exec(argv0, retpath) < 0)
330  return -1;
331 
332  /* Trim off program name and keep just directory */
333  *last_dir_separator(retpath) = '\0';
334  canonicalize_path(retpath);
335 
336  /* Now append the other program's name */
337  snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
338  "/%s%s", target, EXE);
339 
340  if (validate_exec(retpath) != 0)
341  return -1;
342 
343  snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath);
344 
345  if (!pipe_read_line(cmd, line, sizeof(line)))
346  return -1;
347 
348  if (strcmp(line, versionstr) != 0)
349  return -2;
350 
351  return 0;
352 }
static char * argv0
Definition: pg_ctl.c:97
void canonicalize_path(char *path)
Definition: path.c:254
#define MAXPGPATH
static int validate_exec(const char *path)
Definition: exec.c:67
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:128
char * last_dir_separator(const char *filename)
Definition: path.c:138
char * pipe_read_line(char *cmd, char *line, int maxsize)
Definition: exec.c:359
#define EXE
Definition: port.h:118
#define snprintf
Definition: port.h:193

◆ pclose_check()

int pclose_check ( FILE *  stream)

Definition at line 396 of file exec.c.

References _, errcode(), log_error, pfree(), and wait_result_to_str().

Referenced by pipe_read_line().

397 {
398  int exitstatus;
399  char *reason;
400 
401  exitstatus = pclose(stream);
402 
403  if (exitstatus == 0)
404  return 0; /* all is well */
405 
406  if (exitstatus == -1)
407  {
408  /* pclose() itself failed, and hopefully set errno */
409  log_error(errcode(ERRCODE_SYSTEM_ERROR),
410  _("pclose failed: %m"));
411  }
412  else
413  {
414  reason = wait_result_to_str(exitstatus);
415  log_error(errcode(ERRCODE_SYSTEM_ERROR),
416  "%s", reason);
417  pfree(reason);
418  }
419  return exitstatus;
420 }
int errcode(int sqlerrcode)
Definition: elog.c:610
char * wait_result_to_str(int exitstatus)
Definition: wait_error.c:32
void pfree(void *pointer)
Definition: mcxt.c:1056
#define log_error(errcodefn,...)
Definition: exec.c:41
#define _(x)
Definition: elog.c:88

◆ pipe_read_line()

char* pipe_read_line ( char *  cmd,
char *  line,
int  maxsize 
)

Definition at line 359 of file exec.c.

References fprintf, pclose_check(), and generate_unaccent_rules::stdout.

Referenced by find_other_exec(), and getRestoreCommand().

360 {
361  FILE *pgver;
362 
363  /* flush output buffers in case popen does not... */
364  fflush(stdout);
365  fflush(stderr);
366 
367  errno = 0;
368  if ((pgver = popen(cmd, "r")) == NULL)
369  {
370  perror("popen failure");
371  return NULL;
372  }
373 
374  errno = 0;
375  if (fgets(line, maxsize, pgver) == NULL)
376  {
377  if (feof(pgver))
378  fprintf(stderr, "no data was returned by command \"%s\"\n", cmd);
379  else
380  perror("fgets failure");
381  pclose(pgver); /* no error checking */
382  return NULL;
383  }
384 
385  if (pclose_check(pgver))
386  return NULL;
387 
388  return line;
389 }
#define fprintf
Definition: port.h:197
int pclose_check(FILE *stream)
Definition: exec.c:396

◆ resolve_symlinks()

static int resolve_symlinks ( char *  path)
static

Definition at line 231 of file exec.c.

References _, canonicalize_path(), errcode_for_file_access(), join_path_components(), last_dir_separator(), log_error, lstat, MAXPGPATH, readlink, stat, and strlcpy().

Referenced by find_my_exec().

232 {
233 #ifdef HAVE_READLINK
234  struct stat buf;
235  char orig_wd[MAXPGPATH],
236  link_buf[MAXPGPATH];
237  char *fname;
238 
239  /*
240  * To resolve a symlink properly, we have to chdir into its directory and
241  * then chdir to where the symlink points; otherwise we may fail to
242  * resolve relative links correctly (consider cases involving mount
243  * points, for example). After following the final symlink, we use
244  * getcwd() to figure out where the heck we're at.
245  *
246  * One might think we could skip all this if path doesn't point to a
247  * symlink to start with, but that's wrong. We also want to get rid of
248  * any directory symlinks that are present in the given path. We expect
249  * getcwd() to give us an accurate, symlink-free path.
250  */
251  if (!getcwd(orig_wd, MAXPGPATH))
252  {
254  _("could not identify current directory: %m"));
255  return -1;
256  }
257 
258  for (;;)
259  {
260  char *lsep;
261  int rllen;
262 
263  lsep = last_dir_separator(path);
264  if (lsep)
265  {
266  *lsep = '\0';
267  if (chdir(path) == -1)
268  {
270  _("could not change directory to \"%s\": %m"), path);
271  return -1;
272  }
273  fname = lsep + 1;
274  }
275  else
276  fname = path;
277 
278  if (lstat(fname, &buf) < 0 ||
279  !S_ISLNK(buf.st_mode))
280  break;
281 
282  errno = 0;
283  rllen = readlink(fname, link_buf, sizeof(link_buf));
284  if (rllen < 0 || rllen >= sizeof(link_buf))
285  {
287  _("could not read symbolic link \"%s\": %m"), fname);
288  return -1;
289  }
290  link_buf[rllen] = '\0';
291  strcpy(path, link_buf);
292  }
293 
294  /* must copy final component out of 'path' temporarily */
295  strlcpy(link_buf, fname, sizeof(link_buf));
296 
297  if (!getcwd(path, MAXPGPATH))
298  {
300  _("could not identify current directory: %m"));
301  return -1;
302  }
303  join_path_components(path, path, link_buf);
304  canonicalize_path(path);
305 
306  if (chdir(orig_wd) == -1)
307  {
309  _("could not change directory to \"%s\": %m"), orig_wd);
310  return -1;
311  }
312 #endif /* HAVE_READLINK */
313 
314  return 0;
315 }
void canonicalize_path(char *path)
Definition: path.c:254
#define log_error(errcodefn,...)
Definition: exec.c:41
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:67
#define readlink(path, buf, size)
Definition: win32_port.h:222
int errcode_for_file_access(void)
Definition: elog.c:633
#define stat(a, b)
Definition: win32_port.h:255
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
#define lstat(path, sb)
Definition: win32_port.h:244
#define _(x)
Definition: elog.c:88

◆ set_pglocale_pgservice()

void set_pglocale_pgservice ( const char *  argv0,
const char *  app 
)

Definition at line 434 of file exec.c.

References _, AddUserToTokenDacl(), canonicalize_path(), cleanup(), errcode(), find_my_exec(), get_etc_path(), get_locale_path(), i, log_error, MAXPGPATH, my_exec_path, PG_TEXTDOMAIN, putenv, setlocale, and snprintf.

Referenced by main(), and regression_main().

435 {
436  char path[MAXPGPATH];
437  char my_exec_path[MAXPGPATH];
438  char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than
439  * PGLOCALEDIR */
440  char *dup_path;
441 
442  /* don't set LC_ALL in the backend */
443  if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
444  {
445  setlocale(LC_ALL, "");
446 
447  /*
448  * One could make a case for reproducing here PostmasterMain()'s test
449  * for whether the process is multithreaded. Unlike the postmaster,
450  * no frontend program calls sigprocmask() or otherwise provides for
451  * mutual exclusion between signal handlers. While frontends using
452  * fork(), if multithreaded, are formally exposed to undefined
453  * behavior, we have not witnessed a concrete bug. Therefore,
454  * complaining about multithreading here may be mere pedantry.
455  */
456  }
457 
458  if (find_my_exec(argv0, my_exec_path) < 0)
459  return;
460 
461 #ifdef ENABLE_NLS
462  get_locale_path(my_exec_path, path);
463  bindtextdomain(app, path);
464  textdomain(app);
465 
466  if (getenv("PGLOCALEDIR") == NULL)
467  {
468  /* set for libpq to use */
469  snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path);
470  canonicalize_path(env_path + 12);
471  dup_path = strdup(env_path);
472  if (dup_path)
473  putenv(dup_path);
474  }
475 #endif
476 
477  if (getenv("PGSYSCONFDIR") == NULL)
478  {
479  get_etc_path(my_exec_path, path);
480 
481  /* set for libpq to use */
482  snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path);
483  canonicalize_path(env_path + 13);
484  dup_path = strdup(env_path);
485  if (dup_path)
486  putenv(dup_path);
487  }
488 }
static char * argv0
Definition: pg_ctl.c:97
#define setlocale(a, b)
Definition: win32_port.h:408
void canonicalize_path(char *path)
Definition: path.c:254
#define MAXPGPATH
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:128
char my_exec_path[MAXPGPATH]
Definition: globals.c:72
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1155
void get_etc_path(const char *my_exec_path, char *ret_path)
Definition: path.c:713
#define putenv(x)
Definition: win32_port.h:474
void get_locale_path(const char *my_exec_path, char *ret_path)
Definition: path.c:767
#define snprintf
Definition: port.h:193

◆ validate_exec()

static int validate_exec ( const char *  path)
static

Definition at line 67 of file exec.c.

References MAXPGPATH, pg_strcasecmp(), S_IRUSR, S_ISREG, S_IXUSR, stat, and strlcpy().

Referenced by find_my_exec(), and find_other_exec().

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