1
1

Added autodetect installdirs component. Currently supports Solaris and Linux.

* Installation directories will be inferred from the actual location
  of the shared library that contains the component.

* OPAL_PREFIX and other environment variables allow users to override
  the inferred directories.  They should no longer be necessary in
  most cases, though.

* Any directories that cannot be inferred will fall back to whatever
  is provided by the config installdirs component.

This commit was SVN r21723.
Этот коммит содержится в:
Iain Bason 2009-07-21 20:19:38 +00:00
родитель b3e0c79275
Коммит 2250be582d
12 изменённых файлов: 951 добавлений и 98 удалений

Просмотреть файл

@ -32,6 +32,7 @@ gwatson Greg Watson LANL
herault Thomas Herault INRIA herault Thomas Herault INRIA
hpcstork Sven Stork HLRS hpcstork Sven Stork HLRS
htor Torsten Hoefler IU, TUC htor Torsten Hoefler IU, TUC
igb Iain Bason Sun
jdmason Jon Mason Chelsio jdmason Jon Mason Chelsio
jjhursey Josh Hursey IU, ORNL, LANL, LBNL jjhursey Josh Hursey IU, ORNL, LANL, LBNL
jnysal Nysal Jan IBM jnysal Nysal Jan IBM

7
NEWS
Просмотреть файл

@ -10,7 +10,7 @@ Copyright (c) 2004-2006 The Regents of the University of California.
All rights reserved. All rights reserved.
Copyright (c) 2006-2009 Cisco Systems, Inc. All rights reserved. Copyright (c) 2006-2009 Cisco Systems, Inc. All rights reserved.
Copyright (c) 2006 Voltaire, Inc. All rights reserved. Copyright (c) 2006 Voltaire, Inc. All rights reserved.
Copyright (c) 2006 Sun Microsystems, Inc. All rights reserved. Copyright (c) 2006-2009 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms. Use is subject to license terms.
Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights
reserved. reserved.
@ -32,6 +32,11 @@ Trunk (not on release branches yet)
- Added Cray Compute Node Linux (CNL) and ALPS Support. - Added Cray Compute Node Linux (CNL) and ALPS Support.
--> Expected: ??? --> Expected: ???
- Added automatic detection of installation directories for
Solaris and Linux. The OPAL_PREFIX and OPAL_DESTDIR
environment variables no longer need to be set when binaries
are installed in non-default locations.
1.5 1.5
--- ---

26
opal/mca/installdirs/autodetect/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,26 @@
#
# Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
noinst_LTLIBRARIES = libmca_installdirs_autodetect.la
libmca_installdirs_autodetect_la_SOURCES = opal_installdirs_autodetect_component.c
EXTRA_libmca_installdirs_autodetect_la_SOURCES = \
opal_installdirs_solaris.c \
opal_installdirs_linux.c \
opal_installdirs_backtrace.c \
opal_installdirs_walkcontext.c
libmca_installdirs_autodetect_la_LIBADD = \
$(OMPI_INSTALLDIRS_AUTODETECT_PATH) \
$(OMPI_INSTALLDIRS_AUTODETECT_PC)
libmca_installdirs_autodetect_la_DEPENDENCIES = \
$(OMPI_INSTALLDIRS_AUTODETECT_PATH) \
$(OMPI_INSTALLDIRS_AUTODETECT_PC)

Просмотреть файл

@ -0,0 +1,65 @@
# -*- shell-script -*-
#
# Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
AC_DEFUN([MCA_installdirs_autodetect_COMPILE_MODE], [
AC_MSG_CHECKING([for MCA component $2:$3 compile mode])
$4="static"
AC_MSG_RESULT([$$4])
])
# MCA_installdirs_autodetect_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
#
# Solaris uses a binary-format /proc/$$/map file that contains a
# sequence of prmap_t structures. Those can be used to look up
# associated files in /proc/$$/path, which are symbolic links to
# the actual files.
#
# AIX has /proc/$$/map and /proc/$$/object, but no /proc/$$/path.
# I don't know how to achieve autodetect functionality on AIX.
#
# Linux has /proc/self/maps that contains text with both virtual
# addresses and paths. (Under Linux 2.0 there are no paths. I
# don't know how to achieve autodetect functionality on such
# systems.)
AC_DEFUN([MCA_installdirs_autodetect_CONFIG],[
AC_CHECK_HEADERS(procfs.h,
[AC_CHECK_FILE(/proc/$$/path,
[procfs_path_happy="yes"
OMPI_INSTALLDIRS_AUTODETECT_PATH=opal_installdirs_solaris.lo],
[procfs_path_happy="no"])],
[AC_CHECK_FILE(/proc/self/maps,
[procfs_path_happy="yes"
OMPI_INSTALLDIRS_AUTODETECT_PATH=opal_installdirs_linux.lo],
[procfs_path_happy="no"])])
AS_IF([test "$procfs_path_happy" = "yes"],[
# The following check is from opal/mca/backtrace/execinfo/configure.m4
AC_CHECK_HEADERS([execinfo.h],[
# FreeBSD has backtrace in -lexecinfo, usually in libc
OMPI_CHECK_FUNC_LIB([backtrace], [execinfo],
[findpc_happy="yes"
OMPI_INSTALLDIRS_AUTODETECT_PC=opal_installdirs_backtrace.lo],
[findpc_happy="no"])])
AS_IF([test "$backtrace_execinfo_happy" = "no"],[
AC_CHECK_HEADERS([ucontext.h],[
OMPI_CHECK_FUNC_LIB([walkcontext],,
[findpc_happy="yes"
OMPI_INSTALLDIRS_AUTODETECT_PC=opal_installdirs_walkcontext.lo],
[findpc_happy="no"])])])])
AS_IF([test "$procfs_path_happy" = "yes" -a "$findpc_happy" = "yes"],[
AC_SUBST([OMPI_INSTALLDIRS_AUTODETECT_PATH])
AC_SUBST([OMPI_INSTALLDIRS_AUTODETECT_PC])
$1],[$2])])

Просмотреть файл

@ -0,0 +1,15 @@
# -*- shell-script -*-
#
# Copyright (c) 2006 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# Specific to this module
PARAM_CONFIG_PRIORITY=5
PARAM_CONFIG_FILES="Makefile"

Просмотреть файл

@ -0,0 +1,181 @@
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
*
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*
* This module automatically detects the path to itself, and
* instructs the base install_dirs module to infer the prefix
* from that.
*/
#include "opal_config.h"
#include "opal/constants.h"
#include "opal/mca/mca.h"
#include "opal/mca/installdirs/installdirs.h"
#include "opal/util/basename.h"
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int opal_installdirs_autodetect_open(void);
opal_installdirs_base_component_t mca_installdirs_autodetect_component = {
/* First, the mca_component_t struct containing meta information
about the component itself */
{
OPAL_INSTALLDIRS_BASE_VERSION_2_0_0,
/* Component name and version */
"autodetect",
OPAL_MAJOR_VERSION,
OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION,
/* Component open and close functions */
opal_installdirs_autodetect_open,
NULL
},
{
/* This component is Checkpointable */
MCA_BASE_METADATA_PARAM_CHECKPOINT
}
};
/*
* Determine whether the load object is an executable or a shared library.
* The code only works for ELF files. The values and offsets are cribbed
* from the "file" command's magic number file.
*/
typedef enum { executable, shared_object, unknown_object } load_obj_t;
static load_obj_t
whatis(const char *path)
{
int fd;
char buf[18];
uint16_t *kind;
fd = open(path, O_RDONLY);
if (fd < 0) {
return unknown_object;
}
if (read(fd, buf, sizeof(buf)) < sizeof(buf)) {
close(fd);
return unknown_object;
}
close(fd);
if (strncmp(buf, "\177ELF", 4) != 0) {
return unknown_object;
}
kind = (uint16_t*)&buf[16];
if (2 == *kind) {
return executable;
} else if (3 == *kind) {
return shared_object;
} else {
return unknown_object;
}
}
/*
* OS-dependent function to get the address of some instruction in
* this module. We cannot in general just do &func, because if the
* module is in a shared library that can return some other address.
* (On Solaris, for example, it will return the address of an entry in
* the PLT of the program, rather than the shared library.)
*/
uintptr_t opal_installdirs_autodetect_pc(void);
/*
* OS-dependent function to find the path to the executable or shared
* library that contains the given address in the process' address
* space.
*/
const char *opal_installdirs_autodetect_path(uintptr_t);
static int
opal_installdirs_autodetect_open(void)
{
uintptr_t my_addr;
const char *path;
const char *my_dir;
const char *infer_from;
if (getenv("OPAL_DESTDIR") != NULL) {
/*
* OPAL_DESTDIR does not play well with autodetect. We
* certainly don't want it to be used as a prefix for the actual
* installed path. We could try to inhibit it only for those
* paths that cannot be inferred from the actual installed
* path, but it is simpler just to assume the user wants no
* auto detection if OPAL_DESTDIR is set.
*/
return OPAL_ERR_NOT_FOUND;
}
my_addr = opal_installdirs_autodetect_pc();
if (0 == my_addr) {
return OPAL_ERR_NOT_FOUND;
}
path = opal_installdirs_autodetect_path(my_addr);
if (NULL == path) {
return OPAL_ERR_NOT_FOUND;
}
my_dir = opal_dirname(path);
if (NULL == my_dir) {
free(path);
return OPAL_ERR_NOT_FOUND;
}
switch(whatis(path)) {
case executable:
mca_installdirs_autodetect_component.install_dirs_data.bindir = my_dir;
infer_from = "${infer-bindir}";
mca_installdirs_autodetect_component.install_dirs_data.libdir = infer_from;
break;
case shared_object:
mca_installdirs_autodetect_component.install_dirs_data.libdir = my_dir;
infer_from = "${infer-libdir}";
mca_installdirs_autodetect_component.install_dirs_data.bindir = infer_from;
break;
default:
free(my_dir);
free(path);
return OPAL_ERR_NOT_FOUND;
break;
}
free(path);
mca_installdirs_autodetect_component.install_dirs_data.prefix = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.exec_prefix = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.sbindir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.libexecdir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.datarootdir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.datadir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.sysconfdir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.sharedstatedir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.localstatedir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.includedir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.infodir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.mandir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.pkgdatadir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.pkglibdir = infer_from;
mca_installdirs_autodetect_component.install_dirs_data.pkgincludedir = infer_from;
return OPAL_SUCCESS;
}

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
*
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <execinfo.h>
uintptr_t
opal_installdirs_autodetect_pc()
{
void *pc = 0;
backtrace(&pc, 1);
return pc;
}

Просмотреть файл

@ -0,0 +1,188 @@
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
*
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*
* Read /proc/self/maps to find the path to the file containing
* an address.
*/
#include "opal_config.h"
#include "opal_stdint.h"
#include "opal/constants.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
uintptr_t read_addr(FILE *);
int skip_fields(FILE *, int);
int read_path(FILE *);
int skip_line(FILE *);
const char *
opal_installdirs_autodetect_path(uintptr_t my_addr)
{
FILE *f;
uintptr_t lo_start, lo_end;
f = fopen("/proc/self/maps", "r");
if (NULL == f) {
return NULL;
}
for (;;) {
lo_start = read_addr(f);
if (0 == lo_start) {
fclose(f);
return NULL;
}
lo_end = read_addr(f);
if (0 == lo_end) {
fclose(f);
return NULL;
}
if (lo_start <= my_addr && lo_end > my_addr) {
const char *path, *my_dir;
int e = skip_fields(f, 4);
if (OPAL_SUCCESS != e) {
fclose(f);
return e;
}
path = read_path(f);
fclose(f);
return path;
} else {
int e = skip_line(f);
if (OPAL_SUCCESS != e) {
fclose(f);
return NULL;
}
}
}
}
/*
* The following routines don't use isspace et al, because we don't
* want the locale setting to influence them.
*/
/*
* Read a hex address from a file. We don't know how many
* digits there will be. We only know that the result will
* fit into a uintptr_t, and will not be zero.
*
* Return zero on error.
*/
static uintptr_t
read_addr(FILE *f)
{
int c;
uintptr_t n = 0;
for (;;) {
c = getc(f);
if (EOF == c) {
return 0;
}
if (' ' == c || '-' == c) {
if (n > 0) {
return n;
} else {
continue;
}
}
if (c >= '0' && c <= '9') {
n <<= 4;
n += c - '0';
} else if (c >= 'a' && c <= 'f') {
n <<= 4;
n += c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
n <<= 4;
n += c - 'A' + 10;
} else {
return n;
}
}
}
/*
* Skip n fields of input, where fields are separated by white space.
*
* Return OPAL_SUCCESS on success.
*/
static int
skip_fields(FILE *f, int n)
{
int c = getc(f);
while (n-- > 0) {
for (; c == ' ' || c == '\t'; c = getc(f));
if (c == EOF || c == '\n') {
return OPAL_ERR_NOT_AVAILABLE;
}
for(; c != ' ' && c != '\t' && c != '\n'; c = getc(f));
}
return OPAL_SUCCESS;
}
/*
* Read a path, and return it. Return NULL on error.
*/
static int
read_path(FILE *f)
{
char *path = malloc(100);
int n = 100;
int i = 0;
int c = getc(f);
for (; (c == ' ' || c == '\t') && c != '\n' && c != EOF; c = getc(f));
for (; c != '\n' && EOF != c; c = getc(f)) {
if (i >= n) {
n += 100;
path = realloc(path, n);
}
if (NULL == path) {
return NULL;
}
path[i++] = c;
}
if (i >= n) {
n++;
path = realloc(path, n);
} else {
path = realloc(path, i + 1);
}
if (NULL == path) {
return NULL;
}
path[i] = '\0';
return path;
}
/*
* Skip to the next line of input. Return OPAL_SUCCESS on success.
*/
static int
skip_line(FILE *f)
{
int c = 0;
while (c != '\n') {
c = getc(f);
if (EOF == c) {
return OPAL_ERR_NOT_AVAILABLE;
}
}
return OPAL_SUCCESS;
}

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
*
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*
* Read /proc/<pid>/map and /proc/<pid>/path to find the file mapped
* into the process over the given address.
*/
#include "opal_config.h"
#include "opal_stdint.h"
#include "opal/constants.h"
#include <procfs.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
const char *
opal_installdirs_autodetect_path(uintptr_t my_addr)
{
pid_t my_pid;
char *map_path;
prmap_t map;
int map_fd;
char *obj_name;
ssize_t path_size, ls;
char *path;
my_pid = getpid();
asprintf(&map_path, "/proc/%d/map", my_pid);
if (NULL == map_path) {
return NULL;
}
map_fd = open(map_path, O_RDONLY);
free(map_path);
if (map_fd < 0) {
return NULL;
}
for (;;) {
if (read(map_fd, &map, sizeof(map)) < sizeof(map)) {
return OPAL_ERR_NOT_FOUND;
}
if (map.pr_vaddr <= my_addr && map.pr_vaddr + map.pr_size > my_addr) {
break;
}
}
close(map_fd);
asprintf(&obj_name, "/proc/%d/path/%s", my_pid, map.pr_mapname);
if (NULL == obj_name) {
return NULL;
}
/*
We don't know how long the path to the load object might be.
Try allocating a reasonable length. If the readlink system
call doesn't use the entire buffer passed to it then we know
the path is complete.
*/
for (path_size = 100; ; path_size += 100) {
path = malloc(path_size);
if (NULL == path) {
free(obj_name);
return OPAL_ERR_OUT_OF_RESOURCE;
}
ls = readlink(obj_name, path, path_size);
if (ls < 0) {
free(obj_name);
free(path);
return OPAL_ERR_NOT_FOUND;
}
if (ls < path_size) {
path[ls] = '\0';
break;
}
free(path);
}
free(obj_name);
return path;
}

Просмотреть файл

@ -0,0 +1,34 @@
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
*
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <ucontext.h>
static int
savepc(uintptr_t pc, int sig, void *storage)
{
*(uintptr_t*)storage = pc;
return 1;
}
uintptr_t
opal_installdirs_autodetect_pc()
{
ucontext_t ctx;
uintptr_t value = 0;
if (getcontext(&ctx) == -1) {
return 0;
}
walkcontext(&ctx, savepc, &value);
return value;
}

Просмотреть файл

@ -1,11 +1,12 @@
/* /*
* Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights * Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights
* reserved. * reserved.
* Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2009 Sun Microsystem, Inc. All rights reserved.
* $COPYRIGHT$ * $COPYRIGHT$
* *
* Additional copyrights may follow * Additional copyrights may follow
* *
* $HEADER$ * $HEADER$
* *
*/ */
@ -22,29 +23,59 @@ int opal_installdirs_base_output;
opal_install_dirs_t opal_install_dirs; opal_install_dirs_t opal_install_dirs;
opal_list_t opal_installdirs_components; opal_list_t opal_installdirs_components;
#define CONDITIONAL_COPY(target, origin, field) \ char *
do { \ opal_install_dirs_infer(const char *inferred_field,
if (origin.field != NULL && target.field == NULL) { \ const char *infer_from_field,
target.field = origin.field; \ size_t infer_from_field_len,
} \ opal_install_dirs_t *component_installdirs);
} while (0)
/*
* There is a memory leak when inferring a field. The function
* opal_install_dirs_infer returns allocated memory. We will
* later call opal_install_dirs_expand for the field, which
* also allocates memory. We don't record which fields were
* inferred, so we don't know whether to call free after calling
* opal_install_dirs_expand.
*/
#define CONDITIONAL_COPY(target, origin, field) \
do { \
if (origin.field != NULL) { \
if (NULL != target.field && \
strncmp(target.field, "${infer-", 8) == 0) { \
const char *fe = strchr(target.field, '}'); \
if (NULL != fe) { \
const char *f = target.field + 8; \
target.field = \
opal_install_dirs_infer(#field, f, fe - f, &origin); \
} else { \
target.field = NULL; \
} \
} \
if (NULL == target.field) { \
target.field = origin.field; \
} \
} \
\
} while (0) \
int int
opal_installdirs_base_open(void) opal_installdirs_base_open(void)
{ {
int i, ret; int i, ret;
mca_base_component_list_item_t *cli; mca_base_component_list_item_t *cli;
opal_install_dirs_t expanded_dirs;
OBJ_CONSTRUCT(&opal_installdirs_components, opal_list_t); OBJ_CONSTRUCT(&opal_installdirs_components, opal_list_t);
for (i = 0 ; mca_installdirs_base_static_components[i] != NULL ; ++i) { for (i = 0 ; mca_installdirs_base_static_components[i] != NULL ; ++i) {
opal_installdirs_base_component_t *component = opal_installdirs_base_component_t *component =
(opal_installdirs_base_component_t*) (opal_installdirs_base_component_t*)
mca_installdirs_base_static_components[i]; mca_installdirs_base_static_components[i];
/* Save it in a global list for ompi_info */ /* Save it in a global list for ompi_info */
cli = OBJ_NEW(mca_base_component_list_item_t); cli = OBJ_NEW(mca_base_component_list_item_t);
cli->cli_component = mca_installdirs_base_static_components[i]; cli->cli_component = mca_installdirs_base_static_components[i];
opal_list_append(&opal_installdirs_components, opal_list_append(&opal_installdirs_components,
&cli->super); &cli->super);
if (NULL != component->component.mca_open_component) { if (NULL != component->component.mca_open_component) {
@ -53,7 +84,7 @@ opal_installdirs_base_open(void)
} }
/* copy over the data, if something isn't already there */ /* copy over the data, if something isn't already there */
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
prefix); prefix);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
exec_prefix); exec_prefix);
@ -67,63 +98,64 @@ opal_installdirs_base_open(void)
datarootdir); datarootdir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
datadir); datadir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
sysconfdir); sysconfdir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
sharedstatedir); sharedstatedir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
localstatedir); localstatedir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
libdir); libdir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
includedir); includedir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
infodir); infodir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
mandir); mandir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
pkgdatadir); pkgdatadir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
pkglibdir); pkglibdir);
CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data, CONDITIONAL_COPY(opal_install_dirs, component->install_dirs_data,
pkgincludedir); pkgincludedir);
} }
/* expand out all the fields */ /* expand out all the fields */
opal_install_dirs.prefix = expanded_dirs.prefix =
opal_install_dirs_expand(opal_install_dirs.prefix); opal_install_dirs_expand(opal_install_dirs.prefix);
opal_install_dirs.exec_prefix = expanded_dirs.exec_prefix =
opal_install_dirs_expand(opal_install_dirs.exec_prefix); opal_install_dirs_expand(opal_install_dirs.exec_prefix);
opal_install_dirs.bindir = expanded_dirs.bindir =
opal_install_dirs_expand(opal_install_dirs.bindir); opal_install_dirs_expand(opal_install_dirs.bindir);
opal_install_dirs.sbindir = expanded_dirs.sbindir =
opal_install_dirs_expand(opal_install_dirs.sbindir); opal_install_dirs_expand(opal_install_dirs.sbindir);
opal_install_dirs.libexecdir = expanded_dirs.libexecdir =
opal_install_dirs_expand(opal_install_dirs.libexecdir); opal_install_dirs_expand(opal_install_dirs.libexecdir);
opal_install_dirs.datarootdir = expanded_dirs.datarootdir =
opal_install_dirs_expand(opal_install_dirs.datarootdir); opal_install_dirs_expand(opal_install_dirs.datarootdir);
opal_install_dirs.datadir = expanded_dirs.datadir =
opal_install_dirs_expand(opal_install_dirs.datadir); opal_install_dirs_expand(opal_install_dirs.datadir);
opal_install_dirs.sysconfdir = expanded_dirs.sysconfdir =
opal_install_dirs_expand(opal_install_dirs.sysconfdir); opal_install_dirs_expand(opal_install_dirs.sysconfdir);
opal_install_dirs.sharedstatedir = expanded_dirs.sharedstatedir =
opal_install_dirs_expand(opal_install_dirs.sharedstatedir); opal_install_dirs_expand(opal_install_dirs.sharedstatedir);
opal_install_dirs.localstatedir = expanded_dirs.localstatedir =
opal_install_dirs_expand(opal_install_dirs.localstatedir); opal_install_dirs_expand(opal_install_dirs.localstatedir);
opal_install_dirs.libdir = expanded_dirs.libdir =
opal_install_dirs_expand(opal_install_dirs.libdir); opal_install_dirs_expand(opal_install_dirs.libdir);
opal_install_dirs.includedir = expanded_dirs.includedir =
opal_install_dirs_expand(opal_install_dirs.includedir); opal_install_dirs_expand(opal_install_dirs.includedir);
opal_install_dirs.infodir = expanded_dirs.infodir =
opal_install_dirs_expand(opal_install_dirs.infodir); opal_install_dirs_expand(opal_install_dirs.infodir);
opal_install_dirs.mandir = expanded_dirs.mandir =
opal_install_dirs_expand(opal_install_dirs.mandir); opal_install_dirs_expand(opal_install_dirs.mandir);
opal_install_dirs.pkgdatadir = expanded_dirs.pkgdatadir =
opal_install_dirs_expand(opal_install_dirs.pkgdatadir); opal_install_dirs_expand(opal_install_dirs.pkgdatadir);
opal_install_dirs.pkglibdir = expanded_dirs.pkglibdir =
opal_install_dirs_expand(opal_install_dirs.pkglibdir); opal_install_dirs_expand(opal_install_dirs.pkglibdir);
opal_install_dirs.pkgincludedir = expanded_dirs.pkgincludedir =
opal_install_dirs_expand(opal_install_dirs.pkgincludedir); opal_install_dirs_expand(opal_install_dirs.pkgincludedir);
opal_install_dirs = expanded_dirs;
#if 0 #if 0
fprintf(stderr, "prefix: %s\n", opal_install_dirs.prefix); fprintf(stderr, "prefix: %s\n", opal_install_dirs.prefix);
@ -179,7 +211,7 @@ opal_installdirs_base_close(void)
free(opal_install_dirs.pkgincludedir); free(opal_install_dirs.pkgincludedir);
for (item = opal_list_remove_first(&opal_installdirs_components); for (item = opal_list_remove_first(&opal_installdirs_components);
NULL != item; NULL != item;
item = opal_list_remove_first(&opal_installdirs_components)) { item = opal_list_remove_first(&opal_installdirs_components)) {
OBJ_RELEASE(item); OBJ_RELEASE(item);
} }

Просмотреть файл

@ -1,12 +1,12 @@
/* /*
* Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights * Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights
* reserved. * reserved.
* Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2007 Sun Microsystem, Inc. All rights reserved. * Copyright (c) 2007-2009 Sun Microsystem, Inc. All rights reserved.
* $COPYRIGHT$ * $COPYRIGHT$
* *
* Additional copyrights may follow * Additional copyrights may follow
* *
* $HEADER$ * $HEADER$
* *
*/ */
@ -19,77 +19,269 @@
#include "opal/mca/installdirs/base/base.h" #include "opal/mca/installdirs/base/base.h"
#include "opal/mca/installdirs/installdirs.h" #include "opal/mca/installdirs/installdirs.h"
#define EXPAND_STRING(field) \ /*
do { \ * Read a field from an opal_install_dirs_t structure.
if (NULL != (start_pos = strstr(retval, "${" #field "}"))) { \ *
tmp = retval; \ * The field name is passed as a string + a length, and need not be
*start_pos = '\0'; \ * null terminated.
end_pos = start_pos + strlen("${" #field "}"); \ *
asprintf(&retval, "%s%s%s", tmp, \ * The implementation is reasonaly efficient, but perhaps less
opal_install_dirs.field + destdir_offset, \ * readable than a bunch of strncmp calls.
end_pos); \ */
free(tmp); \
changed = true; \
} \
} while (0)
#define CHKTRAIL(s,n) if (strncmp(field, #s, field_length - n) != 0) return NULL
static const char *
field_lookup(const char *field,
int field_length,
opal_install_dirs_t *install_dirs)
{
switch (*field++) {
case 'b':
CHKTRAIL(indir, 1);
return install_dirs->bindir;
case 'd':
CHKTRAIL(atarootdir, 1);
return install_dirs->datarootdir;
case 'e':
CHKTRAIL(xec_prefix, 1);
return install_dirs->exec_prefix;
case 'i':
if ('n' != *field++) return NULL;
switch (*field++) {
case 'c':
CHKTRAIL(ludedir, 3);
return install_dirs->includedir;
case 'f':
CHKTRAIL(odir, 3);
return install_dirs->infodir;
}
return NULL;
case 'l':
switch (*field++) {
case 'o':
CHKTRAIL(calstatedir, 2);
return install_dirs->localstatedir;
case 'i':
switch (*field++) {
case 'b':
switch (*field++) {
case 'd':
CHKTRAIL(ir, 4);
return install_dirs->libdir;
case 'e':
CHKTRAIL(xecdir, 4);
return install_dirs->libexecdir;
}
}
}
return NULL;
case 'm':
CHKTRAIL(andir, 1);
return install_dirs->mandir;
case 'p':
switch (*field++) {
case 'r':
CHKTRAIL(efix, 2);
return install_dirs->prefix;
case 'k':
if ('g' == *field++) {
switch (*field++) {
case 'd':
CHKTRAIL(atadir, 4);
return install_dirs->pkgdatadir;
case 'l':
CHKTRAIL(ibdir, 4);
return install_dirs->pkglibdir;
case 'i':
CHKTRAIL(ncludedir, 4);
return install_dirs->pkgincludedir;
}
}
}
return NULL;
case 's':
switch (*field++) {
case 'b':
CHKTRAIL(indir, 2);
return install_dirs->sbindir;
case 'h':
CHKTRAIL(aredstatedir, 2);
return install_dirs->sharedstatedir;
case 'y':
CHKTRAIL(sconfdir, 2);
return install_dirs->sysconfdir;
}
}
return NULL;
}
/*
* Sets *output to the input string with any "${foo}" references expanded.
* The expansion values come from the fields of install_dirs.
*
* If dont_expand is non-NULL, references to the field it names are
* not expanded. (E.g., "${libdir}" will be copied as is to *output if
* dont_expand is "libdir".)
*/
static void
install_dirs_expand(const char *input,
char **output,
size_t *output_len,
size_t *j,
opal_install_dirs_t *install_dirs,
const char *dont_expand)
{
size_t len, i, m, n;
const char *expansion;
if (0 == *output_len) {
*output_len = 100;
*output = malloc(*output_len);
if (NULL == *output) {
return;
}
}
len = strlen(input);
for (i = 0 ; i < len ; ++i) {
expansion = NULL;
if ('$' == input[i] && '{' == input[i+1]) {
for (n = 0; i + n + 2 < len; n++) {
if ('}' == input[i+n+2]) {
break;
}
}
if (NULL == dont_expand ||
strncmp(&input[i+2], dont_expand, n) != 0 ) {
expansion = field_lookup(&input[i+2], n, install_dirs);
} else {
expansion = NULL;
}
}
if (NULL != expansion) {
install_dirs_expand(expansion, output, output_len, j, install_dirs,
dont_expand);
i += n + 2;
} else {
if (*j + 1 >= *output_len) {
*output_len += 100;
*output = realloc(*output, *output_len);
if (NULL == *output) {
return;
}
}
(*output)[(*j)++] = input[i];
}
}
(*output)[*j] = '\0';
}
char * char *
opal_install_dirs_expand(const char* input) opal_install_dirs_expand(const char* input)
{ {
size_t len, i;
bool needs_expand = false;
char *retval = NULL; char *retval = NULL;
char *destdir = getenv("OPAL_DESTDIR"); char *destdir = getenv("OPAL_DESTDIR");
size_t destdir_offset = 0; size_t j = 0, retval_len = 0;
if (NULL != destdir && strlen(destdir) > 0) { if (NULL != destdir) {
destdir_offset = strlen(destdir); j = strlen(destdir) + sizeof(OPAL_PATH_SEP) - 1;
retval_len = j + 100;
retval = malloc(retval_len);
if (NULL == retval) {
return NULL;
}
sprintf(retval, "%s%s", destdir, OPAL_PATH_SEP);
} }
len = strlen(input); install_dirs_expand(input, &retval, &retval_len, &j, &opal_install_dirs, NULL);
for (i = 0 ; i < len ; ++i) { if (NULL != retval) {
if (input[i] == '$') { retval = realloc(retval, j + 1);
needs_expand = true; }
return retval;
}
char *
opal_install_dirs_infer(const char *inferred_field,
const char *infer_from_field,
size_t infer_from_field_len,
opal_install_dirs_t *component_installdirs)
{
const char *infer_from_path;
char *component_field = NULL;
size_t component_field_len = 0;
const char *installed_field = NULL;
char *p, *q;
size_t j = 0, inferred_field_len = strlen(inferred_field);
size_t leading, trailing, installed_field_len, retval_len;
char *retval;
infer_from_path = field_lookup(infer_from_field, infer_from_field_len,
component_installdirs);
install_dirs_expand(infer_from_path,
&component_field,
&component_field_len,
&j,
component_installdirs,
inferred_field);
installed_field = field_lookup(infer_from_field, infer_from_field_len,
&opal_install_dirs);
/*
* Let's say component_field is, "/path/${prefix}/bin", and
* infer_from_field is "bindir". Then we want to:
*
* 1. Make sure that opal_install_dirs.bindir starts with "/path/"
*
* 2. Make sure that opal_install_dirs.bindir ends with "/bin"
*
* 3. Return the string that appears between those
*/
for (p = component_field; *p; p++) {
if (*p == '$' && p[1] == '{' &&
strncmp(p+2, inferred_field, inferred_field_len) == 0) {
break; break;
} }
} }
if (*p == '\0') {
free(component_field);
return NULL;
}
leading = p - component_field;
trailing = component_field + strlen(component_field) - p -
inferred_field_len - 3;
retval = strdup(input); installed_field_len = strlen(installed_field);
if (NULL == retval) return NULL; if (installed_field_len < trailing + leading) {
free(component_field);
if (needs_expand) { return NULL;
bool changed = false;
char *start_pos, *end_pos, *tmp;
do {
changed = false;
EXPAND_STRING(prefix);
EXPAND_STRING(exec_prefix);
EXPAND_STRING(bindir);
EXPAND_STRING(sbindir);
EXPAND_STRING(libexecdir);
EXPAND_STRING(datarootdir);
EXPAND_STRING(datadir);
EXPAND_STRING(sysconfdir);
EXPAND_STRING(sharedstatedir);
EXPAND_STRING(localstatedir);
EXPAND_STRING(libdir);
EXPAND_STRING(includedir);
EXPAND_STRING(infodir);
EXPAND_STRING(mandir);
EXPAND_STRING(pkgdatadir);
EXPAND_STRING(pkglibdir);
EXPAND_STRING(pkgincludedir);
} while (changed);
} }
if (NULL != destdir) { if (strncmp(component_field, installed_field, leading) != 0) {
char *tmp = retval; free(component_field);
retval = opal_os_path(false, destdir, tmp, NULL); return NULL;
free(tmp);
} }
if (strcmp(p + inferred_field_len + 3,
installed_field + installed_field_len - trailing) != 0) {
free(component_field);
return NULL;
}
free(component_field);
retval_len = installed_field_len - leading - trailing;
retval = malloc(retval_len + 1);
if (NULL == retval) {
return NULL;
}
memcpy(retval, installed_field + leading, retval_len);
retval[retval_len] = '\0';
return retval; return retval;
} }