Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:47:27

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-2023 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 
0112 // Tool connection options
0113 #define PMIX_CLI_SYS_SERVER_FIRST       "system-server-first"       // none
0114 #define PMIX_CLI_SYSTEM_SERVER          "system-server"             // none
0115 #define PMIX_CLI_SYS_SERVER_ONLY        "system-server-only"        // none
0116 #define PMIX_CLI_DO_NOT_CONNECT         "do-not-connect"            // none
0117 #define PMIX_CLI_WAIT_TO_CONNECT        "wait-to-connect"           // required
0118 #define PMIX_CLI_NUM_CONNECT_RETRIES    "num-connect-retries"       // required
0119 #define PMIX_CLI_PID                    "pid"                       // required
0120 #define PMIX_CLI_NAMESPACE              "namespace"                 // required
0121 #define PMIX_CLI_NSPACE                 "nspace"                    // required
0122 #define PMIX_CLI_URI                    "uri"                       // required
0123 #define PMIX_CLI_TIMEOUT                "timeout"                   // required
0124 #define PMIX_CLI_TMPDIR                 "tmpdir"                    // required
0125 #define PMIX_CLI_CONNECTION_ORDER       "connect-order"             // required
0126 #define PMIX_CLI_SYS_CONTROLLER         "system-controller"         // none
0127 
0128 // Allocation request options
0129 #define PMIX_CLI_REQ_ID                 "request-id"                // required
0130 #define PMIX_CLI_QUEUE                  "queue"                     // required, short is 'q'
0131 #define PMIX_CLI_RESOURCES              "resources"                 // required
0132 #define PMIX_CLI_NODES                  "nodes"                     // required, short is 'N'
0133 #define PMIX_CLI_IMAGE                  "image"                     // required, short is 'i'
0134 #define PMIX_CLI_EXCLUDE                "exclude"                   // required, short is 'x'
0135 #define PMIX_CLI_WAIT_ALL_NODES         "wait-all-nodes"            // none
0136 #define PMIX_CLI_NODELIST               "nodelist"                  // required, short is 'w'
0137 #define PMIX_CLI_UID                    "uid"                       // required
0138 #define PMIX_CLI_GID                    "gid"                       // required
0139 #define PMIX_CLI_TIME                   "time"                      // required, short is 't'
0140 #define PMIX_CLI_SIGNAL                 "signal"                    // required
0141 #define PMIX_CLI_SHARE                  "share"                     // none
0142 #define PMIX_CLI_EXTEND                 "extend"                    // none
0143 #define PMIX_CLI_SHRINK                 "shrink"                    // none
0144 #define PMIX_CLI_NO_SHELL               "no-shell"                  // none
0145 #define PMIX_CLI_BEGIN                  "begin"                     // required
0146 #define PMIX_CLI_IMMEDIATE              "immediate"                 // optional, short is 'I'
0147 #define PMIX_CLI_DEPENDENCY             "dependency"                // required, short is 'd'
0148 #define PMIX_CLI_DO_NOT_WAIT            "do-not-wait"               // none
0149 
0150 // Job control options
0151 #define PMIX_CLI_PAUSE                  "pause"                     // none
0152 #define PMIX_CLI_RESUME                 "resume"                    // none
0153 #define PMIX_CLI_CANCEL                 "cancel"                    // required
0154 #define PMIX_CLI_KILL                   "kill"                      // none
0155 #define PMIX_CLI_RESTART                "restart"                   // required
0156 #define PMIX_CLI_CHKPT                  "checkpoint"                // required
0157 #define PMIX_CLI_TARGETS                "targets"                   // required
0158 #define PMIX_CLI_TERMINATE              "terminate"                 // none
0159 #define PMIX_CLI_PSET_NAME              "pset"                      // required
0160 
0161 typedef void (*pmix_cmd_line_store_fn_t)(const char *name, const char *option,
0162                                          pmix_cli_result_t *results);
0163 
0164 PMIX_EXPORT int pmix_cmd_line_parse(char **argv, char *shorts,
0165                                     struct option myoptions[],
0166                                     pmix_cmd_line_store_fn_t storefn,
0167                                     pmix_cli_result_t *results,
0168                                     char *helpfile);
0169 
0170 static inline pmix_cli_item_t* pmix_cmd_line_get_param(pmix_cli_result_t *results,
0171                                                        const char *key)
0172 {
0173     pmix_cli_item_t *opt;
0174 
0175     PMIX_LIST_FOREACH(opt, &results->instances, pmix_cli_item_t) {
0176         if (0 == strcmp(opt->key, key)) {
0177             return opt;
0178         }
0179     }
0180     return NULL;
0181 }
0182 
0183 static inline bool pmix_cmd_line_is_taken(pmix_cli_result_t *results,
0184                                           const char *key)
0185 {
0186     if (NULL == pmix_cmd_line_get_param(results, key)) {
0187         return false;
0188     }
0189     return true;
0190 }
0191 
0192 static inline int pmix_cmd_line_get_ninsts(pmix_cli_result_t *results,
0193                                            const char *key)
0194 {
0195     pmix_cli_item_t *opt;
0196 
0197     opt = pmix_cmd_line_get_param(results, key);
0198     if (NULL == opt) {
0199         return 0;
0200     }
0201     return PMIx_Argv_count(opt->values);
0202 }
0203 
0204 static inline char* pmix_cmd_line_get_nth_instance(pmix_cli_result_t *results,
0205                                                    const char *key, int idx)
0206 {
0207     pmix_cli_item_t *opt;
0208     int ninst;
0209 
0210     opt = pmix_cmd_line_get_param(results, key);
0211     if (NULL == opt) {
0212         return NULL;
0213     }
0214     ninst = PMIx_Argv_count(opt->values);
0215     if (ninst < idx) {
0216         return NULL;
0217     }
0218     return opt->values[idx];
0219 }
0220 
0221 /* USAGE:
0222  *  param "a" is the input command line string
0223  *  param "b" is the defined CLI option
0224  */
0225 static inline bool pmix_check_cli_option(char *a, char *b)
0226 {
0227     size_t len1, len2, len, n;
0228     char **asplit, **bsplit;
0229     int match;
0230 
0231     /* if there exists a '-' in either argument,
0232      * then we are dealing with a multi-word
0233      * option. Parse those by checking each
0234      * word segment individually for a match
0235      * so the user doesn't have to spell it all
0236      * out unless necessary. We consider it a
0237      * valid match if all provided segments match
0238      * that of the target option */
0239     if (NULL != strchr(b, '-') ||
0240         NULL != strchr(a, '-')) {
0241         asplit = PMIx_Argv_split(a, '-');
0242         bsplit = PMIx_Argv_split(b, '-');
0243         if (PMIx_Argv_count(asplit) > PMIx_Argv_count(bsplit)) {
0244             PMIx_Argv_free(asplit);
0245             PMIx_Argv_free(bsplit);
0246             return false;
0247         }
0248         match = 0;
0249         for (n=0; NULL != asplit[n] && NULL != bsplit[n]; n++) {
0250             len1 = strlen(asplit[n]);
0251             len2 = strlen(bsplit[n]);
0252             len = len1 < len2 ? len1 : len2;
0253             if (0 == strncasecmp(asplit[n], bsplit[n], len)) {
0254                 ++match;
0255             } else {
0256                 PMIx_Argv_free(asplit);
0257                 PMIx_Argv_free(bsplit);
0258                 return false;
0259             }
0260         }
0261         PMIx_Argv_free(asplit);
0262         PMIx_Argv_free(bsplit);
0263         if (match == PMIx_Argv_count(asplit)) {
0264             /* all provided segments match */
0265             return true;
0266         }
0267         return false;
0268     }
0269 
0270     /* if this is not a multi-word option, we just
0271      * check the strings */
0272     len1 = strlen(a);
0273     len2 = strlen(b);
0274     len = (len1 < len2) ? len1 : len2;
0275     if (0 == strncasecmp(a, b, len)) {
0276         return true;
0277     }
0278 
0279     return false;
0280 }
0281 
0282 #define PMIX_CHECK_CLI_OPTION(a, b) \
0283     pmix_check_cli_option(a, b)
0284 
0285 static inline unsigned int pmix_convert_string_to_time(const char *t)
0286 {
0287     char **tmp = PMIx_Argv_split(t, ':');
0288     int sz = PMIx_Argv_count(tmp);
0289     unsigned int tm;
0290 
0291     /* work upwards from the bottom, where the
0292      * bottom represents seconds, then minutes,
0293      * then hours, and then days */
0294     tm = strtoul(tmp[sz-1], NULL, 10);
0295     if (0 <= (sz-2) && NULL != tmp[sz-2]) {
0296         tm += 60 * strtoul(tmp[sz-2], NULL, 10);
0297     }
0298     if (0 <= (sz-3) && NULL != tmp[sz-3]) {
0299         tm += 60 * 60 * strtoul(tmp[sz-3], NULL, 10);
0300     }
0301     if (0 <= (sz-4) && NULL != tmp[sz-4]) {
0302         tm += 24 * 60 * 60 * strtoul(tmp[sz-4], NULL, 10);
0303     }
0304     PMIx_Argv_free(tmp);
0305     return tm;
0306 }
0307 
0308 #define PMIX_CONVERT_TIME(s)    \
0309     pmix_convert_string_to_time(s)
0310 
0311 
0312 #define PMIX_CLI_DEBUG_LIST(r)  \
0313 do {                                                                    \
0314     pmix_cli_item_t *_c;                                                \
0315     char *_tail;                                                        \
0316     pmix_output(0, "\n[%s:%s:%d]", __FILE__, __func__, __LINE__);       \
0317     PMIX_LIST_FOREACH(_c, &(r)->instances, pmix_cli_item_t) {           \
0318         pmix_output(0, "KEY: %s", _c->key);                             \
0319         if (NULL != _c->values) {                                       \
0320             for (int _n=0; NULL != _c->values[_n]; _n++) {              \
0321                 pmix_output(0, "    VAL[%d]: %s", _n, _c->values[_n]);  \
0322             }                                                           \
0323         }                                                               \
0324     }                                                                   \
0325     _tail = PMIx_Argv_join((r)->tail, ' ');                             \
0326     pmix_output(0, "TAIL: %s", _tail);                                  \
0327     free(_tail);                                                        \
0328     pmix_output(0, "\n");                                               \
0329 } while(0)
0330 
0331 #define PMIX_CLI_REMOVE_DEPRECATED(r, o)    \
0332 do {                                                        \
0333     pmix_list_remove_item(&(r)->instances, &(o)->super);    \
0334     PMIX_RELEASE(o);                                        \
0335 } while(0)
0336 END_C_DECLS
0337 
0338 #endif /* PMIX_CMD_LINE_H */