1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3  * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
4  *                         University Research and Technology
5  *                         Corporation.  All rights reserved.
6  * Copyright (c) 2004-2011 The University of Tennessee and The University
7  *                         of Tennessee Research Foundation.  All rights
8  *                         reserved.
9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10  *                         University of Stuttgart.  All rights reserved.
11  * Copyright (c) 2004-2005 The Regents of the University of California.
12  *                         All rights reserved.
13  * Copyright (c) 2006-2015 Cisco Systems, Inc.  All rights reserved.
14  * Copyright (c) 2010-2016 Los Alamos National Security, LLC. All rights
15  *                         reserved.
16  * Copyright (c) 2011-2012 University of Houston. All rights reserved.
17  * Copyright (c) 2016-2020 Intel, Inc.  All rights reserved.
18  * Copyright (c) 2017      IBM Corporation.  All rights reserved.
19  * Copyright (c) 2017      Research Organization for Information Science
20  *                         and Technology (RIST). All rights reserved.
21  * $COPYRIGHT$
22  *
23  * Additional copyrights may follow
24  *
25  * $HEADER$
26  */
27 
28 #include "pmix_config.h"
29 
30 #include <string.h>
31 #include <ctype.h>
32 
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 
37 #include <errno.h>
38 
39 #include "src/class/pmix_list.h"
40 #include "src/class/pmix_pointer_array.h"
41 #include "src/runtime/pmix_rte.h"
42 #include "src/util/output.h"
43 #include "src/util/cmd_line.h"
44 #include "src/util/error.h"
45 #include "src/util/argv.h"
46 #include "src/util/show_help.h"
47 
48 #include "src/include/frameworks.h"
49 #include "src/include/pmix_portable_platform.h"
50 
51 #include "src/mca/pinstalldirs/pinstalldirs.h"
52 #include "pinfo.h"
53 #include "support.h"
54 #include "src/mca/base/pmix_mca_base_component_repository.h"
55 
56 const char *pmix_info_path_prefix = "prefix";
57 const char *pmix_info_path_bindir = "bindir";
58 const char *pmix_info_path_libdir = "libdir";
59 const char *pmix_info_path_incdir = "incdir";
60 const char *pmix_info_path_mandir = "mandir";
61 const char *pmix_info_path_pkglibdir = "pkglibdir";
62 const char *pmix_info_path_sysconfdir = "sysconfdir";
63 const char *pmix_info_path_exec_prefix = "exec_prefix";
64 const char *pmix_info_path_sbindir = "sbindir";
65 const char *pmix_info_path_libexecdir = "libexecdir";
66 const char *pmix_info_path_datarootdir = "datarootdir";
67 const char *pmix_info_path_datadir = "datadir";
68 const char *pmix_info_path_sharedstatedir = "sharedstatedir";
69 const char *pmix_info_path_localstatedir = "localstatedir";
70 const char *pmix_info_path_infodir = "infodir";
71 const char *pmix_info_path_pkgdatadir = "pkgdatadir";
72 const char *pmix_info_path_pkgincludedir = "pkgincludedir";
73 
74 bool pmix_info_pretty = true;
75 pmix_mca_base_register_flag_t pmix_info_register_flags = PMIX_MCA_BASE_REGISTER_ALL;
76 
77 const char *pmix_info_type_all = "all";
78 const char *pmix_info_type_pmix = "pmix";
79 const char *pmix_info_component_all = "all";
80 const char *pmix_info_param_all = "all";
81 
82 const char *pmix_info_ver_full = "full";
83 const char *pmix_info_ver_major = "major";
84 const char *pmix_info_ver_minor = "minor";
85 const char *pmix_info_ver_release = "release";
86 const char *pmix_info_ver_greek = "greek";
87 const char *pmix_info_ver_repo = "repo";
88 
89 const char *pmix_info_ver_all = "all";
90 const char *pmix_info_ver_mca = "mca";
91 const char *pmix_info_ver_type = "type";
92 const char *pmix_info_ver_component = "component";
93 
94 static int pmix_info_registered = 0;
95 
component_map_construct(pmix_info_component_map_t * map)96 static void component_map_construct(pmix_info_component_map_t *map)
97 {
98     map->type = NULL;
99 }
component_map_destruct(pmix_info_component_map_t * map)100 static void component_map_destruct(pmix_info_component_map_t *map)
101 {
102     if (NULL != map->type) {
103         free(map->type);
104     }
105     /* the type close functions will release the
106      * list of components
107      */
108 }
109 PMIX_CLASS_INSTANCE(pmix_info_component_map_t,
110                     pmix_list_item_t,
111                     component_map_construct,
112                     component_map_destruct);
113 
114 static void pmix_info_show_failed_component(const pmix_mca_base_component_repository_item_t* ri,
115                                             const char *error_msg);
116 
pmix_info_init(int argc,char ** argv,pmix_cmd_line_t * pmix_info_cmd_line)117 int pmix_info_init(int argc, char **argv,
118                    pmix_cmd_line_t *pmix_info_cmd_line)
119 {
120     int ret;
121     bool want_help = false;
122     bool cmd_error = false;
123     char **app_env = NULL, **global_env = NULL;
124 
125     /* add the cmd line options */
126     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 'V', NULL, "version", 0,
127                             "Show version of Open MPI");
128     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "param", 2,
129                             "Show MCA parameters.  The first parameter is the framework (or the keyword \"all\"); the second parameter is the specific component name (or the keyword \"all\").");
130     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "params", 2,
131                             "Synonym for --param");
132     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "internal", 0,
133                             "Show internal MCA parameters (not meant to be modified by users)");
134     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "path", 1,
135                             "Show paths that Open MPI was configured with.  Accepts the following parameters: prefix, bindir, libdir, incdir, mandir, pkglibdir, sysconfdir, all");
136     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "arch", 0,
137                             "Show architecture Open MPI was compiled on");
138     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 'c', NULL, "config", 0,
139                             "Show configuration options");
140     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 't', NULL, "type", 1,
141                             "Show internal MCA parameters with the type specified in parameter.");
142     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 'h', NULL, "help", 0,
143                             "Show this help message");
144     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "pretty-print", 0,
145                             "When used in conjunction with other parameters, the output is displayed in 'pretty-print' format (default)");
146     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "parsable", 0,
147                             "When used in conjunction with other parameters, the output is displayed in a machine-parsable format");
148     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "parseable", 0,
149                             "Synonym for --parsable");
150     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "hostname", 0,
151                             "Show the hostname that Open MPI was configured and built on");
152     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 'a', NULL, "all", 0,
153                             "Show all configuration options and MCA parameters");
154     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 'l', NULL, "level", 1,
155                             "Show only variables with at most this level (1-9)");
156     pmix_cmd_line_make_opt3(pmix_info_cmd_line, 's', NULL, "selected-only", 0,
157                             "Show only variables from selected components");
158     pmix_cmd_line_make_opt3(pmix_info_cmd_line, '\0', NULL, "show-failed", 0,
159                             "Show the components that failed to load along with the reason why they failed.");
160 
161     if( PMIX_SUCCESS != pmix_mca_base_open() ) {
162         pmix_show_help("help-pinfo.txt", "lib-call-fail", true, "mca_base_open", __FILE__, __LINE__ );
163         PMIX_RELEASE(pmix_info_cmd_line);
164         exit(1);
165     }
166     pmix_mca_base_cmd_line_setup(pmix_info_cmd_line);
167 
168     /* Do the parsing */
169 
170     ret = pmix_cmd_line_parse(pmix_info_cmd_line, false, false, argc, argv);
171     if (PMIX_SUCCESS != ret) {
172         if (PMIX_ERR_SILENT != ret) {
173             fprintf(stderr, "%s: command line error (%s)\n", argv[0],
174                     PMIx_Error_string(ret));
175         }
176         cmd_error = true;
177     }
178     if (!cmd_error &&
179         (pmix_cmd_line_is_taken(pmix_info_cmd_line, "help") ||
180          pmix_cmd_line_is_taken(pmix_info_cmd_line, "h"))) {
181         char *str, *usage;
182 
183         want_help = true;
184         usage = pmix_cmd_line_get_usage_msg(pmix_info_cmd_line);
185         str = pmix_show_help_string("help-pmix-info.txt", "usage", true,
186                                     usage);
187         if (NULL != str) {
188             printf("%s", str);
189             free(str);
190         }
191         free(usage);
192     }
193 
194 
195     /* If we had a cmd line parse error, or we showed the help
196        message, it's time to exit. */
197     if (cmd_error || want_help) {
198         pmix_mca_base_close();
199         PMIX_RELEASE(pmix_info_cmd_line);
200         exit(cmd_error ? 1 : 0);
201     }
202 
203     pmix_mca_base_cmd_line_process_args(pmix_info_cmd_line, &app_env, &global_env);
204 
205 
206     /* set the flags */
207     if (pmix_cmd_line_is_taken(pmix_info_cmd_line, "pretty-print")) {
208         pmix_info_pretty = true;
209     } else if (pmix_cmd_line_is_taken(pmix_info_cmd_line, "parsable") || pmix_cmd_line_is_taken(pmix_info_cmd_line, "parseable")) {
210         pmix_info_pretty = false;
211     }
212 
213     if (pmix_cmd_line_is_taken(pmix_info_cmd_line, "selected-only")) {
214         /* register only selected components */
215         pmix_info_register_flags = PMIX_MCA_BASE_REGISTER_DEFAULT;
216     }
217 
218     if (pmix_cmd_line_is_taken(pmix_info_cmd_line, "show-failed")) {
219         pmix_mca_base_component_track_load_errors = true;
220     }
221 
222     return PMIX_SUCCESS;
223 }
224 
pmix_info_finalize(void)225 void pmix_info_finalize(void)
226 {
227     pmix_mca_base_close();
228 }
229 
info_register_framework(pmix_mca_base_framework_t * framework,pmix_pointer_array_t * component_map)230 static int info_register_framework (pmix_mca_base_framework_t *framework, pmix_pointer_array_t *component_map)
231 {
232     pmix_info_component_map_t *map;
233     int rc;
234     rc = pmix_mca_base_framework_register(framework, pmix_info_register_flags);
235     if (PMIX_SUCCESS != rc && PMIX_ERR_BAD_PARAM != rc) {
236         return rc;
237     }
238 
239     if (NULL != component_map) {
240         map = PMIX_NEW(pmix_info_component_map_t);
241         map->type = strdup(framework->framework_name);
242         map->components = &framework->framework_components;
243         map->failed_components = &framework->framework_failed_components;
244         pmix_pointer_array_add(component_map, map);
245     }
246 
247     return rc;
248 }
249 
pmix_info_register_project_frameworks(const char * project_name,pmix_mca_base_framework_t ** frameworks,pmix_pointer_array_t * component_map)250 int pmix_info_register_project_frameworks (const char *project_name, pmix_mca_base_framework_t **frameworks,
251                                            pmix_pointer_array_t *component_map)
252 {
253     int i, rc=PMIX_SUCCESS;
254 
255     for (i=0; NULL != frameworks[i]; i++) {
256         if (PMIX_SUCCESS != (rc = info_register_framework(frameworks[i], component_map))) {
257             if (PMIX_ERR_BAD_PARAM == rc) {
258                 fprintf(stderr, "\nA \"bad parameter\" error was encountered when opening the %s %s framework\n",
259                         project_name, frameworks[i]->framework_name);
260                 fprintf(stderr, "The output received from that framework includes the following parameters:\n\n");
261             } else if (PMIX_ERR_NOT_AVAILABLE != rc) {
262                 fprintf(stderr, "%s_info_register: %s failed\n", project_name, frameworks[i]->framework_name);
263                 rc = PMIX_ERROR;
264             } else {
265                 continue;
266             }
267 
268             break;
269         }
270     }
271 
272     return rc;
273 }
274 
pmix_info_register_types(pmix_pointer_array_t * mca_types)275 void pmix_info_register_types(pmix_pointer_array_t *mca_types)
276 {
277     int i;
278 
279     /* add the top-level types */
280     pmix_pointer_array_add(mca_types, "mca");
281     pmix_pointer_array_add(mca_types, "pmix");
282 
283     /* push all the types found by autogen */
284     for (i=0; NULL != pmix_frameworks[i]; i++) {
285         pmix_pointer_array_add(mca_types, pmix_frameworks[i]->framework_name);
286     }
287 }
288 
pmix_info_register_framework_params(pmix_pointer_array_t * component_map)289 int pmix_info_register_framework_params(pmix_pointer_array_t *component_map)
290 {
291     int rc;
292 
293     if (pmix_info_registered++) {
294         return PMIX_SUCCESS;
295     }
296 
297     /* Register mca/base parameters */
298     if( PMIX_SUCCESS != pmix_mca_base_open() ) {
299         pmix_show_help("help-pmix_info.txt", "lib-call-fail", true, "mca_base_open", __FILE__, __LINE__ );
300         return PMIX_ERROR;
301     }
302 
303     /* Register the PMIX layer's MCA parameters */
304     if (PMIX_SUCCESS != (rc = pmix_register_params())) {
305         fprintf(stderr, "pmix_info_register: pmix_register_params failed\n");
306         return rc;
307     }
308 
309     return pmix_info_register_project_frameworks("pmix", pmix_frameworks, component_map);
310 }
311 
312 
pmix_info_close_components(void)313 void pmix_info_close_components(void)
314 {
315     int i;
316 
317     assert(pmix_info_registered);
318     if (--pmix_info_registered) {
319         return;
320     }
321 
322     for (i=0; NULL != pmix_frameworks[i]; i++) {
323         (void) pmix_mca_base_framework_close(pmix_frameworks[i]);
324     }
325 
326     /* release our reference to MCA */
327     pmix_mca_base_close ();
328 }
329 
330 
pmix_info_show_path(const char * type,const char * value)331 void pmix_info_show_path(const char *type, const char *value)
332 {
333     char *pretty, *path;
334 
335     pretty = strdup(type);
336     pretty[0] = toupper(pretty[0]);
337 
338     if (0 > asprintf(&path, "path:%s", type)) {
339         free(pretty);
340         return;
341     }
342     pmix_info_out(pretty, path, value);
343     free(pretty);
344     free(path);
345 }
346 
pmix_info_do_path(bool want_all,pmix_cmd_line_t * cmd_line)347 void pmix_info_do_path(bool want_all, pmix_cmd_line_t *cmd_line)
348 {
349     int i, count;
350     char *scope;
351 
352     /* Check bozo case */
353     count = pmix_cmd_line_get_ninsts(cmd_line, "path");
354     for (i = 0; i < count; ++i) {
355         scope = pmix_cmd_line_get_param(cmd_line, "path", i, 0);
356         if (0 == strcmp("all", scope)) {
357             want_all = true;
358             break;
359         }
360     }
361 
362     if (want_all) {
363         pmix_info_show_path(pmix_info_path_prefix, pmix_pinstall_dirs.prefix);
364         pmix_info_show_path(pmix_info_path_exec_prefix, pmix_pinstall_dirs.exec_prefix);
365         pmix_info_show_path(pmix_info_path_bindir, pmix_pinstall_dirs.bindir);
366         pmix_info_show_path(pmix_info_path_sbindir, pmix_pinstall_dirs.sbindir);
367         pmix_info_show_path(pmix_info_path_libdir, pmix_pinstall_dirs.libdir);
368         pmix_info_show_path(pmix_info_path_incdir, pmix_pinstall_dirs.includedir);
369         pmix_info_show_path(pmix_info_path_mandir, pmix_pinstall_dirs.mandir);
370         pmix_info_show_path(pmix_info_path_pkglibdir, pmix_pinstall_dirs.pmixlibdir);
371         pmix_info_show_path(pmix_info_path_libexecdir, pmix_pinstall_dirs.libexecdir);
372         pmix_info_show_path(pmix_info_path_datarootdir, pmix_pinstall_dirs.datarootdir);
373         pmix_info_show_path(pmix_info_path_datadir, pmix_pinstall_dirs.datadir);
374         pmix_info_show_path(pmix_info_path_sysconfdir, pmix_pinstall_dirs.sysconfdir);
375         pmix_info_show_path(pmix_info_path_sharedstatedir, pmix_pinstall_dirs.sharedstatedir);
376         pmix_info_show_path(pmix_info_path_localstatedir, pmix_pinstall_dirs.localstatedir);
377         pmix_info_show_path(pmix_info_path_infodir, pmix_pinstall_dirs.infodir);
378         pmix_info_show_path(pmix_info_path_pkgdatadir, pmix_pinstall_dirs.pmixdatadir);
379         pmix_info_show_path(pmix_info_path_pkglibdir, pmix_pinstall_dirs.pmixlibdir);
380         pmix_info_show_path(pmix_info_path_pkgincludedir, pmix_pinstall_dirs.pmixincludedir);
381     } else {
382         count = pmix_cmd_line_get_ninsts(cmd_line, "path");
383         for (i = 0; i < count; ++i) {
384             scope = pmix_cmd_line_get_param(cmd_line, "path", i, 0);
385 
386             if (0 == strcmp(pmix_info_path_prefix, scope)) {
387                 pmix_info_show_path(pmix_info_path_prefix, pmix_pinstall_dirs.prefix);
388             } else if (0 == strcmp(pmix_info_path_bindir, scope)) {
389                 pmix_info_show_path(pmix_info_path_bindir, pmix_pinstall_dirs.bindir);
390             } else if (0 == strcmp(pmix_info_path_libdir, scope)) {
391                 pmix_info_show_path(pmix_info_path_libdir, pmix_pinstall_dirs.libdir);
392             } else if (0 == strcmp(pmix_info_path_incdir, scope)) {
393                 pmix_info_show_path(pmix_info_path_incdir, pmix_pinstall_dirs.includedir);
394             } else if (0 == strcmp(pmix_info_path_mandir, scope)) {
395                 pmix_info_show_path(pmix_info_path_mandir, pmix_pinstall_dirs.mandir);
396             } else if (0 == strcmp(pmix_info_path_pkglibdir, scope)) {
397                 pmix_info_show_path(pmix_info_path_pkglibdir, pmix_pinstall_dirs.pmixlibdir);
398             } else if (0 == strcmp(pmix_info_path_sysconfdir, scope)) {
399                 pmix_info_show_path(pmix_info_path_sysconfdir, pmix_pinstall_dirs.sysconfdir);
400             } else if (0 == strcmp(pmix_info_path_exec_prefix, scope)) {
401                 pmix_info_show_path(pmix_info_path_exec_prefix, pmix_pinstall_dirs.exec_prefix);
402             } else if (0 == strcmp(pmix_info_path_sbindir, scope)) {
403                 pmix_info_show_path(pmix_info_path_sbindir, pmix_pinstall_dirs.sbindir);
404             } else if (0 == strcmp(pmix_info_path_libexecdir, scope)) {
405                 pmix_info_show_path(pmix_info_path_libexecdir, pmix_pinstall_dirs.libexecdir);
406             } else if (0 == strcmp(pmix_info_path_datarootdir, scope)) {
407                 pmix_info_show_path(pmix_info_path_datarootdir, pmix_pinstall_dirs.datarootdir);
408             } else if (0 == strcmp(pmix_info_path_datadir, scope)) {
409                 pmix_info_show_path(pmix_info_path_datadir, pmix_pinstall_dirs.datadir);
410             } else if (0 == strcmp(pmix_info_path_sharedstatedir, scope)) {
411                 pmix_info_show_path(pmix_info_path_sharedstatedir, pmix_pinstall_dirs.sharedstatedir);
412             } else if (0 == strcmp(pmix_info_path_localstatedir, scope)) {
413                 pmix_info_show_path(pmix_info_path_localstatedir, pmix_pinstall_dirs.localstatedir);
414             } else if (0 == strcmp(pmix_info_path_infodir, scope)) {
415                 pmix_info_show_path(pmix_info_path_infodir, pmix_pinstall_dirs.infodir);
416             } else if (0 == strcmp(pmix_info_path_pkgdatadir, scope)) {
417                 pmix_info_show_path(pmix_info_path_pkgdatadir, pmix_pinstall_dirs.pmixdatadir);
418             } else if (0 == strcmp(pmix_info_path_pkgincludedir, scope)) {
419                 pmix_info_show_path(pmix_info_path_pkgincludedir, pmix_pinstall_dirs.pmixincludedir);
420             } else {
421                 char *usage = pmix_cmd_line_get_usage_msg(cmd_line);
422                 pmix_show_help("help-pmix_info.txt", "usage", true, usage);
423                 free(usage);
424                 exit(1);
425             }
426         }
427     }
428 }
429 
pmix_info_do_params(bool want_all_in,bool want_internal,pmix_pointer_array_t * mca_types,pmix_pointer_array_t * component_map,pmix_cmd_line_t * pmix_info_cmd_line)430 void pmix_info_do_params(bool want_all_in, bool want_internal,
431                          pmix_pointer_array_t *mca_types,
432                          pmix_pointer_array_t *component_map,
433                          pmix_cmd_line_t *pmix_info_cmd_line)
434 {
435     pmix_mca_base_var_info_lvl_t max_level = PMIX_INFO_LVL_1;
436     int count;
437     char *type, *component, *str;
438     bool found;
439     int i;
440     bool want_all = false;
441     char *p;
442 
443     if (pmix_cmd_line_is_taken(pmix_info_cmd_line, "param")) {
444         p = "param";
445     } else if (pmix_cmd_line_is_taken(pmix_info_cmd_line, "params")) {
446         p = "params";
447     } else {
448         p = "foo";  /* should never happen, but protect against segfault */
449     }
450 
451     if (NULL != (str = pmix_cmd_line_get_param (pmix_info_cmd_line, "level", 0, 0))) {
452         char *tmp;
453 
454         errno = 0;
455         max_level = strtol (str, &tmp, 10) + PMIX_INFO_LVL_1 - 1;
456         if (0 != errno || '\0' != tmp[0] || max_level < PMIX_INFO_LVL_1 || max_level > PMIX_INFO_LVL_9) {
457             char *usage = pmix_cmd_line_get_usage_msg(pmix_info_cmd_line);
458             pmix_show_help("help-pmix_info.txt", "invalid-level", true, str);
459             free(usage);
460             exit(1);
461         }
462     } else if (want_all_in) {
463         /* if not specified default to level 9 if all components are requested */
464         max_level = PMIX_INFO_LVL_9;
465     }
466 
467     if (want_all_in) {
468         want_all = true;
469     } else {
470         /* See if the special param "all" was given to --param; that
471          * supercedes any individual type
472          */
473         count = pmix_cmd_line_get_ninsts(pmix_info_cmd_line, p);
474         for (i = 0; i < count; ++i) {
475             type = pmix_cmd_line_get_param(pmix_info_cmd_line, p, (int)i, 0);
476             if (0 == strcmp(pmix_info_type_all, type)) {
477                 want_all = true;
478                 break;
479             }
480         }
481     }
482 
483     /* Show the params */
484 
485     if (want_all) {
486         pmix_info_show_component_version(mca_types, component_map, pmix_info_type_all,
487                                          pmix_info_component_all, pmix_info_ver_full,
488                                          pmix_info_ver_all);
489         for (i = 0; i < mca_types->size; ++i) {
490             if (NULL == (type = (char *)pmix_pointer_array_get_item(mca_types, i))) {
491                 continue;
492             }
493             pmix_info_show_mca_params(type, pmix_info_component_all, max_level, want_internal);
494         }
495     } else {
496         for (i = 0; i < count; ++i) {
497             type = pmix_cmd_line_get_param(pmix_info_cmd_line, p, (int)i, 0);
498             component = pmix_cmd_line_get_param(pmix_info_cmd_line, p, (int)i, 1);
499 
500             for (found = false, i = 0; i < mca_types->size; ++i) {
501                 if (NULL == (str = (char *)pmix_pointer_array_get_item(mca_types, i))) {
502                     continue;
503                 }
504                 if (0 == strcmp(str, type)) {
505                     found = true;
506                     break;
507                 }
508             }
509 
510             if (!found) {
511                 char *usage = pmix_cmd_line_get_usage_msg(pmix_info_cmd_line);
512                 pmix_show_help("help-pmix_info.txt", "not-found", true, type);
513                 free(usage);
514                 exit(1);
515             }
516 
517             pmix_info_show_component_version(mca_types, component_map, type,
518                                              component, pmix_info_ver_full,
519                                              pmix_info_ver_all);
520             pmix_info_show_mca_params(type, component, max_level, want_internal);
521         }
522     }
523 }
524 
pmix_info_err_params(pmix_pointer_array_t * component_map)525 void pmix_info_err_params(pmix_pointer_array_t *component_map)
526 {
527     pmix_info_component_map_t *map=NULL, *mptr;
528     int i;
529 
530     /* all we want to do is display the LAST entry in the
531      * component_map array as this is the one that generated the error
532      */
533     for (i=0; i < component_map->size; i++) {
534         if (NULL == (mptr = (pmix_info_component_map_t*)pmix_pointer_array_get_item(component_map, i))) {
535             continue;
536         }
537         map = mptr;
538     }
539     if (NULL == map) {
540         fprintf(stderr, "pmix_info_err_params: map not found\n");
541         return;
542     }
543     pmix_info_show_mca_params(map->type, pmix_info_component_all, PMIX_INFO_LVL_9, true);
544     fprintf(stderr, "\n");
545     return;
546 }
547 
pmix_info_do_type(pmix_cmd_line_t * pmix_info_cmd_line)548 void pmix_info_do_type(pmix_cmd_line_t *pmix_info_cmd_line)
549 {
550     pmix_mca_base_var_info_lvl_t max_level = PMIX_INFO_LVL_1;
551     int count;
552     char *type, *str;
553     int i, j, k, len, ret;
554     char *p;
555     const pmix_mca_base_var_t *var;
556     char** strings, *message;
557     const pmix_mca_base_var_group_t *group;
558     p = "type";
559 
560     if (NULL != (str = pmix_cmd_line_get_param (pmix_info_cmd_line, "level", 0, 0))) {
561         char *tmp;
562 
563         errno = 0;
564         max_level = strtol (str, &tmp, 10) + PMIX_INFO_LVL_1 - 1;
565         if (0 != errno || '\0' != tmp[0] || max_level < PMIX_INFO_LVL_1 || max_level > PMIX_INFO_LVL_9) {
566             char *usage = pmix_cmd_line_get_usage_msg(pmix_info_cmd_line);
567             pmix_show_help("help-pmix_info.txt", "invalid-level", true, str);
568             free(usage);
569             exit(1);
570         }
571     }
572 
573     count = pmix_cmd_line_get_ninsts(pmix_info_cmd_line, p);
574     len = pmix_mca_base_var_get_count ();
575 
576     for (k = 0; k < count; ++k) {
577         type = pmix_cmd_line_get_param(pmix_info_cmd_line, p, k, 0);
578         for (i = 0; i < len; ++i) {
579             ret = pmix_mca_base_var_get (i, &var);
580             if (PMIX_SUCCESS != ret) {
581                 continue;
582             }
583             if (0 == strcmp(type, pmix_var_type_names[var->mbv_type]) && (var->mbv_info_lvl <= max_level)) {
584                 ret = pmix_mca_base_var_dump(var->mbv_index, &strings, !pmix_info_pretty ? PMIX_MCA_BASE_VAR_DUMP_PARSABLE : PMIX_MCA_BASE_VAR_DUMP_READABLE);
585                 if (PMIX_SUCCESS != ret) {
586                     continue;
587                 }
588                 (void) pmix_mca_base_var_group_get(var->mbv_group_index, &group);
589                 for (j = 0 ; strings[j] ; ++j) {
590                     if (0 == j && pmix_info_pretty) {
591                         if (0 > asprintf (&message, "MCA %s", group->group_framework)) {
592                             continue;
593                         }
594                         pmix_info_out(message, message, strings[j]);
595                         free(message);
596                     } else {
597                         pmix_info_out("", "", strings[j]);
598                     }
599                     free(strings[j]);
600                 }
601                 free(strings);
602             }
603         }
604     }
605 }
606 
pmix_info_show_mca_group_params(const pmix_mca_base_var_group_t * group,pmix_mca_base_var_info_lvl_t max_level,bool want_internal)607 static void pmix_info_show_mca_group_params(const pmix_mca_base_var_group_t *group, pmix_mca_base_var_info_lvl_t max_level, bool want_internal)
608 {
609     const int *variables, *groups;
610     const char *group_component;
611     const pmix_mca_base_var_t *var;
612     char **strings, *message;
613     bool requested = true;
614     int ret, i, j, count;
615 
616     variables = PMIX_VALUE_ARRAY_GET_BASE(&group->group_vars, const int);
617     count = pmix_value_array_get_size((pmix_value_array_t *)&group->group_vars);
618 
619     /* the default component name is "base". depending on how the
620      * group was registered the group may or not have this set.  */
621     group_component = group->group_component ? group->group_component : "base";
622 
623     /* check if this group may be disabled due to a selection variable */
624     if (0 != strcmp (group_component, "base")) {
625         int var_id;
626 
627         /* read the selection parameter */
628         var_id = pmix_mca_base_var_find (group->group_project, group->group_framework, NULL, NULL);
629         if (0 <= var_id) {
630             const pmix_mca_base_var_storage_t *value=NULL;
631             char **requested_components;
632             bool include_mode;
633 
634             pmix_mca_base_var_get_value (var_id, &value, NULL, NULL);
635             if (NULL != value && NULL != value->stringval && '\0' != value->stringval[0]) {
636                 pmix_mca_base_component_parse_requested (value->stringval, &include_mode, &requested_components);
637 
638                 for (i = 0, requested = !include_mode ; requested_components[i] ; ++i) {
639                     if (0 == strcmp (requested_components[i], group_component)) {
640                         requested = include_mode;
641                         break;
642                     }
643                 }
644 
645                 pmix_argv_free (requested_components);
646             }
647         }
648     }
649 
650     const pmix_mca_base_var_group_t *curr_group = NULL;
651     char *component_msg = NULL;
652     if (0 > asprintf(&component_msg, " %s", group_component)) {
653         return;
654     }
655 
656     for (i = 0 ; i < count ; ++i) {
657         ret = pmix_mca_base_var_get(variables[i], &var);
658         if (PMIX_SUCCESS != ret || ((var->mbv_flags & PMIX_MCA_BASE_VAR_FLAG_INTERNAL) &&
659                                     !want_internal) ||
660             max_level < var->mbv_info_lvl) {
661             continue;
662         }
663 
664         if (pmix_info_pretty && curr_group != group) {
665             if (0 > asprintf(&message, "MCA%s %s%s", requested ? "" : " (-)",
666                              group->group_framework,
667                              component_msg ? component_msg : "")) {
668                 continue;
669             }
670             pmix_info_out(message, message, "---------------------------------------------------");
671             free(message);
672             curr_group = group;
673         }
674 
675         ret = pmix_mca_base_var_dump(variables[i], &strings, !pmix_info_pretty ? PMIX_MCA_BASE_VAR_DUMP_PARSABLE : PMIX_MCA_BASE_VAR_DUMP_READABLE);
676         if (PMIX_SUCCESS != ret) {
677             continue;
678         }
679 
680         for (j = 0 ; strings[j] ; ++j) {
681             if (0 == j && pmix_info_pretty) {
682                 if (0 > asprintf (&message, "MCA%s %s%s", requested ? "" : " (-)",
683                                   group->group_framework,
684                                   component_msg ? component_msg : "")) {
685                     continue;
686                 }
687                 pmix_info_out(message, message, strings[j]);
688                 free(message);
689             } else {
690                 pmix_info_out("", "", strings[j]);
691             }
692             free(strings[j]);
693         }
694         if (!pmix_info_pretty) {
695             /* generate an entry indicating whether this variable is disabled or not. if the
696              * format in mca_base_var/pvar.c changes this needs to be changed as well */
697             if (0 > asprintf (&message, "mca:%s:%s:param:%s:disabled:%s", group->group_framework,
698                               group_component, var->mbv_full_name, requested ? "false" : "true")) {
699                 continue;
700             }
701             pmix_info_out("", "", message);
702             free (message);
703         }
704         free(strings);
705     }
706 
707     groups = PMIX_VALUE_ARRAY_GET_BASE(&group->group_subgroups, const int);
708     count = pmix_value_array_get_size((pmix_value_array_t *)&group->group_subgroups);
709 
710     for (i = 0 ; i < count ; ++i) {
711         ret = pmix_mca_base_var_group_get(groups[i], &group);
712         if (PMIX_SUCCESS != ret) {
713             continue;
714         }
715         pmix_info_show_mca_group_params(group, max_level, want_internal);
716     }
717     free(component_msg);
718 }
719 
pmix_info_show_mca_params(const char * type,const char * component,pmix_mca_base_var_info_lvl_t max_level,bool want_internal)720 void pmix_info_show_mca_params(const char *type, const char *component,
721                                pmix_mca_base_var_info_lvl_t max_level, bool want_internal)
722 {
723     const pmix_mca_base_var_group_t *group;
724     int ret;
725 
726     if (0 == strcmp (component, "all")) {
727         ret = pmix_mca_base_var_group_find("*", type, NULL);
728         if (0 > ret) {
729             return;
730         }
731 
732         (void) pmix_mca_base_var_group_get(ret, &group);
733 
734         pmix_info_show_mca_group_params(group, max_level, want_internal);
735     } else {
736         ret = pmix_mca_base_var_group_find("*", type, component);
737         if (0 > ret) {
738             return;
739         }
740 
741         (void) pmix_mca_base_var_group_get(ret, &group);
742         pmix_info_show_mca_group_params(group, max_level, want_internal);
743     }
744 }
745 
746 
747 
pmix_info_do_arch()748 void pmix_info_do_arch()
749 {
750     pmix_info_out("Configured architecture", "config:arch", PMIX_ARCH);
751 }
752 
753 
pmix_info_do_hostname()754 void pmix_info_do_hostname()
755 {
756     pmix_info_out("Configure host", "config:host", PMIX_CONFIGURE_HOST);
757 }
758 
759 
escape_quotes(const char * value)760 static char *escape_quotes(const char *value)
761 {
762     const char *src;
763     int num_quotes = 0;
764     for (src = value; src != NULL && *src != '\0'; ++src) {
765         if ('"' == *src) {
766             ++num_quotes;
767         }
768     }
769 
770     // If there are no quotes in the string, there's nothing to do
771     if (0 == num_quotes) {
772         return NULL;
773     }
774 
775     // If we have quotes, make a new string.  Copy over the old
776     // string, escaping the quotes along the way.  This is simple and
777     // clear to read; it's not particularly efficient (performance is
778     // definitely not important here).
779     char *quoted_value;
780     quoted_value = calloc(1, strlen(value) + num_quotes + 1);
781     if (NULL == quoted_value) {
782         return NULL;
783     }
784 
785     char *dest;
786     for (src = value, dest = quoted_value; *src != '\0'; ++src, ++dest) {
787         if ('"' == *src) {
788             *dest++ = '\\';
789         }
790         *dest = *src;
791     }
792 
793     return quoted_value;
794 }
795 
796 
797 /*
798  * Private variables - set some reasonable screen size defaults
799  */
800 
801 static int centerpoint = 24;
802 static int screen_width = 78;
803 
804 /*
805  * Prints the passed message in a pretty or parsable format.
806  */
pmix_info_out(const char * pretty_message,const char * plain_message,const char * value)807 void pmix_info_out(const char *pretty_message, const char *plain_message, const char *value)
808 {
809     size_t len, max_value_width, value_offset;
810     char *spaces = NULL;
811     char *filler = NULL;
812     char *pos, *v, savev, *v_to_free;
813 
814 #ifdef HAVE_ISATTY
815     /* If we have isatty(), if this is not a tty, then disable
816      * wrapping for grep-friendly behavior
817      */
818     if (0 == isatty(STDOUT_FILENO)) {
819         screen_width = INT_MAX;
820     }
821 #endif
822 
823 #ifdef TIOCGWINSZ
824     if (screen_width < INT_MAX) {
825         struct winsize size;
826         if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char*) &size) >= 0) {
827             screen_width = size.ws_col;
828         }
829     }
830 #endif
831 
832     /* Sanity check (allow NULL to mean "") */
833     if (NULL == value) {
834         value = "";
835     }
836 
837     /* Strip leading and trailing whitespace from the string value */
838     value_offset = strspn(value, " ");
839 
840     v = v_to_free = strdup(value + value_offset);
841     len = strlen(v);
842 
843     if (len > 0) {
844         while (len > 0 && isspace(v[len-1])) len--;
845         v[len] = '\0';
846     }
847 
848     if (pmix_info_pretty && NULL != pretty_message) {
849         if (centerpoint > (int)strlen(pretty_message)) {
850             if (0 > asprintf(&spaces, "%*s", centerpoint -
851                              (int)strlen(pretty_message), " ")) {
852                 if (NULL != v_to_free) {
853                     free(v_to_free);
854                 }
855                 return;
856             }
857         } else {
858             spaces = strdup("");
859 #if PMIX_ENABLE_DEBUG
860             if (centerpoint < (int)strlen(pretty_message)) {
861                 pmix_show_help("help-pmix_info.txt",
862                                "developer warning: field too long", false,
863                                pretty_message, centerpoint);
864             }
865 #endif
866         }
867         max_value_width = screen_width - strlen(spaces) - strlen(pretty_message) - 2;
868         if (0 < strlen(pretty_message)) {
869             if (0 > asprintf(&filler, "%s%s: ", spaces, pretty_message)) {
870                 if (NULL != v_to_free) {
871                     free(v_to_free);
872                 }
873                 return;
874             }
875         } else {
876             if (0 > asprintf(&filler, "%s  ", spaces)) {
877                 if (NULL != v_to_free) {
878                     free(v_to_free);
879                 }
880                 return;
881             }
882         }
883         free(spaces);
884         spaces = NULL;
885 
886         while (true) {
887             if (strlen(v) < max_value_width) {
888                 printf("%s%s\n", filler, v);
889                 break;
890             } else {
891                 if (0 > asprintf(&spaces, "%*s", centerpoint + 2, " ")) {
892                     if (NULL != v_to_free) {
893                         free(v_to_free);
894                     }
895                     return;
896                 }
897 
898                 /* Work backwards to find the first space before
899                  * max_value_width
900                  */
901                 savev = v[max_value_width];
902                 v[max_value_width] = '\0';
903                 pos = (char*)strrchr(v, (int)' ');
904                 v[max_value_width] = savev;
905                 if (NULL == pos) {
906                     /* No space found < max_value_width.  Look for the first
907                      * space after max_value_width.
908                      */
909                     pos = strchr(&v[max_value_width], ' ');
910 
911                     if (NULL == pos) {
912 
913                         /* There's just no spaces.  So just print it and be done. */
914 
915                         printf("%s%s\n", filler, v);
916                         break;
917                     } else {
918                         *pos = '\0';
919                         printf("%s%s\n", filler, v);
920                         v = pos + 1;
921                     }
922                 } else {
923                     *pos = '\0';
924                     printf("%s%s\n", filler, v);
925                     v = pos + 1;
926                 }
927 
928                 /* Reset for the next iteration */
929                 free(filler);
930                 filler = strdup(spaces);
931                 free(spaces);
932                 spaces = NULL;
933             }
934         }
935         if (NULL != filler) {
936             free(filler);
937         }
938         if (NULL != spaces) {
939             free(spaces);
940         }
941     } else {
942         if (NULL != plain_message && 0 < strlen(plain_message)) {
943             // Escape any double quotes in the value.
944             char *quoted_value;
945             quoted_value = escape_quotes(value);
946             if (NULL != quoted_value) {
947                 value = quoted_value;
948             }
949 
950             char *colon = strchr(value, ':');
951             if (NULL != colon) {
952                 printf("%s:\"%s\"\n", plain_message, value);
953             } else {
954                 printf("%s:%s\n", plain_message, value);
955             }
956 
957             if (NULL != quoted_value) {
958                 free(quoted_value);
959             }
960         } else {
961             printf("%s\n", value);
962         }
963     }
964     if (NULL != v_to_free) {
965         free(v_to_free);
966     }
967 }
968 
969 /*
970  * Prints the passed integer in a pretty or parsable format.
971  */
pmix_info_out_int(const char * pretty_message,const char * plain_message,int value)972 void pmix_info_out_int(const char *pretty_message,
973                        const char *plain_message,
974                        int value)
975 {
976     char *valstr;
977 
978     if (0 > asprintf(&valstr, "%d", (int)value)) {
979         return;
980     }
981     pmix_info_out(pretty_message, plain_message, valstr);
982     free(valstr);
983 }
984 
985 /*
986  * Show all the components of a specific type/component combo (component may be
987  * a wildcard)
988  */
pmix_info_show_component_version(pmix_pointer_array_t * mca_types,pmix_pointer_array_t * component_map,const char * type_name,const char * component_name,const char * scope,const char * ver_type)989 void pmix_info_show_component_version(pmix_pointer_array_t *mca_types,
990                                       pmix_pointer_array_t *component_map,
991                                       const char *type_name,
992                                       const char *component_name,
993                                       const char *scope, const char *ver_type)
994 {
995     bool want_all_components = false;
996     bool want_all_types = false;
997     bool found;
998     pmix_mca_base_component_list_item_t *cli;
999     pmix_mca_base_failed_component_t *cli_failed;
1000     int j;
1001     char *pos;
1002     pmix_info_component_map_t *map;
1003 
1004     /* see if all components wanted */
1005     if (0 == strcmp(pmix_info_component_all, component_name)) {
1006         want_all_components = true;
1007     }
1008 
1009     /* see if all types wanted */
1010     if (0 != strcmp(pmix_info_type_all, type_name)) {
1011         /* Check to see if the type is valid */
1012 
1013         for (found = false, j = 0; j < mca_types->size; ++j) {
1014             if (NULL == (pos = (char*)pmix_pointer_array_get_item(mca_types, j))) {
1015                 continue;
1016             }
1017             if (0 == strcmp(pos, type_name)) {
1018                 found = true;
1019                 break;
1020             }
1021         }
1022 
1023         if (!found) {
1024             return;
1025         }
1026     } else {
1027         want_all_types = true;
1028     }
1029 
1030     /* Now that we have a valid type, find the right components */
1031     for (j=0; j < component_map->size; j++) {
1032         if (NULL == (map = (pmix_info_component_map_t*)pmix_pointer_array_get_item(component_map, j))) {
1033             continue;
1034         }
1035         if ((want_all_types || 0 == strcmp(type_name, map->type)) && map->components) {
1036             /* found it! */
1037             PMIX_LIST_FOREACH(cli, map->components, pmix_mca_base_component_list_item_t) {
1038                 const pmix_mca_base_component_t *component = cli->cli_component;
1039                 if (want_all_components ||
1040                     0 == strcmp(component->pmix_mca_component_name, component_name)) {
1041                     pmix_info_show_mca_version(component, scope, ver_type);
1042                 }
1043             }
1044 
1045             /* found it! */
1046             PMIX_LIST_FOREACH(cli_failed, map->failed_components, pmix_mca_base_failed_component_t) {
1047                 pmix_mca_base_component_repository_item_t *ri = cli_failed->comp;
1048                 if (want_all_components ||
1049                     0 == strcmp(component_name, ri->ri_name) ) {
1050                     pmix_info_show_failed_component(ri, cli_failed->error_msg);
1051                 }
1052             }
1053 
1054             if (!want_all_types) {
1055                 break;
1056             }
1057         }
1058     }
1059 }
1060 
1061 
pmix_info_show_failed_component(const pmix_mca_base_component_repository_item_t * ri,const char * error_msg)1062 static void pmix_info_show_failed_component(const pmix_mca_base_component_repository_item_t* ri,
1063                                             const char *error_msg)
1064 {
1065     char *message, *content;
1066 
1067     if (pmix_info_pretty) {
1068         if (0 > asprintf(&message, "MCA %s", ri->ri_type)) {
1069             return;
1070         }
1071         if (0 > asprintf(&content, "%s (failed to load) %s", ri->ri_name, error_msg)) {
1072             free(message);
1073             return;
1074         }
1075 
1076         pmix_info_out(message, NULL, content);
1077 
1078         free(message);
1079         free(content);
1080     } else {
1081         if (0 > asprintf(&message, "mca:%s:%s:failed", ri->ri_type, ri->ri_name)) {
1082             return;
1083         }
1084         if (0 > asprintf(&content, "%s", error_msg)) {
1085             free(message);
1086             return;
1087         }
1088 
1089         pmix_info_out(NULL, message, content);
1090 
1091         free(message);
1092         free(content);
1093     }
1094 }
1095 
1096 /*
1097  * Given a component, display its relevant version(s)
1098  */
pmix_info_show_mca_version(const pmix_mca_base_component_t * component,const char * scope,const char * ver_type)1099 void pmix_info_show_mca_version(const pmix_mca_base_component_t* component,
1100                                 const char *scope, const char *ver_type)
1101 {
1102     bool printed;
1103     bool want_mca = false;
1104     bool want_type = false;
1105     bool want_component = false;
1106     char *message = NULL, *content = NULL;
1107     char *mca_version;
1108     char *api_version;
1109     char *component_version;
1110     char *tmp;
1111 
1112     if (0 == strcmp(ver_type, pmix_info_ver_all) ||
1113         0 == strcmp(ver_type, pmix_info_ver_mca)) {
1114         want_mca = true;
1115     }
1116 
1117     if (0 == strcmp(ver_type, pmix_info_ver_all) ||
1118         0 == strcmp(ver_type, pmix_info_ver_type)) {
1119         want_type = true;
1120     }
1121 
1122     if (0 == strcmp(ver_type, pmix_info_ver_all) ||
1123         0 == strcmp(ver_type, pmix_info_ver_component)) {
1124         want_component = true;
1125     }
1126 
1127     mca_version = pmix_info_make_version_str(scope, component->pmix_mca_major_version,
1128                                              component->pmix_mca_minor_version,
1129                                              component->pmix_mca_release_version, "",
1130                                              "");
1131     api_version = pmix_info_make_version_str(scope, component->pmix_mca_type_major_version,
1132                                              component->pmix_mca_type_minor_version,
1133                                              component->pmix_mca_type_release_version, "",
1134                                              "");
1135     component_version = pmix_info_make_version_str(scope, component->pmix_mca_component_major_version,
1136                                                    component->pmix_mca_component_minor_version,
1137                                                    component->pmix_mca_component_release_version,
1138                                                    "", "");
1139     if (pmix_info_pretty) {
1140         if (0 > asprintf(&message, "MCA %s", component->pmix_mca_type_name)) {
1141             goto exit;
1142         }
1143         printed = false;
1144         if (0 > asprintf(&content, "%s (", component->pmix_mca_component_name)) {
1145             goto exit;
1146         }
1147 
1148         if (want_mca) {
1149             if (0 > asprintf(&tmp, "%sMCA v%s", content, mca_version)) {
1150                 goto exit;
1151             }
1152             content = tmp;
1153             printed = true;
1154         }
1155 
1156         if (want_type) {
1157             if (printed) {
1158                 if (0 > asprintf(&tmp, "%s, ", content)) {
1159                     goto exit;
1160                 }
1161                 free(content);
1162                 content = tmp;
1163             }
1164             if (0 > asprintf(&tmp, "%sAPI v%s", content, api_version)) {
1165                 goto exit;
1166             }
1167             free(content);
1168             content = tmp;
1169             printed = true;
1170         }
1171 
1172         if (want_component) {
1173             if (printed) {
1174                 if (0 > asprintf(&tmp, "%s, ", content)) {
1175                     goto exit;
1176                 }
1177                 free(content);
1178                 content = tmp;
1179             }
1180             if (0 > asprintf(&tmp, "%sComponent v%s", content, component_version)) {
1181                 goto exit;
1182             }
1183             free(content);
1184             content = tmp;
1185             printed = true;
1186         }
1187         if (NULL != content) {
1188             if (0 > asprintf(&tmp, "%s)", content)) {
1189                 goto exit;
1190             }
1191         } else {
1192             tmp = NULL;
1193         }
1194 
1195         pmix_info_out(message, NULL, tmp);
1196         if (NULL != tmp) {
1197             free(tmp);
1198         }
1199 
1200     } else {
1201         if (0 > asprintf(&message, "mca:%s:%s:version", component->pmix_mca_type_name, component->pmix_mca_component_name)) {
1202             goto exit;
1203         }
1204         if (want_mca) {
1205             if (0 > asprintf(&tmp, "mca:%s", mca_version)) {
1206                 goto exit;
1207             }
1208             pmix_info_out(NULL, message, tmp);
1209             free(tmp);
1210         }
1211         if (want_type) {
1212             if (0 > asprintf(&tmp, "api:%s", api_version)) {
1213                 goto exit;
1214             }
1215             pmix_info_out(NULL, message, tmp);
1216             free(tmp);
1217         }
1218         if (want_component) {
1219             if (0 > asprintf(&tmp, "component:%s", component_version)) {
1220                 goto exit;
1221             }
1222             pmix_info_out(NULL, message, tmp);
1223             free(tmp);
1224         }
1225     }
1226 
1227 exit:
1228     if (NULL != mca_version) {
1229         free(mca_version);
1230     }
1231     if (NULL != api_version) {
1232         free(api_version);
1233     }
1234     if (NULL != component_version) {
1235         free(component_version);
1236     }
1237     if (NULL != message) {
1238         free(message);
1239     }
1240     if (NULL != content) {
1241         free(content);
1242     }
1243 }
1244 
1245 
pmix_info_make_version_str(const char * scope,int major,int minor,int release,const char * greek,const char * repo)1246 char *pmix_info_make_version_str(const char *scope,
1247                                  int major, int minor, int release,
1248                                  const char *greek,
1249                                  const char *repo)
1250 {
1251     char *str = NULL, *tmp;
1252     char temp[BUFSIZ];
1253 
1254     temp[BUFSIZ - 1] = '\0';
1255     if (0 == strcmp(scope, pmix_info_ver_full) ||
1256         0 == strcmp(scope, pmix_info_ver_all)) {
1257         snprintf(temp, BUFSIZ - 1, "%d.%d.%d", major, minor, release);
1258         str = strdup(temp);
1259         if (NULL != greek) {
1260             if (0 > asprintf(&tmp, "%s%s", str, greek)) {
1261                 free(str);
1262                 return NULL;
1263             }
1264             free(str);
1265             str = tmp;
1266         }
1267     } else if (0 == strcmp(scope, pmix_info_ver_major)) {
1268         snprintf(temp, BUFSIZ - 1, "%d", major);
1269     } else if (0 == strcmp(scope, pmix_info_ver_minor)) {
1270         snprintf(temp, BUFSIZ - 1, "%d", minor);
1271     } else if (0 == strcmp(scope, pmix_info_ver_release)) {
1272         snprintf(temp, BUFSIZ - 1, "%d", release);
1273     } else if (0 == strcmp(scope, pmix_info_ver_greek)) {
1274         str = strdup(greek);
1275     } else if (0 == strcmp(scope, pmix_info_ver_repo)) {
1276         str = strdup(repo);
1277     }
1278 
1279     if (NULL == str) {
1280         str = strdup(temp);
1281     }
1282 
1283     return str;
1284 }
1285 
pmix_info_show_pmix_version(const char * scope)1286 void pmix_info_show_pmix_version(const char *scope)
1287 {
1288     char *tmp, *tmp2;
1289 
1290     if (0 > asprintf(&tmp, "%s:version:full", pmix_info_type_pmix)) {
1291         return;
1292     }
1293     tmp2 = pmix_info_make_version_str(scope,
1294                                       PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION,
1295                                       PMIX_RELEASE_VERSION,
1296                                       PMIX_GREEK_VERSION,
1297                                       PMIX_REPO_REV);
1298     pmix_info_out("PMIX", tmp, tmp2);
1299     free(tmp);
1300     free(tmp2);
1301     if (0 > asprintf(&tmp, "%s:version:repo", pmix_info_type_pmix)) {
1302         return;
1303     }
1304     pmix_info_out("PMIX repo revision", tmp, PMIX_REPO_REV);
1305     free(tmp);
1306     if (0 > asprintf(&tmp, "%s:version:release_date", pmix_info_type_pmix)) {
1307         return;
1308     }
1309     pmix_info_out("PMIX release date", tmp, PMIX_RELEASE_DATE);
1310     free(tmp);
1311 }
1312 
1313 /*
1314  * do_config
1315  * Accepts:
1316  *  - want_all: boolean flag; TRUE -> display all options
1317  *                FALSE -> display selected options
1318  *
1319  * This function displays all the options with which the current
1320  * installation of pmix was configured. There are many options here
1321  * that are carried forward from OMPI-7 and are not mca parameters
1322  * in OMPI-10. I have to dig through the invalid options and replace
1323  * them with OMPI-10 options.
1324  */
pmix_info_do_config(bool want_all)1325 void pmix_info_do_config(bool want_all)
1326 {
1327     char *debug;
1328     char *have_dl;
1329     char *symbol_visibility;
1330 
1331     /* setup the strings that don't require allocations*/
1332     debug = PMIX_ENABLE_DEBUG ? "yes" : "no";
1333     have_dl = PMIX_HAVE_PDL_SUPPORT ? "yes" : "no";
1334     symbol_visibility = PMIX_HAVE_VISIBILITY ? "yes" : "no";
1335 
1336     /* output values */
1337     pmix_info_out("Configured by", "config:user", PMIX_CONFIGURE_USER);
1338     pmix_info_out("Configured on", "config:timestamp", PMIX_CONFIGURE_DATE);
1339     pmix_info_out("Configure host", "config:host", PMIX_CONFIGURE_HOST);
1340     pmix_info_out("Configure command line", "config:cli", PMIX_CONFIGURE_CLI);
1341 
1342     pmix_info_out("Built by", "build:user", PMIX_BUILD_USER);
1343     pmix_info_out("Built on", "build:timestamp", PMIX_BUILD_DATE);
1344     pmix_info_out("Built host", "build:host", PMIX_BUILD_HOST);
1345 
1346     pmix_info_out("C compiler", "compiler:c:command", PMIX_CC);
1347     pmix_info_out("C compiler absolute", "compiler:c:absolute", PMIX_CC_ABSOLUTE);
1348     pmix_info_out("C compiler family name", "compiler:c:familyname", _STRINGIFY(PMIX_BUILD_PLATFORM_COMPILER_FAMILYNAME));
1349     pmix_info_out("C compiler version", "compiler:c:version", _STRINGIFY(PMIX_BUILD_PLATFORM_COMPILER_VERSION_STR));
1350 
1351     if (want_all) {
1352         pmix_info_out_int("C char size", "compiler:c:sizeof:char", sizeof(char));
1353         pmix_info_out_int("C bool size", "compiler:c:sizeof:bool", sizeof(bool));
1354         pmix_info_out_int("C short size", "compiler:c:sizeof:short", sizeof(short));
1355         pmix_info_out_int("C int size", "compiler:c:sizeof:int", sizeof(int));
1356         pmix_info_out_int("C long size", "compiler:c:sizeof:long", sizeof(long));
1357         pmix_info_out_int("C float size", "compiler:c:sizeof:float", sizeof(float));
1358         pmix_info_out_int("C double size", "compiler:c:sizeof:double", sizeof(double));
1359         pmix_info_out_int("C pointer size", "compiler:c:sizeof:pointer", sizeof(void *));
1360         pmix_info_out_int("C char align", "compiler:c:align:char", PMIX_ALIGNMENT_CHAR);
1361         pmix_info_out("C bool align", "compiler:c:align:bool", "skipped");
1362         pmix_info_out_int("C int align", "compiler:c:align:int", PMIX_ALIGNMENT_INT);
1363         pmix_info_out_int("C float align", "compiler:c:align:float", PMIX_ALIGNMENT_FLOAT);
1364         pmix_info_out_int("C double align", "compiler:c:align:double", PMIX_ALIGNMENT_DOUBLE);
1365     }
1366 
1367     if (want_all) {
1368         pmix_info_out("Build CFLAGS", "option:build:cflags", PMIX_BUILD_CFLAGS);
1369         pmix_info_out("Build LDFLAGS", "option:build:ldflags", PMIX_BUILD_LDFLAGS);
1370         pmix_info_out("Build LIBS", "option:build:libs", PMIX_BUILD_LIBS);
1371     }
1372 
1373     pmix_info_out("Internal debug support", "option:debug", debug);
1374     pmix_info_out("dl support", "option:dlopen", have_dl);
1375     pmix_info_out("Symbol vis. support", "options:visibility", symbol_visibility);
1376 }
1377