1 /*
2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3  *                         University Research and Technology
4  *                         Corporation.  All rights reserved.
5  * Copyright (c) 2004-2005 The University of Tennessee and The University
6  *                         of Tennessee Research Foundation.  All rights
7  *                         reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  *                         University of Stuttgart.  All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  *                         All rights reserved.
12  * Copyright (c) 2014      Intel, Inc. All rights reserved.
13  * Copyright (c) 2014-2015 Cisco Systems, Inc.  All rights reserved.
14  * $COPYRIGHT$
15  *
16  * Additional copyrights may follow
17  *
18  * $HEADER$
19  */
20 
21 #include "opal_config.h"
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "opal/util/cmd_line.h"
27 #include "opal/util/argv.h"
28 #include "opal/util/opal_environ.h"
29 #include "opal/util/show_help.h"
30 #include "opal/mca/base/base.h"
31 #include "opal/constants.h"
32 
33 
34 /*
35  * Private variables
36  */
37 
38 /*
39  * Private functions
40  */
41 static int process_arg(const char *param, const char *value,
42                        char ***params, char ***values);
43 static void add_to_env(char **params, char **values, char ***env);
44 
45 
46 /*
47  * Add -mca to the possible command line options list
48  */
mca_base_cmd_line_setup(opal_cmd_line_t * cmd)49 int mca_base_cmd_line_setup(opal_cmd_line_t *cmd)
50 {
51     int ret = OPAL_SUCCESS;
52 
53     ret = opal_cmd_line_make_opt3(cmd, '\0', OPAL_MCA_CMD_LINE_ID, OPAL_MCA_CMD_LINE_ID, 2,
54                                   "Pass context-specific MCA parameters; they are considered global if --g"OPAL_MCA_CMD_LINE_ID" is not used and only one context is specified (arg0 is the parameter name; arg1 is the parameter value)");
55     if (OPAL_SUCCESS != ret) {
56         return ret;
57     }
58 
59     ret = opal_cmd_line_make_opt3(cmd, '\0', "g"OPAL_MCA_CMD_LINE_ID, "g"OPAL_MCA_CMD_LINE_ID, 2,
60                                   "Pass global MCA parameters that are applicable to all contexts (arg0 is the parameter name; arg1 is the parameter value)");
61 
62     if (OPAL_SUCCESS != ret) {
63         return ret;
64     }
65 
66     {
67         opal_cmd_line_init_t entry =
68             {"mca_base_param_file_prefix", '\0', "am", NULL, 1,
69              NULL, OPAL_CMD_LINE_TYPE_STRING,
70              "Aggregate MCA parameter set file list",
71              OPAL_CMD_LINE_OTYPE_LAUNCH
72             };
73         ret = opal_cmd_line_make_opt_mca(cmd, entry);
74         if (OPAL_SUCCESS != ret) {
75             return ret;
76         }
77     }
78 
79     {
80         opal_cmd_line_init_t entry =
81             {"mca_base_envar_file_prefix", '\0', "tune", NULL, 1,
82              NULL, OPAL_CMD_LINE_TYPE_STRING,
83              "Application profile options file list",
84              OPAL_CMD_LINE_OTYPE_DEBUG
85             };
86         ret = opal_cmd_line_make_opt_mca(cmd, entry);
87         if (OPAL_SUCCESS != ret) {
88             return ret;
89         }
90     }
91 
92     return ret;
93 }
94 
95 
96 /*
97  * Look for and handle any -mca options on the command line
98  */
mca_base_cmd_line_process_args(opal_cmd_line_t * cmd,char *** context_env,char *** global_env)99 int mca_base_cmd_line_process_args(opal_cmd_line_t *cmd,
100                                    char ***context_env, char ***global_env)
101 {
102     int i, num_insts, rc;
103     char **params;
104     char **values;
105 
106     /* If no relevant parameters were given, just return */
107 
108     if (!opal_cmd_line_is_taken(cmd, OPAL_MCA_CMD_LINE_ID) &&
109         !opal_cmd_line_is_taken(cmd, "g"OPAL_MCA_CMD_LINE_ID)) {
110         return OPAL_SUCCESS;
111     }
112 
113     /* Handle app context-specific parameters */
114 
115     num_insts = opal_cmd_line_get_ninsts(cmd, OPAL_MCA_CMD_LINE_ID);
116     params = values = NULL;
117     for (i = 0; i < num_insts; ++i) {
118         if (OPAL_SUCCESS != (rc = process_arg(opal_cmd_line_get_param(cmd, OPAL_MCA_CMD_LINE_ID, i, 0),
119                                               opal_cmd_line_get_param(cmd, OPAL_MCA_CMD_LINE_ID, i, 1),
120                                               &params, &values))) {
121             return rc;
122         }
123     }
124     if (NULL != params) {
125         add_to_env(params, values, context_env);
126         opal_argv_free(params);
127         opal_argv_free(values);
128     }
129 
130     /* Handle global parameters */
131 
132     num_insts = opal_cmd_line_get_ninsts(cmd, "g"OPAL_MCA_CMD_LINE_ID);
133     params = values = NULL;
134     for (i = 0; i < num_insts; ++i) {
135         if (OPAL_SUCCESS != (rc = process_arg(opal_cmd_line_get_param(cmd, "g"OPAL_MCA_CMD_LINE_ID, i, 0),
136                                               opal_cmd_line_get_param(cmd, "g"OPAL_MCA_CMD_LINE_ID, i, 1),
137                                               &params, &values))) {
138             return rc;
139         }
140     }
141     if (NULL != params) {
142         add_to_env(params, values, global_env);
143         opal_argv_free(params);
144         opal_argv_free(values);
145     }
146 
147     /* All done */
148 
149     return OPAL_SUCCESS;
150 }
151 
152 
153 
154 /*
155  * Process a single MCA argument.
156  */
process_arg(const char * param,const char * value,char *** params,char *** values)157 static int process_arg(const char *param, const char *value,
158                        char ***params, char ***values)
159 {
160     int i;
161     char *p1;
162 
163     /* check for quoted value */
164     if ('\"' == value[0] && '\"' == value[strlen(value)-1]) {
165         p1 = strdup(&value[1]);
166         p1[strlen(p1)-1] = '\0';
167     } else {
168         p1 = strdup(value);
169     }
170 
171     /* Look to see if we've already got an -mca argument for the same
172        param.  Check against the list of MCA param's that we've
173        already saved arguments for - if found, return an error. */
174 
175     for (i = 0; NULL != *params && NULL != (*params)[i]; ++i) {
176         if (0 == strcmp(param, (*params)[i])) {
177             /* cannot use show_help here as it may not get out prior
178              * to the process exiting */
179             fprintf(stderr,
180                     "---------------------------------------------------------------------------\n"
181                     "The following MCA parameter has been listed multiple times on the\n"
182                     "command line:\n\n"
183                     "  MCA param:   %s\n\n"
184                     "MCA parameters can only be listed once on a command line to ensure there\n"
185                     "is no ambiguity as to its value.  Please correct the situation and\n"
186                     "try again.\n"
187                     "---------------------------------------------------------------------------\n",
188                     param);
189             free(p1);
190             return OPAL_ERROR;
191         }
192     }
193 
194     /* If we didn't already have an value for the same param, save
195        this one away */
196     opal_argv_append_nosize(params, param);
197     opal_argv_append_nosize(values, p1);
198     free(p1);
199 
200     return OPAL_SUCCESS;
201 }
202 
203 
add_to_env(char ** params,char ** values,char *** env)204 static void add_to_env(char **params, char **values, char ***env)
205 {
206     int i;
207     char *name;
208 
209     /* Loop through all the args that we've gotten and make env
210        vars of the form OPAL_MCA_PREFIX*=value. */
211 
212     for (i = 0; NULL != params && NULL != params[i]; ++i) {
213         (void) mca_base_var_env_name (params[i], &name);
214         opal_setenv(name, values[i], true, env);
215         free(name);
216     }
217 }
218 
mca_base_cmd_line_wrap_args(char ** args)219 void mca_base_cmd_line_wrap_args(char **args)
220 {
221     int i;
222     char *tstr;
223 
224     for (i=0; NULL != args && NULL != args[i]; i++) {
225         if (0 == strcmp(args[i], "-"OPAL_MCA_CMD_LINE_ID) ||
226             0 == strcmp(args[i], "--"OPAL_MCA_CMD_LINE_ID)) {
227             if (NULL == args[i+1] || NULL == args[i+2]) {
228                 /* this should be impossible as the error would
229                  * have been detected well before here, but just
230                  * be safe */
231                 return;
232             }
233             i += 2;
234             asprintf(&tstr, "\"%s\"", args[i]);
235             free(args[i]);
236             args[i] = tstr;
237         }
238     }
239 }
240