You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
6.3 KiB
206 lines
6.3 KiB
/* Relocating wrapper program. |
|
Copyright (C) 2003, 2005-2007, 2009-2017 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 <http://www.gnu.org/licenses/>. */ |
|
|
|
/* Dependencies: |
|
relocwrapper |
|
-> progname |
|
-> progreloc |
|
-> areadlink |
|
-> careadlinkat |
|
-> allocator |
|
-> readlink |
|
-> stat |
|
-> dosname |
|
-> pathmax |
|
-> verify |
|
-> canonicalize-lgpl |
|
-> malloca |
|
-> lstat |
|
-> readlink |
|
-> 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); |
|
}
|
|
|