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