225 lines
6.7 KiB
C
225 lines
6.7 KiB
C
/* Relocating wrapper program.
|
|
Copyright (C) 2003, 2005-2007, 2009-2022 Free Software Foundation, Inc.
|
|
Written by Bruno Haible <bruno@clisp.org>, 2003.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
/* Dependencies:
|
|
relocwrapper
|
|
-> progname
|
|
-> progreloc
|
|
-> stat
|
|
-> filename
|
|
-> pathmax
|
|
-> verify
|
|
-> areadlink
|
|
-> careadlinkat
|
|
-> allocator
|
|
-> readlink
|
|
-> stat
|
|
-> canonicalize-lgpl
|
|
-> libc-config
|
|
-> errno
|
|
-> fcntl-h
|
|
-> stdbool
|
|
-> sys_stat
|
|
-> unistd
|
|
-> eloop-threshold
|
|
-> filename
|
|
-> idx
|
|
-> intprops
|
|
-> scratch_buffer
|
|
-> malloc-posix
|
|
-> realloc-posix
|
|
-> free-posix
|
|
-> pathmax
|
|
-> mempcpy
|
|
-> rawmemchr
|
|
-> readlink
|
|
-> stat
|
|
-> double-slash-root
|
|
-> relocatable
|
|
-> setenv
|
|
-> malloca
|
|
-> fprintf-posix [ignore, cut dependency tree here]
|
|
-> strerror [ignore, cut dependency tree here]
|
|
-> c-ctype
|
|
|
|
Macros that need to be set while compiling this file:
|
|
- ENABLE_RELOCATABLE 1
|
|
- INSTALLPREFIX the base installation directory
|
|
- INSTALLDIR the directory into which this program is installed
|
|
- LIBPATHVAR the platform dependent runtime library path variable
|
|
- LIBDIRS a comma-terminated list of strings representing the list of
|
|
directories that contain the libraries at installation time
|
|
|
|
We don't want to internationalize this wrapper because then it would
|
|
depend on libintl and therefore need relocation itself. So use only
|
|
libc functions, no gettext(), no error(), no xmalloc(), no xsetenv().
|
|
*/
|
|
|
|
#define _GL_USE_STDLIB_ALLOC 1
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include "progname.h"
|
|
#include "relocatable.h"
|
|
#include "c-ctype.h"
|
|
#include "verify.h"
|
|
|
|
/* Use the system functions, not the gnulib overrides in this file. */
|
|
#undef fprintf
|
|
#undef strerror
|
|
|
|
/* Return a copy of the filename, with an extra ".bin" at the end.
|
|
More generally, it replaces "${EXEEXT}" at the end with ".bin${EXEEXT}". */
|
|
static char *
|
|
add_dotbin (const char *filename)
|
|
{
|
|
size_t filename_len = strlen (filename);
|
|
char *result = (char *) malloc (filename_len + 4 + 1);
|
|
|
|
if (result != NULL)
|
|
{
|
|
if (sizeof (EXEEXT) > sizeof (""))
|
|
{
|
|
/* EXEEXT handling. */
|
|
const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
|
|
static const char exeext[] = EXEEXT;
|
|
if (filename_len > exeext_len)
|
|
{
|
|
/* Compare using an inlined copy of c_strncasecmp(), because
|
|
the filenames may have undergone a case conversion since
|
|
they were packaged. In other words, EXEEXT may be ".exe"
|
|
on one system and ".EXE" on another. */
|
|
const char *s1 = filename + filename_len - exeext_len;
|
|
const char *s2 = exeext;
|
|
for (; *s1 != '\0'; s1++, s2++)
|
|
{
|
|
unsigned char c1 = *s1;
|
|
unsigned char c2 = *s2;
|
|
if (c_tolower (c1) != c_tolower (c2))
|
|
goto simple_append;
|
|
}
|
|
/* Insert ".bin" before EXEEXT or its equivalent. */
|
|
memcpy (result, filename, filename_len - exeext_len);
|
|
memcpy (result + filename_len - exeext_len, ".bin", 4);
|
|
memcpy (result + filename_len - exeext_len + 4,
|
|
filename + filename_len - exeext_len,
|
|
exeext_len + 1);
|
|
return result;
|
|
}
|
|
}
|
|
simple_append:
|
|
/* Simply append ".bin". */
|
|
memcpy (result, filename, filename_len);
|
|
memcpy (result + filename_len, ".bin", 4 + 1);
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
/* List of directories that contain the libraries. */
|
|
static const char *libdirs[] = { LIBDIRS NULL };
|
|
/* Verify that at least one directory is given. */
|
|
verify (sizeof (libdirs) / sizeof (libdirs[0]) > 1);
|
|
|
|
/* Relocate the list of directories that contain the libraries. */
|
|
static void
|
|
relocate_libdirs ()
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
|
|
libdirs[i] = relocate (libdirs[i]);
|
|
}
|
|
|
|
/* Activate the list of directories in the LIBPATHVAR. */
|
|
static void
|
|
activate_libdirs ()
|
|
{
|
|
const char *old_value;
|
|
size_t total;
|
|
size_t i;
|
|
char *value;
|
|
char *p;
|
|
|
|
old_value = getenv (LIBPATHVAR);
|
|
if (old_value == NULL)
|
|
old_value = "";
|
|
|
|
total = 0;
|
|
for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
|
|
total += strlen (libdirs[i]) + 1;
|
|
total += strlen (old_value) + 1;
|
|
|
|
value = (char *) malloc (total);
|
|
if (value == NULL)
|
|
{
|
|
fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
|
|
exit (1);
|
|
}
|
|
p = value;
|
|
for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
|
|
{
|
|
size_t len = strlen (libdirs[i]);
|
|
memcpy (p, libdirs[i], len);
|
|
p += len;
|
|
*p++ = ':';
|
|
}
|
|
if (old_value[0] != '\0')
|
|
strcpy (p, old_value);
|
|
else
|
|
p[-1] = '\0';
|
|
|
|
if (setenv (LIBPATHVAR, value, 1) < 0)
|
|
{
|
|
fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
char *full_program_name;
|
|
|
|
/* Set the program name and perform preparations for
|
|
get_full_program_name() and relocate(). */
|
|
set_program_name_and_installdir (argv[0], INSTALLPREFIX, INSTALLDIR);
|
|
|
|
/* Get the full program path. (Important if accessed through a symlink.) */
|
|
full_program_name = get_full_program_name ();
|
|
if (full_program_name == NULL)
|
|
full_program_name = argv[0];
|
|
|
|
/* Invoke the real program, with suffix ".bin". */
|
|
argv[0] = add_dotbin (full_program_name);
|
|
relocate_libdirs ();
|
|
activate_libdirs ();
|
|
execv (argv[0], argv);
|
|
fprintf (stderr, "%s: could not execute %s: %s\n",
|
|
program_name, argv[0], strerror (errno));
|
|
exit (127);
|
|
}
|