Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-21 09:19:58

0001 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
0002 /*
0003  * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
0004  *                         University Research and Technology
0005  *                         Corporation.  All rights reserved.
0006  * Copyright (c) 2004-2005 The University of Tennessee and The University
0007  *                         of Tennessee Research Foundation.  All rights
0008  *                         reserved.
0009  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
0010  *                         University of Stuttgart.  All rights reserved.
0011  * Copyright (c) 2004-2005 The Regents of the University of California.
0012  *                         All rights reserved.
0013  * Copyright (c) 2012-2020 Cisco Systems, Inc.  All rights reserved
0014  * Copyright (c) 2015-2020 Intel, Inc.  All rights reserved.
0015  * Copyright (c) 2016-2017 Los Alamos National Security, LLC. All rights
0016  *                         reserved.
0017  * Copyright (c) 2017      IBM Corporation. All rights reserved.
0018  * Copyright (c) 2021-2026 Nanook Consulting  All rights reserved.
0019  * $COPYRIGHT$
0020  *
0021  * Additional copyrights may follow
0022  *
0023  * $HEADER$
0024  */
0025 
0026 #ifndef PMIX_CMD_LINE_H
0027 #define PMIX_CMD_LINE_H
0028 
0029 #include "src/include/pmix_config.h"
0030 
0031 #ifdef HAVE_UNISTD_H
0032 #    include <unistd.h>
0033 #endif
0034 #include <ctype.h>
0035 #include <stdio.h>
0036 #include <string.h>
0037 #include <getopt.h>
0038 
0039 #include "src/class/pmix_list.h"
0040 #include "src/class/pmix_object.h"
0041 #include "src/util/pmix_argv.h"
0042 
0043 BEGIN_C_DECLS
0044 
0045 typedef struct {
0046     pmix_list_item_t super;
0047     char *key;
0048     char **values;
0049 } pmix_cli_item_t;
0050 PMIX_CLASS_DECLARATION(pmix_cli_item_t);
0051 
0052 typedef struct {
0053     pmix_object_t super;
0054     pmix_list_t instances;  // comprised of pmix_cli_item_t's
0055     char **tail;  // remainder of argv
0056 } pmix_cli_result_t;
0057 PMIX_CLASS_DECLARATION(pmix_cli_result_t);
0058 
0059 #define PMIX_CLI_RESULT_STATIC_INIT                 \
0060 {                                                   \
0061     .super = PMIX_OBJ_STATIC_INIT(pmix_object_t),   \
0062     .instances = PMIX_LIST_STATIC_INIT,             \
0063     .tail = NULL                                    \
0064 }
0065 
0066 /* define PMIX-named flags for argument required */
0067 #define PMIX_ARG_REQD       required_argument
0068 #define PMIX_ARG_NONE       no_argument
0069 #define PMIX_ARG_OPTIONAL   optional_argument
0070 
0071 /* define PMIX-named flags for whether parsing
0072  * CLI shall include deprecation warnings */
0073 #define PMIX_CLI_SILENT     true
0074 #define PMIX_CLI_WARN       false
0075 
0076 /* define a long option that has no short option equivalent
0077  *
0078  * n = name of the option (see below for definitions)
0079  * a = whether or not it requires an argument
0080  */
0081 #define PMIX_OPTION_DEFINE(n, a)    \
0082 {                                   \
0083     .name = (n),                    \
0084     .has_arg = (a),                 \
0085     .flag = NULL,                   \
0086     .val = 0                        \
0087 }
0088 /* define a long option that has a short option equivalent
0089  *
0090  * n = name of the option (see below for definitions)
0091  * a = whether or not it requires an argument
0092  * c = single character equivalent option
0093  */
0094 #define PMIX_OPTION_SHORT_DEFINE(n, a, c)   \
0095 {                                           \
0096     .name = (n),                            \
0097     .has_arg = (a),                         \
0098     .flag = NULL,                           \
0099     .val = (c)                              \
0100 }
0101 
0102 #define PMIX_OPTION_END  {0, 0, 0, 0}
0103 
0104 //      NAME                            STRING                      ARGUMENT
0105 
0106 // Basic options
0107 #define PMIX_CLI_HELP                   "help"                      // optional
0108 #define PMIX_CLI_VERSION                "version"                   // none
0109 #define PMIX_CLI_VERBOSE                "verbose"                   // number of instances => verbosity level
0110 #define PMIX_CLI_PMIXMCA                "pmixmca"                   // requires TWO
0111 #define PMIX_CLI_PRETTY_PRINT           "pretty-print"              // none
0112 #define PMIX_CLI_PARSABLE               "parsable"                  // none
0113 #define PMIX_CLI_PARSEABLE              "parseable"                 // none
0114 
0115 // Tool connection options
0116 #define PMIX_CLI_SYS_SERVER_FIRST       "system-server-first"       // none
0117 #define PMIX_CLI_SYSTEM_SERVER          "system-server"             // none
0118 #define PMIX_CLI_SYS_SERVER_ONLY        "system-server-only"        // none
0119 #define PMIX_CLI_DO_NOT_CONNECT         "do-not-connect"            // none
0120 #define PMIX_CLI_WAIT_TO_CONNECT        "wait-to-connect"           // required
0121 #define PMIX_CLI_NUM_CONNECT_RETRIES    "num-connect-retries"       // required
0122 #define PMIX_CLI_PID                    "pid"                       // required
0123 #define PMIX_CLI_NAMESPACE              "namespace"                 // required
0124 #define PMIX_CLI_NSPACE                 "nspace"                    // required
0125 #define PMIX_CLI_URI                    "uri"                       // required
0126 #define PMIX_CLI_TIMEOUT                "timeout"                   // required
0127 #define PMIX_CLI_TMPDIR                 "tmpdir"                    // required
0128 #define PMIX_CLI_CONNECTION_ORDER       "connect-order"             // required
0129 #define PMIX_CLI_SYS_CONTROLLER         "system-controller"         // none
0130 
0131 // Allocation request options
0132 #define PMIX_CLI_REQ_ID                 "request-id"                // required
0133 #define PMIX_CLI_QUEUE                  "queue"                     // required, short is 'q'
0134 #define PMIX_CLI_RESOURCES              "resources"                 // required
0135 #define PMIX_CLI_NODES                  "nodes"                     // required, short is 'N'
0136 #define PMIX_CLI_IMAGE                  "image"                     // required, short is 'i'
0137 #define PMIX_CLI_EXCLUDE                "exclude"                   // required, short is 'x'
0138 #define PMIX_CLI_WAIT_ALL_NODES         "wait-all-nodes"            // none
0139 #define PMIX_CLI_NODELIST               "nodelist"                  // required, short is 'w'
0140 #define PMIX_CLI_UID                    "uid"                       // required
0141 #define PMIX_CLI_GID                    "gid"                       // required
0142 #define PMIX_CLI_TIME                   "time"                      // required, short is 't'
0143 #define PMIX_CLI_SIGNAL                 "signal"                    // required
0144 #define PMIX_CLI_SHARE                  "share"                     // none
0145 #define PMIX_CLI_EXTEND                 "extend"                    // none
0146 #define PMIX_CLI_SHRINK                 "shrink"                    // none
0147 #define PMIX_CLI_NO_SHELL               "no-shell"                  // none
0148 #define PMIX_CLI_BEGIN                  "begin"                     // required
0149 #define PMIX_CLI_IMMEDIATE              "immediate"                 // optional, short is 'I'
0150 #define PMIX_CLI_DEPENDENCY             "dependency"                // required, short is 'd'
0151 #define PMIX_CLI_DO_NOT_WAIT            "do-not-wait"               // none
0152 
0153 // Job control options
0154 #define PMIX_CLI_PAUSE                  "pause"                     // none
0155 #define PMIX_CLI_RESUME                 "resume"                    // none
0156 #define PMIX_CLI_CANCEL                 "cancel"                    // required
0157 #define PMIX_CLI_KILL                   "kill"                      // none
0158 #define PMIX_CLI_RESTART                "restart"                   // required
0159 #define PMIX_CLI_CHKPT                  "checkpoint"                // required
0160 #define PMIX_CLI_TARGETS                "targets"                   // required
0161 #define PMIX_CLI_TERMINATE              "terminate"                 // none
0162 #define PMIX_CLI_PSET_NAME              "pset"                      // required
0163 #define PMIX_CLI_FWD_ENVAR              "x"                         // required
0164 #define PMIX_CLI_SET_ENVAR              "set-env"                   // required
0165 #define PMIX_CLI_PREPEND_ENVAR          "prepend-env"               // required
0166 #define PMIX_CLI_APPEND_ENVAR           "append-env"                // required
0167 #define PMIX_CLI_UNSET_ENVAR            "unset-env"                 // required
0168 
0169 // Info options
0170 #define PMIX_CLI_INFO_ALL               "all"                       // none
0171 #define PMIX_CLI_INFO_ARCH              "arch"                      // none
0172 #define PMIX_CLI_INFO_CONFIG            "config"                    // none
0173 #define PMIX_CLI_INFO_HOSTNAME          "hostname"                  // none
0174 #define PMIX_CLI_INFO_INTERNAL          "internal"                  // none
0175 #define PMIX_CLI_INFO_PARAM             "param"                     // required
0176 #define PMIX_CLI_INFO_PARAMS            "params"                    // required
0177 #define PMIX_CLI_INFO_PATH              "path"                      // required
0178 #define PMIX_CLI_INFO_VERSION           "show-version"              // required
0179 #define PMIX_CLI_INFO_TYPES             "type"                      // required
0180 #define PMIX_CLI_INFO_COLOR             "color"                     // required
0181 #define PMIX_CLI_INFO_SHOW_FAILED       "show-failed"               //none
0182 #define PMIX_CLI_INFO_SELECTED_ONLY     "selected-only"             // none
0183 
0184 
0185 typedef void (*pmix_cmd_line_store_fn_t)(const char *name, const char *option,
0186                                          pmix_cli_result_t *results);
0187 
0188 PMIX_EXPORT int pmix_cmd_line_parse(char **argv, char *shorts,
0189                                     struct option myoptions[],
0190                                     pmix_cmd_line_store_fn_t storefn,
0191                                     pmix_cli_result_t *results,
0192                                     char *helpfile);
0193 
0194 static inline pmix_cli_item_t* pmix_cmd_line_get_param(pmix_cli_result_t *results,
0195                                                        const char *key)
0196 {
0197     pmix_cli_item_t *opt;
0198 
0199     PMIX_LIST_FOREACH(opt, &results->instances, pmix_cli_item_t) {
0200         if (0 == strcmp(opt->key, key)) {
0201             return opt;
0202         }
0203     }
0204     return NULL;
0205 }
0206 
0207 static inline bool pmix_cmd_line_is_taken(pmix_cli_result_t *results,
0208                                           const char *key)
0209 {
0210     if (NULL == pmix_cmd_line_get_param(results, key)) {
0211         return false;
0212     }
0213     return true;
0214 }
0215 
0216 static inline int pmix_cmd_line_get_ninsts(pmix_cli_result_t *results,
0217                                            const char *key)
0218 {
0219     pmix_cli_item_t *opt;
0220 
0221     opt = pmix_cmd_line_get_param(results, key);
0222     if (NULL == opt) {
0223         return 0;
0224     }
0225     return PMIx_Argv_count(opt->values);
0226 }
0227 
0228 static inline char* pmix_cmd_line_get_nth_instance(pmix_cli_result_t *results,
0229                                                    const char *key, int idx)
0230 {
0231     pmix_cli_item_t *opt;
0232     int ninst;
0233 
0234     opt = pmix_cmd_line_get_param(results, key);
0235     if (NULL == opt) {
0236         return NULL;
0237     }
0238     ninst = PMIx_Argv_count(opt->values);
0239     if (ninst < idx) {
0240         return NULL;
0241     }
0242     return opt->values[idx];
0243 }
0244 
0245 /* USAGE:
0246  *  param "a" is the input command line string
0247  *  param "b" is the defined CLI option
0248  */
0249 static inline bool pmix_check_cli_option(char *ain, char *bin)
0250 {
0251     size_t len1, len2, len, n;
0252     char *a, *b, *p;
0253     char **asplit, **bsplit;
0254     int match, acnt, bcnt;
0255 
0256     // protect the input
0257     a = strdup(ain);
0258     b = strdup(bin);
0259 
0260     /* if there is an '=' in the option, then we only
0261      * check up to that position in the option as
0262      * everything past it is the value the option
0263      * is being assigned */
0264     p = strchr(a, '=');
0265     if (NULL != p) {
0266         *p = '\0';
0267     }
0268     p = strchr(b, '=');
0269     if (NULL != p) {
0270         *p = '\0';
0271     }
0272 
0273     /* if there exists a '-' in either argument,
0274      * then we are dealing with a multi-word
0275      * option. Parse those by checking each
0276      * word segment individually for a match
0277      * so the user doesn't have to spell it all
0278      * out unless necessary. We consider it a
0279      * valid match if all provided segments match
0280      * that of the target option */
0281     if (NULL != strchr(b, '-') ||
0282         NULL != strchr(a, '-')) {
0283         asplit = PMIx_Argv_split(a, '-');
0284         bsplit = PMIx_Argv_split(b, '-');
0285         acnt = PMIx_Argv_count(asplit);
0286         bcnt = PMIx_Argv_count(bsplit);
0287         if (acnt > bcnt) {
0288             PMIx_Argv_free(asplit);
0289             PMIx_Argv_free(bsplit);
0290             free(a);
0291             free(b);
0292             return false;
0293         }
0294         match = 0;
0295         for (n=0; NULL != asplit[n] && NULL != bsplit[n]; n++) {
0296             len1 = strlen(asplit[n]);
0297             len2 = strlen(bsplit[n]);
0298             len = len1 < len2 ? len1 : len2;
0299             if (0 == strncasecmp(asplit[n], bsplit[n], len)) {
0300                 ++match;
0301             } else {
0302                 PMIx_Argv_free(asplit);
0303                 PMIx_Argv_free(bsplit);
0304                 free(a);
0305                 free(b);
0306                 return false;
0307             }
0308         }
0309         PMIx_Argv_free(asplit);
0310         PMIx_Argv_free(bsplit);
0311         if (match == acnt) {
0312             /* all provided segments match */
0313             free(a);
0314             free(b);
0315             return true;
0316         }
0317         free(a);
0318         free(b);
0319         return false;
0320     }
0321 
0322     /* if this is not a multi-word option, we just
0323      * check the strings */
0324     len1 = strlen(a);
0325     len2 = strlen(b);
0326     len = (len1 < len2) ? len1 : len2;
0327     if (0 == strncasecmp(a, b, len)) {
0328         free(a);
0329         free(b);
0330         return true;
0331     }
0332 
0333     free(a);
0334     free(b);
0335     return false;
0336 }
0337 
0338 #define PMIX_CHECK_CLI_OPTION(a, b) \
0339     pmix_check_cli_option(a, b)
0340 
0341 static inline unsigned int pmix_convert_string_to_time(const char *t)
0342 {
0343     char **tmp = PMIx_Argv_split(t, ':');
0344     int sz = PMIx_Argv_count(tmp);
0345     unsigned int tm;
0346 
0347     /* work upwards from the bottom, where the
0348      * bottom represents seconds, then minutes,
0349      * then hours, and then days */
0350     tm = strtoul(tmp[sz-1], NULL, 10);
0351     if (0 <= (sz-2) && NULL != tmp[sz-2]) {
0352         tm += 60 * strtoul(tmp[sz-2], NULL, 10);
0353     }
0354     if (0 <= (sz-3) && NULL != tmp[sz-3]) {
0355         tm += 60 * 60 * strtoul(tmp[sz-3], NULL, 10);
0356     }
0357     if (0 <= (sz-4) && NULL != tmp[sz-4]) {
0358         tm += 24 * 60 * 60 * strtoul(tmp[sz-4], NULL, 10);
0359     }
0360     PMIx_Argv_free(tmp);
0361     return tm;
0362 }
0363 
0364 #define PMIX_CONVERT_TIME(s)    \
0365     pmix_convert_string_to_time(s)
0366 
0367 
0368 #define PMIX_CLI_DEBUG_LIST(r)  \
0369 do {                                                                    \
0370     pmix_cli_item_t *_c;                                                \
0371     char *_tail;                                                        \
0372     pmix_output(0, "\n[%s:%s:%d]", __FILE__, __func__, __LINE__);       \
0373     PMIX_LIST_FOREACH(_c, &(r)->instances, pmix_cli_item_t) {           \
0374         pmix_output(0, "KEY: %s", _c->key);                             \
0375         if (NULL != _c->values) {                                       \
0376             for (int _n=0; NULL != _c->values[_n]; _n++) {              \
0377                 pmix_output(0, "    VAL[%d]: %s", _n, _c->values[_n]);  \
0378             }                                                           \
0379         }                                                               \
0380     }                                                                   \
0381     _tail = PMIx_Argv_join((r)->tail, ' ');                             \
0382     pmix_output(0, "TAIL: %s", _tail);                                  \
0383     free(_tail);                                                        \
0384     pmix_output(0, "\n");                                               \
0385 } while(0)
0386 
0387 #define PMIX_CLI_REMOVE_DEPRECATED(r, o)    \
0388 do {                                                        \
0389     pmix_list_remove_item(&(r)->instances, &(o)->super);    \
0390     PMIX_RELEASE(o);                                        \
0391 } while(0)
0392 END_C_DECLS
0393 
0394 #endif /* PMIX_CMD_LINE_H */