root/opal/util/info.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. opal_info_dup
  2. opal_info_get_nolock
  3. opal_info_set_nolock
  4. opal_info_dup_mode
  5. opal_info_dup_mpistandard
  6. opal_info_set
  7. opal_info_set_value_enum
  8. opal_info_get
  9. opal_info_get_value_enum
  10. opal_info_get_bool
  11. opal_str_to_bool
  12. opal_info_delete
  13. opal_info_get_valuelen
  14. opal_info_get_nthkey
  15. info_constructor
  16. info_destructor
  17. info_entry_constructor
  18. info_entry_destructor
  19. info_find_key
  20. opal_info_value_to_int
  21. opal_info_value_to_bool

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2007 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) 2007-2018 Cisco Systems, Inc.  All rights reserved
  14  * Copyright (c) 2009      Sun Microsystems, Inc.  All rights reserved.
  15  * Copyright (c) 2012-2017 Los Alamos National Security, LLC. All rights
  16  *                         reserved.
  17  * Copyright (c) 2015-2017 Research Organization for Information Science
  18  *                         and Technology (RIST). All rights reserved.
  19  * Copyright (c) 2016-2018 IBM Corporation. All rights reserved.
  20  * Copyright (c) 2017      Intel, Inc. All rights reserved.
  21  * $COPYRIGHT$
  22  *
  23  * Additional copyrights may follow
  24  *
  25  * $HEADER$
  26  */
  27 
  28 #include <string.h>
  29 #include <errno.h>
  30 #include <stdlib.h>
  31 #ifdef HAVE_UNISTD_H
  32 #include <unistd.h>
  33 #endif
  34 #include <limits.h>
  35 #include <ctype.h>
  36 #ifdef HAVE_SYS_UTSNAME_H
  37 #include <sys/utsname.h>
  38 #endif
  39 #include <assert.h>
  40 
  41 #include "opal/util/argv.h"
  42 #include "opal/util/opal_getcwd.h"
  43 #include "opal/util/output.h"
  44 #include "opal/util/string_copy.h"
  45 #include "opal/util/info.h"
  46 
  47 /*
  48  * Local functions
  49  */
  50 static void info_constructor(opal_info_t *info);
  51 static void info_destructor(opal_info_t *info);
  52 static void info_entry_constructor(opal_info_entry_t *entry);
  53 static void info_entry_destructor(opal_info_entry_t *entry);
  54 static opal_info_entry_t *info_find_key (opal_info_t *info, const char *key);
  55 
  56 
  57 /*
  58  * opal_info_t classes
  59  */
  60 OBJ_CLASS_INSTANCE(opal_info_t,
  61                    opal_list_t,
  62                    info_constructor,
  63                    info_destructor);
  64 
  65 /*
  66  * opal_info_entry_t classes
  67  */
  68 OBJ_CLASS_INSTANCE(opal_info_entry_t,
  69                    opal_list_item_t,
  70                    info_entry_constructor,
  71                    info_entry_destructor);
  72 
  73 
  74 
  75 /*
  76  * Duplicate an info
  77  */
  78 int opal_info_dup (opal_info_t *info, opal_info_t **newinfo)
  79 {
  80     int err;
  81     opal_info_entry_t *iterator;
  82 
  83     OPAL_THREAD_LOCK(info->i_lock);
  84     OPAL_LIST_FOREACH(iterator, &info->super, opal_info_entry_t) {
  85         err = opal_info_set(*newinfo, iterator->ie_key, iterator->ie_value);
  86         if (OPAL_SUCCESS != err) {
  87             OPAL_THREAD_UNLOCK(info->i_lock);
  88             return err;
  89         }
  90      }
  91     OPAL_THREAD_UNLOCK(info->i_lock);
  92     return OPAL_SUCCESS;
  93 }
  94 
  95 static void opal_info_get_nolock (opal_info_t *info, const char *key, int valuelen,
  96                                  char *value, int *flag)
  97 {
  98     opal_info_entry_t *search;
  99 
 100     search = info_find_key (info, key);
 101     if (NULL == search){
 102         *flag = 0;
 103     } else if (value && valuelen) {
 104         /*
 105          * We have found the element, so we can return the value
 106          * Set the flag and value
 107          */
 108         *flag = 1;
 109         // Note: we copy exactly (valuelen) characters, because that's
 110         // what the caller asked for.  Don't use opal_string_copy()
 111         // here, because that will guarantee to \0-terminate what is
 112         // copied (i.e., potentially copy (valuelen-1) chars and then
 113         // an additional \0).  Instead: copy over exactly (valuelen)
 114         // characters, and if that's not \0-terminated, then so be it.
 115         memcpy(value, search->ie_value, valuelen);
 116     }
 117 }
 118 
 119 static int opal_info_set_nolock (opal_info_t *info, const char *key, const char *value)
 120 {
 121     char *new_value;
 122     opal_info_entry_t *new_info;
 123     opal_info_entry_t *old_info;
 124 
 125     new_value = strdup(value);
 126     if (NULL == new_value) {
 127       return OPAL_ERR_OUT_OF_RESOURCE;
 128     }
 129 
 130     old_info = info_find_key (info, key);
 131     if (NULL != old_info) {
 132         /*
 133          * key already exists. remove the value associated with it
 134          */
 135         free(old_info->ie_value);
 136         old_info->ie_value = new_value;
 137     } else {
 138         new_info = OBJ_NEW(opal_info_entry_t);
 139         if (NULL == new_info) {
 140             free(new_value);
 141             OPAL_THREAD_UNLOCK(info->i_lock);
 142             return OPAL_ERR_OUT_OF_RESOURCE;
 143         }
 144         opal_string_copy (new_info->ie_key, key, OPAL_MAX_INFO_KEY);
 145         new_info->ie_value = new_value;
 146         opal_list_append (&(info->super), (opal_list_item_t *) new_info);
 147     }
 148     return OPAL_SUCCESS;
 149 }
 150 /*
 151  * An object's info can be set, but those settings can be modified by
 152  * system callbacks. When those callbacks happen, we save a "__IN_<key>"/"val"
 153  * copy of changed or erased values.
 154  *
 155  * extra options for how to dup:
 156  *   include_system_extras (default 1)
 157  *   omit_ignored          (default 1)
 158  *   show_modifications    (default 0)
 159  */
 160 static
 161 int opal_info_dup_mode (opal_info_t *info, opal_info_t **newinfo,
 162     int include_system_extras,  // (k/v with no corresponding __IN_k)
 163     int omit_ignored,           // (__IN_k with no k/v)
 164     int show_modifications)     // (pick v from k/v or __IN_k/v)
 165 {
 166     int err, flag;
 167     opal_info_entry_t *iterator;
 168     char savedkey[OPAL_MAX_INFO_KEY + 1]; // iterator->ie_key has this as its size
 169     char savedval[OPAL_MAX_INFO_VAL];
 170     char *valptr, *pkey;
 171     int is_IN_key;
 172     int exists_IN_key, exists_reg_key;
 173 
 174     OPAL_THREAD_LOCK(info->i_lock);
 175     OPAL_LIST_FOREACH(iterator, &info->super, opal_info_entry_t) {
 176 // If we see an __IN_<key> key but no <key>, decide what to do based on mode.
 177 // If we see an __IN_<key> and a <key>, skip since it'll be handled when
 178 // we process <key>.
 179          is_IN_key = 0;
 180          exists_IN_key = 0;
 181          exists_reg_key = 0;
 182          pkey = iterator->ie_key;
 183          if (0 == strncmp(iterator->ie_key, OPAL_INFO_SAVE_PREFIX,
 184              strlen(OPAL_INFO_SAVE_PREFIX)))
 185         {
 186              pkey += strlen(OPAL_INFO_SAVE_PREFIX);
 187 
 188              is_IN_key = 1;
 189              exists_IN_key = 1;
 190              opal_info_get_nolock (info, pkey, 0, NULL, &flag);
 191              if (flag) {
 192                  exists_reg_key = 1;
 193              }
 194          } else {
 195              is_IN_key = 0;
 196              exists_reg_key = 1;
 197 
 198 // see if there is an __IN_<key> for the current <key>
 199              if (strlen(OPAL_INFO_SAVE_PREFIX) + strlen(pkey) < OPAL_MAX_INFO_KEY) {
 200                  snprintf(savedkey, OPAL_MAX_INFO_KEY+1,
 201                      OPAL_INFO_SAVE_PREFIX "%s", pkey);
 202 // (the prefix macro is a string, so the unreadable part above is a string concatenation)
 203                  opal_info_get_nolock (info, savedkey, OPAL_MAX_INFO_VAL,
 204                                        savedval, &flag);
 205              } else {
 206                  flag = 0;
 207              }
 208              if (flag) {
 209                  exists_IN_key = 1;
 210              }
 211          }
 212 
 213          if (is_IN_key) {
 214              if (exists_reg_key) {
 215 // we're processing __IN_<key> and there exists a <key> so we'll handle it then
 216                  continue;
 217              } else {
 218 // we're processing __IN_<key> and no <key> exists
 219 // this would mean <key> was set by the user but ignored by the system
 220 // so base our behavior on the omit_ignored
 221                  if (!omit_ignored) {
 222                      err = opal_info_set_nolock(*newinfo, pkey, iterator->ie_value);
 223                      if (OPAL_SUCCESS != err) {
 224                          OPAL_THREAD_UNLOCK(info->i_lock);
 225                          return err;
 226                      }
 227                  }
 228              }
 229          } else {
 230              valptr = 0;
 231              if (!exists_IN_key) {
 232 // we're processing <key> and no __IN_<key> <key> exists
 233 // this would mean it's a system setting, not something that came from the user
 234                  if (include_system_extras) {
 235                      valptr = iterator->ie_value;
 236                  }
 237              } else {
 238 // we're processing <key> and __IN_<key> also exists
 239 // pick which value to use
 240                  if (!show_modifications) {
 241                      valptr = savedval;
 242                  } else {
 243                      valptr = iterator->ie_value;
 244                  }
 245              }
 246              if (valptr) {
 247                  err = opal_info_set_nolock(*newinfo, pkey, valptr);
 248                  if (OPAL_SUCCESS != err) {
 249                      OPAL_THREAD_UNLOCK(info->i_lock);
 250                      return err;
 251                  }
 252              }
 253          }
 254      }
 255      OPAL_THREAD_UNLOCK(info->i_lock);
 256      return OPAL_SUCCESS;
 257 }
 258 
 259 /*
 260  * Implement opal_info_dup_mpistandard by using whatever mode
 261  * settings represent our interpretation of the standard
 262  */
 263 int opal_info_dup_mpistandard (opal_info_t *info, opal_info_t **newinfo)
 264 {
 265     return opal_info_dup_mode (info, newinfo, 1, 1, 0);
 266 }
 267 
 268 /*
 269  * Set a value on the info
 270  */
 271 int opal_info_set (opal_info_t *info, const char *key, const char *value)
 272 {
 273     int ret;
 274 
 275     OPAL_THREAD_LOCK(info->i_lock);
 276     ret = opal_info_set_nolock(info, key, value);
 277     OPAL_THREAD_UNLOCK(info->i_lock);
 278     return ret;
 279 }
 280 
 281 
 282 int opal_info_set_value_enum (opal_info_t *info, const char *key, int value,
 283                               mca_base_var_enum_t *var_enum)
 284 {
 285     char *string_value;
 286     int ret;
 287 
 288     ret = var_enum->string_from_value (var_enum, value, &string_value);
 289     if (OPAL_SUCCESS != ret) {
 290         return ret;
 291     }
 292 
 293     return opal_info_set (info, key, string_value);
 294 }
 295 
 296 
 297 /*
 298  * Get a value from an info
 299  */
 300 int opal_info_get (opal_info_t *info, const char *key, int valuelen,
 301                    char *value, int *flag)
 302 {
 303     OPAL_THREAD_LOCK(info->i_lock);
 304     opal_info_get_nolock(info, key, valuelen, value, flag);
 305     OPAL_THREAD_UNLOCK(info->i_lock);
 306     return OPAL_SUCCESS;
 307 }
 308 
 309 int opal_info_get_value_enum (opal_info_t *info, const char *key, int *value,
 310                               int default_value, mca_base_var_enum_t *var_enum,
 311                               int *flag)
 312 {
 313     opal_info_entry_t *search;
 314     int ret;
 315 
 316     *value = default_value;
 317 
 318     OPAL_THREAD_LOCK(info->i_lock);
 319     search = info_find_key (info, key);
 320     if (NULL == search){
 321         OPAL_THREAD_UNLOCK(info->i_lock);
 322         *flag = 0;
 323         return OPAL_SUCCESS;
 324     }
 325 
 326     /* we found a mathing key. pass the string value to the enumerator and
 327      * return */
 328     *flag = 1;
 329 
 330     ret = var_enum->value_from_string (var_enum, search->ie_value, value);
 331     OPAL_THREAD_UNLOCK(info->i_lock);
 332 
 333     return ret;
 334 }
 335 
 336 
 337 /*
 338  * Similar to opal_info_get(), but cast the result into a boolean
 339  * using some well-defined rules.
 340  */
 341 int opal_info_get_bool(opal_info_t *info, char *key, bool *value, int *flag)
 342 {
 343     char str[256];
 344 
 345     str[sizeof(str) - 1] = '\0';
 346     opal_info_get(info, key, sizeof(str) - 1, str, flag);
 347     if (*flag) {
 348         *value = opal_str_to_bool(str);
 349     }
 350 
 351     return OPAL_SUCCESS;
 352 }
 353 
 354 
 355 bool
 356 opal_str_to_bool(char *str)
 357 {
 358     bool result = false;
 359     char *ptr;
 360 
 361     /* Trim whitespace */
 362     ptr = str + sizeof(str) - 1;
 363     while (ptr >= str && isspace(*ptr)) {
 364         *ptr = '\0';
 365         --ptr;
 366     }
 367     ptr = str;
 368     while (ptr < str + sizeof(str) - 1 && *ptr != '\0' &&
 369            isspace(*ptr)) {
 370         ++ptr;
 371     }
 372     if ('\0' != *ptr) {
 373         if (isdigit(*ptr)) {
 374             result = (bool) atoi(ptr);
 375         } else if (0 == strcasecmp(ptr, "yes") ||
 376                    0 == strcasecmp(ptr, "true")) {
 377             result = true;
 378         } else if (0 != strcasecmp(ptr, "no") &&
 379                    0 != strcasecmp(ptr, "false")) {
 380             /* RHC unrecognized value -- print a warning? */
 381         }
 382     }
 383     return result;
 384 }
 385 
 386 /*
 387  * Delete a key from an info
 388  */
 389 int opal_info_delete(opal_info_t *info, const char *key)
 390 {
 391     opal_info_entry_t *search;
 392 
 393     OPAL_THREAD_LOCK(info->i_lock);
 394     search = info_find_key (info, key);
 395     if (NULL == search){
 396          OPAL_THREAD_UNLOCK(info->i_lock);
 397          return OPAL_ERR_NOT_FOUND;
 398     } else {
 399          /*
 400           * An entry with this key value was found. Remove the item
 401           * and free the memory allocated to it.
 402           * As this key *must* be available, we do not check for errors.
 403           */
 404           opal_list_remove_item (&(info->super),
 405                                  (opal_list_item_t *)search);
 406           OBJ_RELEASE(search);
 407     }
 408     OPAL_THREAD_UNLOCK(info->i_lock);
 409     return OPAL_SUCCESS;
 410 }
 411 
 412 
 413 /*
 414  * Return the length of a value
 415  */
 416 int opal_info_get_valuelen (opal_info_t *info, const char *key, int *valuelen,
 417                             int *flag)
 418 {
 419     opal_info_entry_t *search;
 420 
 421     OPAL_THREAD_LOCK(info->i_lock);
 422     search = info_find_key (info, key);
 423     if (NULL == search){
 424         *flag = 0;
 425     } else {
 426         /*
 427          * We have found the element, so we can return the value
 428          * Set the flag, value_length and value
 429          */
 430          *flag = 1;
 431          *valuelen = strlen(search->ie_value);
 432     }
 433     OPAL_THREAD_UNLOCK(info->i_lock);
 434     return OPAL_SUCCESS;
 435 }
 436 
 437 
 438 /*
 439  * Get the nth key
 440  */
 441 int opal_info_get_nthkey (opal_info_t *info, int n, char *key)
 442 {
 443     opal_info_entry_t *iterator;
 444 
 445     /*
 446      * Iterate over and over till we get to the nth key
 447      */
 448     OPAL_THREAD_LOCK(info->i_lock);
 449     for (iterator = (opal_info_entry_t *)opal_list_get_first(&(info->super));
 450          n > 0;
 451          --n) {
 452          iterator = (opal_info_entry_t *)opal_list_get_next(iterator);
 453          if (opal_list_get_end(&(info->super)) ==
 454              (opal_list_item_t *) iterator) {
 455              OPAL_THREAD_UNLOCK(info->i_lock);
 456              return OPAL_ERR_BAD_PARAM;
 457          }
 458     }
 459     /*
 460      * iterator is of the type opal_list_item_t. We have to
 461      * cast it to opal_info_entry_t before we can use it to
 462      * access the value
 463      */
 464     opal_string_copy(key, iterator->ie_key, OPAL_MAX_INFO_KEY);
 465     OPAL_THREAD_UNLOCK(info->i_lock);
 466     return OPAL_SUCCESS;
 467 }
 468 
 469 
 470 
 471 /*
 472  * This function is invoked when OBJ_NEW() is called. Here, we add this
 473  * info pointer to the table and then store its index as the handle
 474  */
 475 static void info_constructor(opal_info_t *info)
 476 {
 477     info->i_lock = OBJ_NEW(opal_mutex_t);
 478 }
 479 
 480 /*
 481  * This function is called during OBJ_DESTRUCT of "info". When this
 482  * done, we need to remove the entry from the opal fortran to C
 483  * translation table
 484  */
 485 static void info_destructor(opal_info_t *info)
 486 {
 487     opal_list_item_t *item;
 488     opal_info_entry_t *iterator;
 489 
 490     /* Remove every key in the list */
 491 
 492     for (item = opal_list_remove_first(&(info->super));
 493          NULL != item;
 494          item = opal_list_remove_first(&(info->super))) {
 495         iterator = (opal_info_entry_t *) item;
 496         OBJ_RELEASE(iterator);
 497     }
 498 
 499     /* Release the lock */
 500 
 501     OBJ_RELEASE(info->i_lock);
 502 }
 503 
 504 
 505 /*
 506  * opal_info_entry_t interface functions
 507  */
 508 static void info_entry_constructor(opal_info_entry_t *entry)
 509 {
 510     memset(entry->ie_key, 0, sizeof(entry->ie_key));
 511     entry->ie_key[OPAL_MAX_INFO_KEY] = 0;
 512 }
 513 
 514 
 515 static void info_entry_destructor(opal_info_entry_t *entry)
 516 {
 517     if (NULL != entry->ie_value) {
 518         free(entry->ie_value);
 519     }
 520 }
 521 
 522 
 523 /*
 524  * Find a key
 525  *
 526  * Do NOT thread lock in here -- the calling function is responsible
 527  * for that.
 528  */
 529 static opal_info_entry_t *info_find_key (opal_info_t *info, const char *key)
 530 {
 531     opal_info_entry_t *iterator;
 532 
 533     /* No thread locking in here! */
 534 
 535     /* Iterate over all the entries. If the key is found, then
 536      * return immediately. Else, the loop will fall of the edge
 537      * and NULL is returned
 538      */
 539     OPAL_LIST_FOREACH(iterator, &info->super, opal_info_entry_t) {
 540         if (0 == strcmp(key, iterator->ie_key)) {
 541             return iterator;
 542         }
 543     }
 544     return NULL;
 545 }
 546 
 547 
 548 int
 549 opal_info_value_to_int(char *value, int *interp)
 550 {
 551     long tmp;
 552     char *endp;
 553 
 554     if (NULL == value || '\0' == value[0]) return OPAL_ERR_BAD_PARAM;
 555 
 556     errno = 0;
 557     tmp = strtol(value, &endp, 10);
 558     /* we found something not a number */
 559     if (*endp != '\0') return OPAL_ERR_BAD_PARAM;
 560     /* underflow */
 561     if (tmp == 0 && errno == EINVAL) return OPAL_ERR_BAD_PARAM;
 562 
 563     *interp = (int) tmp;
 564 
 565     return OPAL_SUCCESS;
 566 }
 567 
 568 
 569 int
 570 opal_info_value_to_bool(char *value, bool *interp)
 571 {
 572     int tmp;
 573 
 574     /* idiot case */
 575     if (NULL == value || NULL == interp) return OPAL_ERR_BAD_PARAM;
 576 
 577     /* is it true / false? */
 578     if (0 == strcmp(value, "true")) {
 579         *interp = true;
 580         return OPAL_SUCCESS;
 581     } else if (0 == strcmp(value, "false")) {
 582         *interp = false;
 583         return OPAL_SUCCESS;
 584 
 585     /* is it a number? */
 586     } else if (OPAL_SUCCESS == opal_info_value_to_int(value, &tmp)) {
 587         if (tmp == 0) {
 588             *interp = false;
 589         } else {
 590             *interp = true;
 591         }
 592         return OPAL_SUCCESS;
 593     }
 594 
 595     return OPAL_ERR_BAD_PARAM;
 596 }

/* [<][>][^][v][top][bottom][index][help] */