From ea1d8c004c8d70b20a1ee910f75abb5a68ace9e0 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 20 Aug 2003 19:45:05 +0000 Subject: [PATCH] New module 'progname'. --- ChangeLog | 5 + MODULES.html.sh | 1 + lib/ChangeLog | 6 + lib/progname.c | 54 +++++++++ lib/progname.h | 54 +++++++++ lib/progreloc.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++ modules/progname | 21 ++++ 7 files changed, 434 insertions(+) create mode 100644 lib/progname.c create mode 100644 lib/progname.h create mode 100644 lib/progreloc.c create mode 100644 modules/progname diff --git a/ChangeLog b/ChangeLog index efadfbb842..6455977843 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-08-20 Bruno Haible + + * modules/progname: New file. + * MODULES.html.sh (func_all_modules): Add progname. + 2003-08-18 Paul Eggert * modules/stdbool: Add BUILT_SOURCES. Prefer $@ to target name diff --git a/MODULES.html.sh b/MODULES.html.sh index 82334f0a56..76b705e249 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1892,6 +1892,7 @@ func_all_modules () func_module getusershell func_module physmem func_module posixver + func_module progname func_module quotearg func_module quote func_module readutmp diff --git a/lib/ChangeLog b/lib/ChangeLog index ad78dc7b5a..a1e5888d78 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,9 @@ +2003-08-20 Bruno Haible + + * progname.h: New file, from GNU gettext with modifications. + * progname.c: New file, from GNU gettext with modifications. + * progreloc.c: New file. + 2003-08-19 Bruno Haible * xstrdup.c: Assume exists. diff --git a/lib/progname.c b/lib/progname.c new file mode 100644 index 0000000000..2a49763159 --- /dev/null +++ b/lib/progname.c @@ -0,0 +1,54 @@ +/* Program name management. + Copyright (C) 2001-2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2001. + + 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 2, 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Specification. */ +#include "progname.h" + +#include +#include + +#undef set_program_name + + +/* String containing name the program is called with. + To be initialized by main(). */ +const char *program_name; + +/* Set program_name, based on argv[0]. */ +void +set_program_name (const char *argv0) +{ + /* libtool creates a temporary executable whose name is sometimes prefixed + with "lt-" (depends on the platform). It also makes argv[0] absolute. + Remove this "/.libs/" or "/.libs/lt-" prefix here. */ + const char *slash; + const char *base; + + slash = strrchr (argv0, '/'); + base = (slash != NULL ? slash + 1 : argv0); + if (base - argv0 >= 7 && memcmp (base - 7, "/.libs/", 7) == 0) + argv0 = base; + if (strncmp (base, "lt-", 3) == 0) + argv0 = base + 3; + program_name = argv0; +} diff --git a/lib/progname.h b/lib/progname.h new file mode 100644 index 0000000000..8b0eeda86f --- /dev/null +++ b/lib/progname.h @@ -0,0 +1,54 @@ +/* Program name management. + Copyright (C) 2001-2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2001. + + 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 2, 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PROGNAME_H +#define _PROGNAME_H + +#include + +/* This file supports selectively prefixing or nor prefixing error messages + with the program name. + + Programs using this file should do the following in main(): + set_program_name (argv[0]); + error_print_progname = maybe_print_progname; + */ + +/* String containing name the program is called with. */ +extern const char *program_name; + +/* Set program_name, based on argv[0]. */ +extern void set_program_name (const char *argv0); + +#if ENABLE_RELOCATABLE + +/* Set program_name, based on argv[0], and original installation prefix and + directory, for relocatability. */ +extern void set_program_name_and_installdir (const char *argv0, + const char *orig_installprefix, + const char *orig_installdir); +#define set_program_name(ARG0) \ + set_program_name_and_installdir (ARG0, INSTALLPREFIX, INSTALLDIR) + +/* Return the full pathname of the current executable, based on the earlier + call to set_program_name_and_installdir. Return NULL if unknown. */ +extern char *get_full_program_name (void); + +#endif + +#endif /* _PROGNAME_H */ diff --git a/lib/progreloc.c b/lib/progreloc.c new file mode 100644 index 0000000000..cda55a76e9 --- /dev/null +++ b/lib/progreloc.c @@ -0,0 +1,293 @@ +/* Provide relocatable programs. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Specification. */ +#include "progname.h" + +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +# include +#endif +#include + +#if defined _WIN32 || defined __WIN32__ +# undef WIN32 /* avoid warning on mingw32 */ +# define WIN32 +#endif + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include +#endif + +#include "xreadlink.h" +#include "canonicalize.h" +#include "relocatable.h" + +#ifdef NO_XMALLOC +# define xmalloc malloc +#else +# include "xmalloc.h" +#endif + +/* Pathname support. + ISSLASH(C) tests whether C is a directory separator character. + IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. + */ +#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ + /* Win32, OS/2, DOS */ +# define ISSLASH(C) ((C) == '/' || (C) == '\\') +# define HAS_DEVICE(P) \ + ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ + && (P)[1] == ':') +# define IS_PATH_WITH_DIR(P) \ + (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) +# define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) +#else + /* Unix */ +# define ISSLASH(C) ((C) == '/') +# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) +# define FILESYSTEM_PREFIX_LEN(P) 0 +#endif + +#undef set_program_name + + +#if ENABLE_RELOCATABLE + +#ifdef __linux__ +/* File descriptor of the executable. + (Only used to verify that we find the correct executable.) */ +static int executable_fd = -1; +#endif + +/* Tests whether a given pathname may belong to the executable. */ +static bool +maybe_executable (const char *filename) +{ +#if !defined WIN32 + if (access (filename, X_OK) < 0) + return false; + +#ifdef __linux__ + if (executable_fd >= 0) + { + /* If we already have an executable_fd, check that filename points to + the same inode. */ + struct stat statexe; + struct stat statfile; + + if (fstat (executable_fd, &statexe) >= 0) + { + if (stat (filename, &statfile) < 0) + return false; + if (!(statfile.st_dev + && statfile.st_dev == statexe.st_dev + && statfile.st_ino == statexe.st_ino)) + return false; + } + } +#endif +#endif + + return true; +} + +/* Determine the full pathname of the current executable, freshly allocated. + Return NULL if unknown. + Guaranteed to work on Linux and Woe32. Likely to work on the other + Unixes (maybe except BeOS), under most conditions. */ +static char * +find_executable (const char *argv0) +{ +#ifdef WIN32 + char buf[1024]; + int length = GetModuleFileName (NULL, buf, sizeof (buf)); + if (length < 0) + return NULL; + if (!IS_PATH_WITH_DIR (buf)) + /* Shouldn't happen. */ + return NULL; + return xstrdup (buf); +#else /* Unix */ +#ifdef __linux__ + /* The executable is accessible as /proc//exe. In newer Linux + versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink + to the true pathname; older Linux versions give only device and ino, + enclosed in brackets, which we cannot use here. */ + { + char *link; + + link = xreadlink ("/proc/self/exe"); + if (link != NULL && link[0] != '[') + return link; + if (executable_fd < 0) + executable_fd = open ("/proc/self/exe", O_RDONLY, 0); + + { + char buf[6+10+5]; + sprintf (buf, "/proc/%d/exe", getpid ()); + link = xreadlink (buf); + if (link != NULL && link[0] != '[') + return link; + if (executable_fd < 0) + executable_fd = open (buf, O_RDONLY, 0); + } + } +#endif + /* Guess the executable's full path. We assume the executable has been + called via execlp() or execvp() with properly set up argv[0]. The + login(1) convention to add a '-' prefix to argv[0] is not supported. */ + { + bool has_slash = false; + { + const char *p; + for (p = argv0; *p; p++) + if (*p == '/') + { + has_slash = true; + break; + } + } + if (!has_slash) + { + /* exec searches paths without slashes in the directory list given + by $PATH. */ + const char *path = getenv ("PATH"); + + if (path != NULL) + { + const char *p; + const char *p_next; + + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + char *concat_name; + + for (q = p; *q; q++) + if (*q == ':') + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + + /* We have a path item at p, of length p_len. + Now concatenate the path item and argv0. */ + concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2); +#ifdef NO_XMALLOC + if (concat_name == NULL) + return NULL; +#endif + if (p_len == 0) + /* An empty PATH element designates the current directory. */ + strcpy (concat_name, argv0); + else + { + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, argv0); + } + if (maybe_executable (concat_name)) + return canonicalize_file_name (concat_name); + free (concat_name); + } + } + /* Not found in the PATH, assume the current directory. */ + } + /* exec treats paths containing slashes as relative to the current + directory. */ + if (maybe_executable (argv0)) + return canonicalize_file_name (argv0); + } + /* No way to find the executable. */ + return NULL; +#endif +} + +/* Full pathname of executable, or NULL. */ +static char *executable_fullname; + +static void +prepare_relocate (const char *orig_installprefix, const char *orig_installdir, + const char *argv0) +{ + const char *curr_prefix; + + /* Determine the full pathname of the current executable. */ + executable_fullname = find_executable (argv0); + + /* Determine the current installation prefix from it. */ + curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir, + executable_fullname); + if (curr_prefix != NULL) + /* Now pass this prefix to all copies of the relocate.c source file. */ + set_relocation_prefix (orig_installprefix, curr_prefix); +} + +/* Set program_name, based on argv[0], and original installation prefix and + directory, for relocatability. */ +void +set_program_name_and_installdir (const char *argv0, + const char *orig_installprefix, + const char *orig_installdir) +{ + const char *argv0_stripped = argv0; + + /* Relocatable programs are renamed to .bin by install-reloc. Remove + this suffix here. */ + { + size_t argv0_len = strlen (argv0); + if (argv0_len > 4 && memcmp (argv0 + argv0_len - 4, ".bin", 4) == 0) + { + char *shorter = (char *) xmalloc (argv0_len - 4 + 1); +#ifdef NO_XMALLOC + if (shorter != NULL) +#endif + { + memcpy (shorter, argv0, argv0_len - 4); + shorter[argv0_len - 4] = '\0'; + argv0_stripped = shorter; + } + } + } + + set_program_name (argv0_stripped); + + prepare_relocate (orig_installprefix, orig_installdir, argv0); +} + +/* Return the full pathname of the current executable, based on the earlier + call to set_program_name_and_installdir. Return NULL if unknown. */ +char * +get_full_program_name () +{ + return executable_fullname; +} + +#endif diff --git a/modules/progname b/modules/progname new file mode 100644 index 0000000000..fb9d73e809 --- /dev/null +++ b/modules/progname @@ -0,0 +1,21 @@ +Description: +Program name management. + +Files: +lib/progname.h +lib/progname.c + +Depends-on: +stdbool + +configure.ac: + +Makefile.am: +lib_SOURCES += progname.h progname.c + +Include: +"progname.h" + +Maintainer: +Bruno Haible + -- 2.30.2