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