1 /*
2 * Copyright (C) by Argonne National Laboratory
3 * See COPYRIGHT in top-level directory
4 */
5
6 #include "mpichconf.h"
7
8 #include <stdio.h>
9 #ifdef HAVE_UNISTD_H
10 #include <unistd.h>
11 #endif
12 #ifdef HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif
15 #ifdef HAVE_STRING_H
16 #include <string.h>
17 #endif
18 #if defined(HAVE_PUTENV) && defined(NEEDS_PUTENV_DECL)
19 extern int putenv(char *string);
20 #endif
21
22 #include "pmutil.h"
23 #include "process.h"
24 #include "env.h"
25 #include "cmnargs.h" /* for mpiexec_usage */
26
27 /*
28 *
29 */
30
31 /*
32 * This routine may be called by MPIE_Args to handle any environment arguments
33 * Returns the number of arguments to skip (0 if argument is not recognized
34 * as an environment control)
35 */
MPIE_ArgsCheckForEnv(int argc,char * argv[],ProcessWorld * pWorld,EnvInfo ** appEnv)36 int MPIE_ArgsCheckForEnv(int argc, char *argv[], ProcessWorld * pWorld, EnvInfo ** appEnv)
37 {
38 int i, incr = 0;
39 EnvInfo *env;
40 char *cmd;
41
42 if (strncmp(argv[0], "-env", 4) == 0) {
43 if (!*appEnv) {
44 env = (EnvInfo *) MPL_malloc(sizeof(EnvInfo), MPL_MEM_PM);
45 env->includeAll = 1;
46 env->envPairs = 0;
47 env->envNames = 0;
48 *appEnv = env;
49 } else
50 env = *appEnv;
51 cmd = argv[0] + 4;
52 } else if (strncmp(argv[0], "-genv", 5) == 0) {
53 if (!pWorld->genv) {
54 env = (EnvInfo *) MPL_malloc(sizeof(EnvInfo), MPL_MEM_PM);
55 env->includeAll = 1;
56 env->envPairs = 0;
57 env->envNames = 0;
58 pWorld->genv = env;
59 }
60 env = pWorld->genv;
61 cmd = argv[0] + 5;
62 } else
63 return 0;
64
65 /* genv and env commands have the same form, just affect different
66 * env structures. We handle this by identifying which structure,
67 * then checkout the remaining command */
68 if (!cmd[0]) {
69 /* A basic name value command */
70 EnvData *p;
71 if (!argv[1] || !argv[2]) {
72 mpiexec_usage("Missing arguments to -env or -genv");
73 }
74 p = (EnvData *) MPL_malloc(sizeof(EnvData), MPL_MEM_PM);
75 p->name = (const char *) MPL_strdup(argv[1]);
76 p->value = (const char *) MPL_strdup(argv[2]);
77 p->envvalue = 0;
78 p->nextData = env->envPairs;
79 env->envPairs = p;
80
81 incr = 3;
82 } else if (strcmp(cmd, "none") == 0) {
83 env->includeAll = 0;
84 incr = 1;
85 } else if (strcmp(cmd, "list") == 0) {
86 /* argv[1] has a list of names, separated by commas */
87 EnvData *p;
88 char *lPtr = argv[1], *name;
89 int namelen;
90
91 if (!argv[1]) {
92 mpiexec_usage("Missing argument to -envlist or -genvlist");
93 }
94 while (*lPtr) {
95 name = lPtr++;
96 while (*lPtr && *lPtr != ',')
97 lPtr++;
98 /* The length of any environment string will fit in an int */
99 namelen = (int) (lPtr - name);
100 p = (EnvData *) MPL_malloc(sizeof(EnvData), MPL_MEM_PM);
101 p->value = 0;
102 p->name = (const char *) MPL_malloc(namelen + 1, MPL_MEM_PM);
103 p->envvalue = 0;
104 for (i = 0; i < namelen; i++)
105 ((char *) p->name)[i] = name[i];
106 ((char *) p->name)[namelen] = 0;
107
108 p->nextData = env->envNames;
109 env->envNames = p;
110 if (*lPtr == ',')
111 lPtr++;
112 }
113 incr = 2;
114 } else {
115 /* Unrecognized env argument. */
116 incr = 0;
117 }
118
119 return incr;
120 }
121
122 /*
123 Setup the environment of a process for a given process state.
124 This handles the options for the process world and app
125
126 Input Arguments:
127 pState - process state structure
128 envp - Base (pre-existing) environment. Note that this should
129 be the envp from main() (see below)
130 maxclient - size of client_envp array
131
132 Output Arguments:
133 client_envp -
134
135 Side Effects:
136 If envnone or genvnone was selected, the environment variables in envp
137 will be removed with unsetenv() or by direct manipulation of the envp
138 array (for systems that do not support unsetenv, envp must be the
139 array pass into main()).
140
141 Returns the number of items set in client_envp, or -1 on error.
142 */
MPIE_EnvSetup(ProcessState * pState,char * envp[],char * client_envp[],int maxclient)143 int MPIE_EnvSetup(ProcessState * pState, char *envp[], char *client_envp[], int maxclient)
144 {
145 ProcessWorld *pWorld;
146 ProcessApp *app;
147 EnvInfo *env;
148 EnvData *wPairs = 0, *wNames = 0, *aPairs = 0, *aNames = 0;
149 int includeAll = 1;
150 int irc = 0;
151 int debug = 1;
152
153 app = pState->app;
154 pWorld = app->pWorld;
155
156 /* Get the world defaults */
157 env = pWorld->genv;
158 if (env) {
159 includeAll = env->includeAll;
160 wPairs = env->envPairs;
161 wNames = env->envNames;
162 }
163
164 /* Get the app values (overrides includeAll) */
165 env = app->env;
166 if (env) {
167 if (includeAll) {
168 /* Let the local env set envnone (there is no way to undo
169 * -genvnone) */
170 includeAll = env->includeAll;
171 }
172 aPairs = env->envPairs;
173 aNames = env->envNames;
174 }
175
176 if (includeAll) {
177 if (envp) {
178 int j;
179 for (j = 0; envp[j] && j < maxclient; j++) {
180 putenv(envp[j]);
181 client_envp[j] = envp[j];
182 }
183 irc = j;
184 } else
185 irc = 0;
186 } else {
187 MPIE_UnsetAllEnv(envp);
188 irc = 0;
189 }
190
191 while (wPairs) {
192 if (putenv((char *) (wPairs->envvalue))) {
193 irc = -1;
194 if (debug)
195 perror("putenv(wPairs) failed: ");
196 }
197 wPairs = wPairs->nextData;
198 }
199
200 while (wNames) {
201 if (putenv((char *) (wNames->envvalue))) {
202 irc = -1;
203 if (debug)
204 perror("putenv(wNames) failed: ");
205 }
206 wNames = wNames->nextData;
207 }
208
209 while (aPairs) {
210 if (putenv((char *) (aPairs->envvalue))) {
211 irc = -1;
212 if (debug)
213 perror("putenv(aPairs) failed: ");
214 }
215 aPairs = aPairs->nextData;
216 }
217
218 while (aNames) {
219 if (putenv((char *) (aNames->envvalue))) {
220 irc = -1;
221 if (debug) {
222 perror("putenv(aNames) failed: ");
223 }
224 }
225 aNames = aNames->nextData;
226 }
227
228 return irc;
229 }
230
231 /*
232 Initialize the environment data
233
234 Builds the envvalue version of the data, using the given data.
235 if getValue is true, get the value for the name with getenv .
236 */
MPIE_EnvInitData(EnvData * elist,int getValue)237 int MPIE_EnvInitData(EnvData * elist, int getValue)
238 {
239 const char *value;
240 char *str;
241 int rc;
242 size_t slen;
243
244 while (elist) {
245 /* Skip variables that already have value strings */
246 if (!elist->envvalue) {
247 if (getValue) {
248 value = (const char *) getenv(elist->name);
249 } else {
250 value = elist->value;
251 }
252 if (!value) {
253 /* Special case for an empty value */
254 value = "";
255 }
256 slen = strlen(elist->name) + strlen(value) + 2;
257 str = (char *) MPL_malloc(slen, MPL_MEM_PM);
258 if (!str) {
259 return 1;
260 }
261 MPL_strncpy(str, elist->name, slen);
262 if (value && *value) {
263 rc = MPL_strnapp(str, "=", slen);
264 rc += MPL_strnapp(str, value, slen);
265 if (rc) {
266 return 1;
267 }
268 }
269 elist->envvalue = (const char *) str;
270 }
271 elist = elist->nextData;
272 }
273 return 0;
274 }
275
276 /*
277 * Add an enviroinment variable to the global list of variables
278 */
MPIE_Putenv(ProcessWorld * pWorld,const char * env_string)279 int MPIE_Putenv(ProcessWorld * pWorld, const char *env_string)
280 {
281 EnvInfo *genv;
282 EnvData *p;
283
284 /* FIXME: This should be getGenv (so allocation/init in one place) */
285 if (!pWorld->genv) {
286 genv = (EnvInfo *) MPL_malloc(sizeof(EnvInfo), MPL_MEM_PM);
287 genv->includeAll = 1;
288 genv->envPairs = 0;
289 genv->envNames = 0;
290 pWorld->genv = genv;
291 }
292 genv = pWorld->genv;
293
294 p = (EnvData *) MPL_malloc(sizeof(EnvData), MPL_MEM_PM);
295 if (!p)
296 return 1;
297 p->name = 0;
298 p->value = 0;
299 p->envvalue = (const char *) MPL_strdup(env_string);
300 if (!p->envvalue)
301 return 1;
302 p->nextData = genv->envPairs;
303 genv->envPairs = p;
304
305 return 0;
306 }
307
308
309 /* Unset all environment variables.
310
311 Not all systems support unsetenv (e.g., System V derived systems such
312 as Solaris), so we have to provide our own implementation.
313
314 In addition, there are various ways to determine the "current" environment
315 variables. One is to pass a third arg to main; the other is a global
316 variable.
317
318 Also, we prefer the environ variable over envp, because exec often
319 prefers what is in environ rather than the envp (envp appears to be a
320 copy, and unsetting the env doesn't always change the environment
321 that exec creates. This seems wrong, but it was what was observed
322 on Linux).
323
324 */
325 #ifdef HAVE_EXTERN_ENVIRON
326 #ifdef NEEDS_ENVIRON_DECL
327 extern char **environ;
328 #endif
MPIE_UnsetAllEnv(char * envp[])329 int MPIE_UnsetAllEnv(char *envp[])
330 {
331 /* Ignore envp because environ is the real array that controls
332 * the environment used by getenv/putenv/etc */
333 char **ep = environ;
334
335 while (*ep)
336 *ep++ = 0;
337 return 0;
338 }
339 #elif defined(HAVE_UNSETENV)
MPIE_UnsetAllEnv(char * envp[])340 int MPIE_UnsetAllEnv(char *envp[])
341 {
342 int j;
343
344 for (j = 0; envp[j]; j++) {
345 unsetenv(envp[j]);
346 }
347 return 0;
348 }
349 #else
350 /* No known way to unset the environment. Return failure */
MPIE_UnsetAllEnv(char * envp[])351 int MPIE_UnsetAllEnv(char *envp[])
352 {
353 return 1;
354 }
355 #endif
356