93 lines
2.8 KiB
C
93 lines
2.8 KiB
C
#define _GNU_SOURCE
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
static void fail(const char *message)
|
|
{
|
|
fprintf(stderr, "embedded PostgreSQL launcher: %s\n", message);
|
|
exit(127);
|
|
}
|
|
|
|
static void join_path(char *destination, size_t capacity, const char *left, const char *right)
|
|
{
|
|
int length = snprintf(destination, capacity, "%s/%s", left, right);
|
|
if (length < 0 || (size_t) length >= capacity)
|
|
fail("installation path is too long");
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char executable[PATH_MAX];
|
|
ssize_t executable_length = readlink("/proc/self/exe", executable, sizeof(executable) - 1);
|
|
if (executable_length < 0) {
|
|
perror("embedded PostgreSQL launcher: /proc/self/exe");
|
|
return 127;
|
|
}
|
|
executable[executable_length] = '\0';
|
|
|
|
char *tool = strrchr(executable, '/');
|
|
if (tool == NULL || tool[1] == '\0')
|
|
fail("cannot determine the requested PostgreSQL tool");
|
|
tool++;
|
|
|
|
char root[PATH_MAX];
|
|
if ((size_t) executable_length >= sizeof(root))
|
|
fail("installation path is too long");
|
|
memcpy(root, executable, (size_t) executable_length + 1);
|
|
|
|
char *bin_separator = strrchr(root, '/');
|
|
if (bin_separator == NULL)
|
|
fail("cannot determine the PostgreSQL installation directory");
|
|
*bin_separator = '\0';
|
|
char *root_separator = strrchr(root, '/');
|
|
if (root_separator == NULL)
|
|
fail("cannot determine the PostgreSQL installation directory");
|
|
*root_separator = '\0';
|
|
|
|
char loader[PATH_MAX];
|
|
char library_path[PATH_MAX];
|
|
char real_tool[PATH_MAX];
|
|
join_path(loader, sizeof(loader), root, "lib/ld-musl-x86_64.so.1");
|
|
join_path(library_path, sizeof(library_path), root, "lib");
|
|
|
|
char real_tool_relative[PATH_MAX];
|
|
int relative_length = snprintf(
|
|
real_tool_relative,
|
|
sizeof(real_tool_relative),
|
|
"libexec/%s",
|
|
tool
|
|
);
|
|
if (relative_length < 0 || (size_t) relative_length >= sizeof(real_tool_relative))
|
|
fail("tool path is too long");
|
|
join_path(real_tool, sizeof(real_tool), root, real_tool_relative);
|
|
|
|
char **loader_argv = calloc((size_t) argc + 6, sizeof(char *));
|
|
if (loader_argv == NULL) {
|
|
perror("embedded PostgreSQL launcher: calloc");
|
|
return 127;
|
|
}
|
|
|
|
loader_argv[0] = loader;
|
|
loader_argv[1] = "--library-path";
|
|
loader_argv[2] = library_path;
|
|
loader_argv[3] = "--argv0";
|
|
loader_argv[4] = executable;
|
|
loader_argv[5] = real_tool;
|
|
for (int index = 1; index < argc; index++)
|
|
loader_argv[index + 5] = argv[index];
|
|
|
|
execv(loader, loader_argv);
|
|
fprintf(
|
|
stderr,
|
|
"embedded PostgreSQL launcher: cannot execute %s: %s\n",
|
|
real_tool,
|
|
strerror(errno)
|
|
);
|
|
return 127;
|
|
}
|