mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
common: Support a gpgconf.ctl file under Unix.
* common/homedir.c (unix_rootdir): New. (gnupg_bindir): Use it. (gnupg_libexecdir): Use it. (gnupg_libdir): Use it. (gnupg_datadir): Use it. (gnupg_localedir): Use it. -- This feature is useful for building and using an AppImage version of gnupg and probably also for some other use cases. GnuPG-bug-id: 5999 Here is a sample gpgconf.ctl file --8<---------------cut here---------------start------------->8--- # gpgconf.ctl # # This file is used to change the directories where the gpg components # are installed. It does not change the configuration directories. # The file is expected in the same directory as gpgconf. The physical # installation directories are evaluated and no symlinks. Blank lines # and lines starting with pound signed are ignored. No errors are # printed for unknown keywords or commands. The only defined key for # now is "rootdir" which must be followed by one optional space, an # equal sign, and the value for the root directory. Environment # variables are substituted in standard shell manner, the final value # must start with a slash, trailing slashed are stripped. rootdir = $APPDIR/gnupg --8<---------------cut here---------------end--------------->8---
This commit is contained in:
parent
9c272dc245
commit
d4768bb982
269
common/homedir.c
269
common/homedir.c
@ -388,8 +388,10 @@ check_portable_app (const char *dir)
|
||||
}
|
||||
xfree (fname);
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* Determine the root directory of the gnupg installation on Windows. */
|
||||
static const char *
|
||||
w32_rootdir (void)
|
||||
@ -441,7 +443,180 @@ w32_rootdir (void)
|
||||
/* Fallback to the hardwired value. */
|
||||
return GNUPG_LIBEXECDIR;
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
|
||||
#ifndef HAVE_W32_SYSTEM /* Unix */
|
||||
/* Determine the root directory of the gnupg installation on Unix.
|
||||
* The standard case is that this function returns NULL so that the
|
||||
* root directory as configured at build time is used. However, it
|
||||
* may return a static string with a different root directory, similar
|
||||
* to what we do on Windows. That second mode is triggered by the
|
||||
* existence of a file gpgconf.ctl installed side-by-side to gpgconf.
|
||||
* This file is parsed for keywords describing the actually to be used
|
||||
* root directory. There is no solid standard on Unix to locate the
|
||||
* binary used to create the process, thus we support this currently
|
||||
* only on Linux where we can look this info up using the proc file
|
||||
* system. */
|
||||
static const char *
|
||||
unix_rootdir (void)
|
||||
{
|
||||
static int checked;
|
||||
static char *dir;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
char *p;
|
||||
char *buffer;
|
||||
size_t bufsize = 256-1;
|
||||
int nread;
|
||||
gpg_error_t err;
|
||||
char *line;
|
||||
size_t linelen;
|
||||
ssize_t length;
|
||||
estream_t fp;
|
||||
char *rootdir;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
buffer = xmalloc (bufsize+1);
|
||||
nread = readlink ("/proc/self/exe", buffer, bufsize);
|
||||
if (nread < 0)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_info ("error reading symlink '/proc/self/exe': %s\n",
|
||||
gpg_strerror (err));
|
||||
buffer[0] = 0;
|
||||
break;
|
||||
}
|
||||
else if (nread < bufsize)
|
||||
{
|
||||
buffer[nread] = 0;
|
||||
break; /* Got it. */
|
||||
}
|
||||
else if (bufsize >= 4095)
|
||||
{
|
||||
buffer[0] = 0;
|
||||
log_info ("error reading symlink '/proc/self/exe': %s\n",
|
||||
"value too large");
|
||||
break;
|
||||
}
|
||||
xfree (buffer);
|
||||
bufsize += 256;
|
||||
}
|
||||
if (!*buffer)
|
||||
{
|
||||
xfree (buffer);
|
||||
checked = 1;
|
||||
return NULL; /* Error - assume no gpgconf.ctl. */
|
||||
}
|
||||
|
||||
p = strrchr (buffer, '/');
|
||||
if (!p)
|
||||
{
|
||||
xfree (buffer);
|
||||
checked = 1;
|
||||
return NULL; /* Erroneous /proc - assume no gpgconf.ctl. */
|
||||
}
|
||||
*p = 0; /* BUFFER has the directory. */
|
||||
if ((p = strrchr (buffer, '/')))
|
||||
{
|
||||
/* Strip one part and expect the file below a bin dir. */
|
||||
*p = 0;
|
||||
p = xstrconcat (buffer, "/bin/gpgconf.ctl", NULL);
|
||||
xfree (buffer);
|
||||
buffer = p;
|
||||
}
|
||||
else /* !p */
|
||||
{
|
||||
/* Installed in the root which is not a good idea. Assume
|
||||
* no gpgconf.ctl. */
|
||||
xfree (buffer);
|
||||
checked = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gnupg_access (buffer, F_OK))
|
||||
{
|
||||
/* No gpgconf.ctl file. */
|
||||
xfree (buffer);
|
||||
checked = 1;
|
||||
return NULL;
|
||||
}
|
||||
/* log_info ("detected '%s'\n", buffer); */
|
||||
fp = es_fopen (buffer, "r");
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_info ("error opening '%s': %s\n", buffer, gpg_strerror (err));
|
||||
xfree (buffer);
|
||||
checked = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
line = NULL;
|
||||
linelen = 0;
|
||||
rootdir = NULL;
|
||||
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
|
||||
{
|
||||
/* Strip NL and CR, if present. */
|
||||
while (length > 0
|
||||
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
||||
line[--length] = 0;
|
||||
trim_spaces (line);
|
||||
if (!strncmp (line, "rootdir=", 8))
|
||||
p = line + 8;
|
||||
else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
|
||||
p = line + 9;
|
||||
else
|
||||
continue;
|
||||
trim_spaces (p);
|
||||
rootdir = substitute_envvars (p);
|
||||
if (!rootdir)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_info ("error getting rootdir from gpgconf.ctl: %s\n",
|
||||
gpg_strerror (err));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (length < 0 || es_ferror (fp))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_info ("error reading '%s': %s\n", buffer, gpg_strerror (err));
|
||||
es_fclose (fp);
|
||||
xfree (buffer);
|
||||
xfree (line);
|
||||
checked = 1;
|
||||
return NULL;
|
||||
}
|
||||
es_fclose (fp);
|
||||
xfree (buffer);
|
||||
xfree (line);
|
||||
|
||||
if (!rootdir || !*rootdir || *rootdir != '/')
|
||||
{
|
||||
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
|
||||
xfree (rootdir);
|
||||
dir = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
|
||||
rootdir[strlen (rootdir)-1] = 0;
|
||||
dir = rootdir;
|
||||
gpgrt_annotate_leaked_object (dir);
|
||||
/* log_info ("want rootdir '%s'\n", dir); */
|
||||
}
|
||||
checked = 1;
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
#endif /* Unix */
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static const char *
|
||||
w32_commondir (void)
|
||||
{
|
||||
@ -954,20 +1129,13 @@ gnupg_sysconfdir (void)
|
||||
const char *
|
||||
gnupg_bindir (void)
|
||||
{
|
||||
#if defined (HAVE_W32CE_SYSTEM)
|
||||
static char *name;
|
||||
|
||||
if (!name)
|
||||
name = xstrconcat (w32_rootdir (), DIRSEP_S "bin", NULL);
|
||||
return name;
|
||||
#elif defined(HAVE_W32_SYSTEM)
|
||||
const char *rdir;
|
||||
|
||||
#if defined(HAVE_W32_SYSTEM)
|
||||
rdir = w32_rootdir ();
|
||||
if (w32_bin_is_bin)
|
||||
{
|
||||
static char *name;
|
||||
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (rdir, DIRSEP_S "bin", NULL);
|
||||
@ -978,7 +1146,18 @@ gnupg_bindir (void)
|
||||
else
|
||||
return rdir;
|
||||
#else /*!HAVE_W32_SYSTEM*/
|
||||
return GNUPG_BINDIR;
|
||||
rdir = unix_rootdir ();
|
||||
if (rdir)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (rdir, DIRSEP_S "bin", NULL);
|
||||
gpgrt_annotate_leaked_object (name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
else
|
||||
return GNUPG_BINDIR;
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
}
|
||||
|
||||
@ -991,16 +1170,30 @@ gnupg_libexecdir (void)
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
return gnupg_bindir ();
|
||||
#else /*!HAVE_W32_SYSTEM*/
|
||||
return GNUPG_LIBEXECDIR;
|
||||
static char *name;
|
||||
const char *rdir;
|
||||
|
||||
rdir = unix_rootdir ();
|
||||
if (rdir)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (rdir, DIRSEP_S "libexec", NULL);
|
||||
gpgrt_annotate_leaked_object (name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
else
|
||||
return GNUPG_LIBEXECDIR;
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
}
|
||||
|
||||
const char *
|
||||
gnupg_libdir (void)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static char *name;
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (w32_rootdir (), DIRSEP_S "lib" DIRSEP_S "gnupg", NULL);
|
||||
@ -1008,16 +1201,29 @@ gnupg_libdir (void)
|
||||
}
|
||||
return name;
|
||||
#else /*!HAVE_W32_SYSTEM*/
|
||||
return GNUPG_LIBDIR;
|
||||
const char *rdir;
|
||||
|
||||
rdir = unix_rootdir ();
|
||||
if (rdir)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (rdir, DIRSEP_S "lib", DIRSEP_S, "gnupg", NULL);
|
||||
gpgrt_annotate_leaked_object (name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
else
|
||||
return GNUPG_LIBDIR;
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
}
|
||||
|
||||
const char *
|
||||
gnupg_datadir (void)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static char *name;
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (w32_rootdir (), DIRSEP_S "share" DIRSEP_S "gnupg",
|
||||
@ -1026,7 +1232,20 @@ gnupg_datadir (void)
|
||||
}
|
||||
return name;
|
||||
#else /*!HAVE_W32_SYSTEM*/
|
||||
return GNUPG_DATADIR;
|
||||
const char *rdir;
|
||||
|
||||
rdir = unix_rootdir ();
|
||||
if (rdir)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (rdir, DIRSEP_S "share" DIRSEP_S "gnupg", NULL);
|
||||
gpgrt_annotate_leaked_object (name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
else
|
||||
return GNUPG_DATADIR;
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
}
|
||||
|
||||
@ -1034,9 +1253,9 @@ gnupg_datadir (void)
|
||||
const char *
|
||||
gnupg_localedir (void)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static char *name;
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (w32_rootdir (), DIRSEP_S "share" DIRSEP_S "locale",
|
||||
@ -1045,7 +1264,20 @@ gnupg_localedir (void)
|
||||
}
|
||||
return name;
|
||||
#else /*!HAVE_W32_SYSTEM*/
|
||||
return LOCALEDIR;
|
||||
const char *rdir;
|
||||
|
||||
rdir = unix_rootdir ();
|
||||
if (rdir)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
name = xstrconcat (rdir, DIRSEP_S "share" DIRSEP_S "locale", NULL);
|
||||
gpgrt_annotate_leaked_object (name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
else
|
||||
return LOCALEDIR;
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
}
|
||||
|
||||
@ -1171,7 +1403,10 @@ static int gnupg_module_name_called;
|
||||
* be called before any invocation of 'gnupg_module_name', and must
|
||||
* not be called twice. It can be used by test suites to make sure
|
||||
* the components from the build directory are used instead of
|
||||
* potentially outdated installed ones. */
|
||||
* potentially outdated installed ones.
|
||||
* Fixme: It might be better to make use of the newer gpgconf.ctl feature
|
||||
* for regression testing.
|
||||
*/
|
||||
void
|
||||
gnupg_set_builddir (const char *newdir)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user