Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

abstract in-tree detection into libutil, remove FLUX_CONF_INTREE environment variable #2351

Merged
merged 7 commits into from
Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 12 additions & 64 deletions src/cmd/flux.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h>
#include <stdbool.h>
#include <sys/param.h>
#include <glob.h>
#include <assert.h>
#include <flux/core.h>
Expand All @@ -27,6 +25,7 @@
#include "src/common/libutil/log.h"
#include "src/common/libutil/xzmalloc.h"
#include "src/common/libutil/environment.h"
#include "src/common/libutil/intree.h"

#include "cmdhelp.h"
#include "builtin.h"
Expand Down Expand Up @@ -198,8 +197,6 @@ int main (int argc, char *argv[])
flux_conf_get ("rc3_path", flags), 0);
environment_from_env (env, "FLUX_PMI_LIBRARY_PATH",
flux_conf_get ("pmi_library_path", flags), 0);
if ((flags & CONF_FLAG_INTREE))
environment_push (env, "FLUX_CONF_INTREE", "1");

environment_apply (env);

Expand Down Expand Up @@ -230,63 +227,12 @@ int main (int argc, char *argv[])
return 0;
}

/* Strip trailing ".libs", otherwise do nothing
*/
char *strip_trailing_dot_libs (char *dir)
{
char *p = dir + strlen (dir) - 1;
if ( (*(p--) == 's')
&& (*(p--) == 'b')
&& (*(p--) == 'i')
&& (*(p--) == 'l')
&& (*(p--) == '.')
&& (*p == '/') )
*p = '\0';
return (dir);
}

/* Return directory containing this executable. Caller must free.
* (using non-portable /proc/self/exe support for now)
* NOTE: build tree .libs directory stripped from path if found.
*/
char *dir_self (void)
{
static char flux_exe_path [MAXPATHLEN];
static char *flux_exe_dir;
static bool exe_path_valid = false;
if (!exe_path_valid) {
memset (flux_exe_path, 0, MAXPATHLEN);
if (readlink ("/proc/self/exe", flux_exe_path, MAXPATHLEN - 1) < 0)
log_err_exit ("readlink (/proc/self/exe)");
flux_exe_dir = strip_trailing_dot_libs (dirname (flux_exe_path));
exe_path_valid = true;
}
return xstrdup (flux_exe_dir);
}

bool flux_is_installed (void)
{
const char *conf_bindir = flux_conf_get ("bindir", CONF_FLAG_INTREE);
char *selfdir = dir_self ();
char *bindir = NULL;
bool ret = true;
/*
* Calling realpath(3) with NULL second arg is safe since POSIX.1-2008.
* (Equivalent to glibc's canonicalize_path_name(3))
*
* If realpath(3) returns ENOENT, then BINDIR doesn't exist and flux
* clearly can't be from the installed path:
*/

if (!(bindir = realpath (conf_bindir, NULL))
&& (errno != ENOENT)
&& (errno != EACCES))
log_err_exit ("realpath (%s)", conf_bindir);
else if (bindir && !strcmp (selfdir, bindir))
ret = false;
free (selfdir);
free (bindir);
return ret;
int rc = executable_is_intree ();
if (rc < 0)
log_err_exit ("Failed to to determine if flux is installed");
return (rc == 0);
}

/*
Expand All @@ -298,16 +244,18 @@ bool flux_is_installed (void)
*/
void setup_path (struct environment *env, const char *argv0)
{
char *selfdir;
const char *selfdir = NULL;
assert (argv0);

/* If argv[0] was explicitly "flux" then assume PATH is already set */
if (strcmp (argv0, "flux") == 0)
return;
environment_from_env (env, "PATH", "/bin:/usr/bin", ':');
selfdir = dir_self ();
environment_push (env, "PATH", selfdir);
free (selfdir);
if ((selfdir = executable_selfdir ())) {
environment_from_env (env, "PATH", "/bin:/usr/bin", ':');
environment_push (env, "PATH", executable_selfdir ());
}
else
log_msg_exit ("Unable to determine flux executable dir");
}

void setup_keydir (struct environment *env, int flags)
Expand Down
14 changes: 11 additions & 3 deletions src/common/libutil/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ AM_LDFLAGS = \
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_srcdir)/src/include \
-I$(top_builddir)/src/common/libflux
-I$(top_builddir)/src/common/libflux \
-DABS_TOP_BUILDDIR=\"$(abs_top_builddir)\"

noinst_LTLIBRARIES = libutil.la

Expand Down Expand Up @@ -89,7 +90,9 @@ libutil_la_SOURCES = \
fsd.h \
zsecurity.c \
zsecurity.h \
errno_safe.h
errno_safe.h \
intree.c \
intree.h

EXTRA_DIST = veb_mach.c

Expand All @@ -116,7 +119,8 @@ TESTS = test_ev.t \
test_aux.t \
test_fdutils.t \
test_fsd.t \
test_zsecurity.t
test_zsecurity.t \
test_intree.t


test_ldadd = \
Expand Down Expand Up @@ -237,3 +241,7 @@ test_fsd_t_LDADD = $(test_ldadd)
test_zsecurity_t_SOURCES = test/zsecurity.c
test_zsecurity_t_CPPFLAGS = $(test_cppflags)
test_zsecurity_t_LDADD = $(test_ldadd)

test_intree_t_SOURCES = test/intree.c
test_intree_t_CPPFLAGS = $(test_cppflags)
test_intree_t_LDADD = $(test_ldadd)
101 changes: 101 additions & 0 deletions src/common/libutil/intree.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/************************************************************\
* Copyright 2019 Lawrence Livermore National Security, LLC
* (c.f. AUTHORS, NOTICE.LLNS, COPYING)
*
* This file is part of the Flux resource manager framework.
* For details, see https://github.com/flux-framework.
*
* SPDX-License-Identifier: LGPL-3.0
\************************************************************/

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/param.h> /* MAXPATHLEN */
#include <libgen.h> /* dirname(3) */
#include <pthread.h>


/* Strip trailing ".libs", otherwise do nothing
*/
static char *strip_trailing_dot_libs (char *dir)
{
char *p = dir + strlen (dir) - 1;
if ( (*(p--) == 's')
&& (*(p--) == 'b')
&& (*(p--) == 'i')
&& (*(p--) == 'l')
&& (*(p--) == '.')
&& (*p == '/') )
*p = '\0';
return (dir);
}

/* Return directory containing this executable.
*/
const char *executable_selfdir (void)
{
static pthread_mutex_t selfdir_lock = PTHREAD_MUTEX_INITIALIZER;
static char current_exe_path [MAXPATHLEN];
static char *current_exe_dir = NULL;
pthread_mutex_lock (&selfdir_lock);
if (!current_exe_dir) {
memset (current_exe_path, 0, sizeof (current_exe_path));
if (readlink ("/proc/self/exe", current_exe_path, MAXPATHLEN - 1) < 0)
goto out;
current_exe_dir = strip_trailing_dot_libs (dirname (current_exe_path));
}
out:
pthread_mutex_unlock (&selfdir_lock);
return current_exe_dir;
}

/* Check if the path to the current executable is in a subdirectory
* of the top build directory of flux-core. This should work to detect
* if an executable is running in-tree no matter where in the build
* tree that executable was built.
*/
static int is_intree (void)
{
const char *selfdir = NULL;
char *builddir = NULL;
int ret = 0;

if (!(selfdir = executable_selfdir ()))
return -1;
/*
* Calling realpath(3) with NULL second arg is safe since POSIX.1-2008.
* (Equivalent to glibc's canonicalize_path_name(3))
*
* If realpath(3) returns ENOENT, then BINDIR doesn't exist and flux
* clearly can't be from the installed path:
*/
if (!(builddir = realpath (ABS_TOP_BUILDDIR, NULL))
&& (errno != ENOENT)
&& (errno != EACCES))
ret = -1;
else if (strncmp (builddir, selfdir, strlen (builddir)) == 0)
ret = 1;
free (builddir);
return ret;
}

int executable_is_intree (void)
{
static pthread_mutex_t intree_lock = PTHREAD_MUTEX_INITIALIZER;
static int current_exe_intree = -1;
/* If uninitialized, initialize current_exe_intree now */
pthread_mutex_lock (&intree_lock);
if (current_exe_intree < 0)
current_exe_intree = is_intree ();
pthread_mutex_unlock (&intree_lock);
return current_exe_intree;
}

/* vi: ts=4 sw=4 expandtab
*/
30 changes: 30 additions & 0 deletions src/common/libutil/intree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/************************************************************\
* Copyright 2019 Lawrence Livermore National Security, LLC
* (c.f. AUTHORS, NOTICE.LLNS, COPYING)
*
* This file is part of the Flux resource manager framework.
* For details, see https://github.com/flux-framework.
*
* SPDX-License-Identifier: LGPL-3.0
\************************************************************/

#ifndef _UTIL_INTREE_H
#define _UTIL_INTREE_H

/* Check if the current executable was started from a build tree,
* i.e. if top_builddir is a prefix of the pat the the current
* executable.
*
* Returns 1 if executable was started from the build tree, 0 if
* not and -1 on any error.
*/
int executable_is_intree (void);

/* Return the directory containing the current executable.
*/
const char *executable_selfdir (void);

#endif /* !_UTIL_INTREE_H */
/*
* vi:tabstop=4 shiftwidth=4 expandtab
*/
74 changes: 74 additions & 0 deletions src/common/libutil/test/intree.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/************************************************************\
* Copyright 2019 Lawrence Livermore National Security, LLC
* (c.f. AUTHORS, NOTICE.LLNS, COPYING)
*
* This file is part of the Flux resource manager framework.
* For details, see https://github.com/flux-framework.
*
* SPDX-License-Identifier: LGPL-3.0
\************************************************************/

#include <string.h>
#include <errno.h>
#include <pthread.h>

#include "src/common/libtap/tap.h"
#include "src/common/libutil/intree.h"

#define NTHREADS 16

static pthread_barrier_t barrier;

static void *thd_intree (void *arg)
{
int *resultp = arg;
int e;
if ((e = pthread_barrier_wait (&barrier))
&& e != PTHREAD_BARRIER_SERIAL_THREAD)
BAIL_OUT ("pthread_barrier_wait: %s %s", strerror (e), strerror (errno));
*resultp = executable_is_intree ();
return NULL;
}

int main (int argc, char *argv[])
{
pthread_t threads [NTHREADS];
int results [NTHREADS];
int i;
plan (NO_PLAN);

ok (executable_is_intree (),
"executable_is_intree() works");
like (executable_selfdir (), ".*/src/common/libutil",
"executable_selfdir() works");

if (pthread_barrier_init (&barrier, NULL, NTHREADS))
BAIL_OUT ("pthread_barrier_init");

for (i = 0; i < NTHREADS; i++) {
int e = pthread_create (&threads[i], NULL, thd_intree, &results[i]);
if (e)
BAIL_OUT ("pthread_create");
}
int pass = 1;
for (i = 0; i < NTHREADS; i++) {
if (pthread_join (threads[i], NULL))
BAIL_OUT ("pthread_join");
if (results[i] != 1) {
pass = 0;
fail ("thread %d: executable_is_intree() returned %d",
i, results[i]);
}
}

ok (pass == 1,
"%d threads ran executable_is_intree sucessfully", NTHREADS);

pthread_barrier_destroy (&barrier);
done_testing ();
return 0;
};

/*
* vi:tabstop=4 shiftwidth=4 expandtab
*/
Loading