1 /*
2  * Copyright (c) 2006-2007 Los Alamos National Security, LLC.  All rights
3  *                         reserved.
4  * Copyright (c) 2007-2010 Cisco Systems, Inc.  All rights reserved.
5  * Copyright (c) 2007      Sun Microsystem, Inc.  All rights reserved.
6  * Copyright (c) 2010      Sandia National Laboratories. All rights reserved.
7  * $COPYRIGHT$
8  *
9  * Additional copyrights may follow
10  *
11  * $HEADER$
12  *
13  */
14 
15 #include "opal_config.h"
16 
17 #include <string.h>
18 
19 #include "opal/util/os_path.h"
20 #include "opal/mca/installdirs/base/base.h"
21 #include "opal/mca/installdirs/installdirs.h"
22 
23 /* Support both ${name} and @{name} forms.  The latter allows us to
24    pass values through AC_SUBST without being munged by m4 (e.g., if
25    we want to pass "@{libdir}" and not have it replaced by m4 to be
26    whatever the actual value of the shell variable is. */
27 #define EXPAND_STRING(name) EXPAND_STRING2(name, name)
28 
29 #define EXPAND_STRING2(ompiname, fieldname)                             \
30     do {                                                                \
31         if (NULL != (start_pos = strstr(retval, "${" #fieldname "}"))) { \
32             tmp = retval;                                               \
33             *start_pos = '\0';                                          \
34             end_pos = start_pos + strlen("${" #fieldname "}");          \
35             asprintf(&retval, "%s%s%s", tmp,                            \
36                      opal_install_dirs.ompiname + destdir_offset,       \
37                      end_pos);                                          \
38             free(tmp);                                                  \
39             changed = true;                                             \
40         } else if (NULL != (start_pos = strstr(retval, "@{" #fieldname "}"))) { \
41             tmp = retval;                                               \
42             *start_pos = '\0';                                          \
43             end_pos = start_pos + strlen("@{" #fieldname "}");          \
44             asprintf(&retval, "%s%s%s", tmp,                            \
45                      opal_install_dirs.ompiname + destdir_offset,       \
46                      end_pos);                                          \
47             free(tmp);                                                  \
48             changed = true;                                             \
49         }                                                               \
50     } while (0)
51 
52 
53 /*
54  * Read the lengthy comment below to understand the value of the
55  * is_setup parameter.
56  */
57 static char *
opal_install_dirs_expand_internal(const char * input,bool is_setup)58 opal_install_dirs_expand_internal(const char* input, bool is_setup)
59 {
60     size_t len, i;
61     bool needs_expand = false;
62     char *retval = NULL;
63     char *destdir = NULL;
64     size_t destdir_offset = 0;
65 
66     /* This is subtle, and worth explaining.
67 
68        If we substitute in any ${FIELD} values, we need to prepend it
69        with the value of the $OPAL_DESTDIR environment variable -- if
70        it is set.
71 
72        We need to handle at least three cases properly (assume that
73        configure was invoked with --prefix=/opt/openmpi and no other
74        directory specifications, and OPAL_DESTDIR is set to
75        /tmp/buildroot):
76 
77        1. Individual directories, such as libdir.  These need to be
78           prepended with DESTDIR.  I.e., return
79           /tmp/buildroot/opt/openmpi/lib.
80 
81        2. Compiler flags that have ${FIELD} values embedded in them.
82           For example, consider if a wrapper compiler data file
83           contains the line:
84 
85           preprocessor_flags=-DMYFLAG="${prefix}/share/randomthingy/"
86 
87           The value we should return is:
88 
89           -DMYFLAG="/tmp/buildroot/opt/openmpi/share/randomthingy/"
90 
91        3. Compiler flags that do not have any ${FIELD} values.
92           For example, consider if a wrapper compiler data file
93           contains the line:
94 
95           preprocessor_flags=-pthread
96 
97           The value we should return is:
98 
99           -pthread
100 
101        Note, too, that this OPAL_DESTDIR futzing only needs to occur
102        during opal_init().  By the time opal_init() has completed, all
103        values should be substituted in that need substituting.  Hence,
104        we take an extra parameter (is_setup) to know whether we should
105        do this futzing or not. */
106     if (is_setup) {
107         destdir = getenv("OPAL_DESTDIR");
108         if (NULL != destdir && strlen(destdir) > 0) {
109             destdir_offset = strlen(destdir);
110         }
111     }
112 
113     len = strlen(input);
114     for (i = 0 ; i < len ; ++i) {
115         if ('$' == input[i] || '@' == input[i]) {
116             needs_expand = true;
117             break;
118         }
119     }
120 
121     retval = strdup(input);
122     if (NULL == retval) return NULL;
123 
124     if (needs_expand) {
125         bool changed = false;
126         char *start_pos, *end_pos, *tmp;
127 
128         do {
129             changed = false;
130             EXPAND_STRING(prefix);
131             EXPAND_STRING(exec_prefix);
132             EXPAND_STRING(bindir);
133             EXPAND_STRING(sbindir);
134             EXPAND_STRING(libexecdir);
135             EXPAND_STRING(datarootdir);
136             EXPAND_STRING(datadir);
137             EXPAND_STRING(sysconfdir);
138             EXPAND_STRING(sharedstatedir);
139             EXPAND_STRING(localstatedir);
140             EXPAND_STRING(libdir);
141             EXPAND_STRING(includedir);
142             EXPAND_STRING(infodir);
143             EXPAND_STRING(mandir);
144             EXPAND_STRING2(opaldatadir, pkgdatadir);
145             EXPAND_STRING2(opallibdir, pkglibdir);
146             EXPAND_STRING2(opalincludedir, pkgincludedir);
147         } while (changed);
148     }
149 
150     if (NULL != destdir) {
151         char *tmp = retval;
152         retval = opal_os_path(false, destdir, tmp, NULL);
153         free(tmp);
154     }
155 
156     return retval;
157 }
158 
159 
160 char *
opal_install_dirs_expand(const char * input)161 opal_install_dirs_expand(const char* input)
162 {
163     /* We do NOT want OPAL_DESTDIR expansion in this case. */
164     return opal_install_dirs_expand_internal(input, false);
165 }
166 
167 
168 char *
opal_install_dirs_expand_setup(const char * input)169 opal_install_dirs_expand_setup(const char* input)
170 {
171     /* We DO want OPAL_DESTDIR expansion in this case. */
172     return opal_install_dirs_expand_internal(input, true);
173 }
174