/*
This file is part of GNUnet.
Copyright (C) 2006-2018 GNUnet e.V.
GNUnet 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, or (at your
option) any later version.
GNUnet 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 GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/**
* @file src/util/os_installation.c
* @brief get paths used by the program
* @author Milan
* @author Christian Fuchs
* @author Christian Grothoff
* @author Matthias Wachs
* @author Heikki Lindholm
* @author LRN
*/
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <unistr.h> /* for u16_to_u8 */
#include "platform.h"
#include "gnunet_util_lib.h"
#if DARWIN
#include <mach-o/ldsyms.h>
#include <mach-o/dyld.h>
#elif WINDOWS
#include <windows.h>
#endif
#define LOG(kind,...) GNUNET_log_from (kind, "util-os-installation", __VA_ARGS__)
#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-os-installation", syscall, filename)
/**
* Default project data used for installation path detection
* for GNUnet (core).
*/
static const struct GNUNET_OS_ProjectData default_pd = {
.libname = "libgnunetutil",
.project_dirname = "gnunet",
.binary_name = "gnunet-arm",
.env_varname = "GNUNET_PREFIX",
.base_config_varname = "GNUNET_BASE_CONFIG",
.bug_email = "gnunet-developers@gnu.org",
.homepage = "http://www.gnu.org/s/gnunet/",
.config_file = "gnunet.conf",
.user_config_file = "~/.config/gnunet.conf",
};
/**
* Which project data do we currently use for installation
* path detection? Never NULL.
*/
static const struct GNUNET_OS_ProjectData *current_pd = &default_pd;
/**
* Return default project data used by 'libgnunetutil' for GNUnet.
*/
const struct GNUNET_OS_ProjectData *
GNUNET_OS_project_data_default (void)
{
return &default_pd;
}
/**
* @return current project data.
*/
const struct GNUNET_OS_ProjectData *
GNUNET_OS_project_data_get ()
{
return current_pd;
}
/**
* Setup OS subsystem with project data.
*
* @param pd project data used to determine paths
*/
void
GNUNET_OS_init (const struct GNUNET_OS_ProjectData *pd)
{
GNUNET_assert (NULL != pd);
current_pd = pd;
}
#if LINUX
/**
* Try to determine path by reading /proc/PID/exe
*
* @return NULL on error
*/
static char *
get_path_from_proc_maps ()
{
char fn[64];
char line[1024];
char dir[1024];
FILE *f;
char *lgu;
GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
if (NULL == (f = FOPEN (fn, "r")))
return NULL;
while (NULL != fgets (line, sizeof (line), f))
{
if ((1 ==
SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
(NULL != (lgu = strstr (dir,
current_pd->libname))))
{
lgu[0] = '\0';
FCLOSE (f);
return GNUNET_strdup (dir);
}
}
FCLOSE (f);
return NULL;
}
/**
* Try to determine path by reading /proc/PID/exe
*
* @return NULL on error
*/
static char *
get_path_from_proc_exe ()
{
char fn[64];
char lnk[1024];
ssize_t size;
char *lep;
GNUNET_snprintf (fn,
sizeof (fn),
"/proc/%u/exe",
getpid ());
size = readlink (fn,
lnk,
sizeof (lnk) - 1);
if (size <= 0)
{
LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR,
"readlink",
fn);
return NULL;
}
GNUNET_assert ( ((size_t) size) < sizeof (lnk));
lnk[size] = '\0';
while ((lnk[size] != '/') && (size > 0))
size--;
GNUNET_asprintf (&lep,
"/%s/libexec/",
current_pd->project_dirname);
/* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */
if ( (((size_t) size) > strlen (lep)) &&
(0 == strcmp (lep,
&lnk[size - strlen (lep)])) )
size -= strlen (lep) - 1;
GNUNET_free (lep);
if ( (size < 4) ||
(lnk[size - 4] != '/') )
{
/* not installed in "/bin/" -- binary path probably useless */
return NULL;
}
lnk[size] = '\0';
return GNUNET_strdup (lnk);
}
#endif
#if WINDOWS
static HINSTANCE dll_instance;
/**
* GNUNET_util_cl_init() in common_logging.c is preferred.
* This function is only for thread-local storage (not used in GNUnet)
* and hInstance saving.
*/
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch