/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2012-2017 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2017 IBM Corporation. All rights reserved. * Copyright (c) 2017 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #ifdef HAVE_SYS_UTSNAME_H #include #endif #include #include "opal/util/argv.h" #include "opal/util/opal_getcwd.h" #include "opal/util/output.h" #include "opal/util/strncpy.h" #include "opal/util/info.h" /* * Local functions */ static void info_constructor(opal_info_t *info); static void info_destructor(opal_info_t *info); static void info_entry_constructor(opal_info_entry_t *entry); static void info_entry_destructor(opal_info_entry_t *entry); static opal_info_entry_t *info_find_key (opal_info_t *info, const char *key); /* * opal_info_t classes */ OBJ_CLASS_INSTANCE(opal_info_t, opal_list_t, info_constructor, info_destructor); /* * opal_info_entry_t classes */ OBJ_CLASS_INSTANCE(opal_info_entry_t, opal_list_item_t, info_entry_constructor, info_entry_destructor); /* * Duplicate an info */ int opal_info_dup (opal_info_t *info, opal_info_t **newinfo) { int err; opal_info_entry_t *iterator; OPAL_THREAD_LOCK(info->i_lock); OPAL_LIST_FOREACH(iterator, &info->super, opal_info_entry_t) { err = opal_info_set(*newinfo, iterator->ie_key, iterator->ie_value); if (OPAL_SUCCESS != err) { OPAL_THREAD_UNLOCK(info->i_lock); return err; } } OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_SUCCESS; } static void opal_info_get_nolock (opal_info_t *info, const char *key, int valuelen, char *value, int *flag) { opal_info_entry_t *search; int value_length; search = info_find_key (info, key); if (NULL == search){ *flag = 0; } else if (value && valuelen) { /* * We have found the element, so we can return the value * Set the flag, value_length and value */ *flag = 1; value_length = strlen(search->ie_value); /* * If the stored value is shorter than valuelen, then * we can copy the entire value out. Else, we have to * copy ONLY valuelen bytes out */ if (value_length < valuelen ) { strcpy(value, search->ie_value); } else { opal_strncpy(value, search->ie_value, valuelen); if (OPAL_MAX_INFO_VAL == valuelen) { value[valuelen-1] = 0; } else { value[valuelen] = 0; } } } } static int opal_info_set_nolock (opal_info_t *info, const char *key, const char *value) { char *new_value; opal_info_entry_t *new_info; opal_info_entry_t *old_info; new_value = strdup(value); if (NULL == new_value) { return OPAL_ERR_OUT_OF_RESOURCE; } old_info = info_find_key (info, key); if (NULL != old_info) { /* * key already exists. remove the value associated with it */ free(old_info->ie_value); old_info->ie_value = new_value; } else { new_info = OBJ_NEW(opal_info_entry_t); if (NULL == new_info) { free(new_value); OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_ERR_OUT_OF_RESOURCE; } strncpy (new_info->ie_key, key, OPAL_MAX_INFO_KEY); new_info->ie_value = new_value; opal_list_append (&(info->super), (opal_list_item_t *) new_info); } return OPAL_SUCCESS; } /* * An object's info can be set, but those settings can be modified by * system callbacks. When those callbacks happen, we save a "__IN_"/"val" * copy of changed or erased values. * * extra options for how to dup: * include_system_extras (default 1) * omit_ignored (default 1) * show_modifications (default 0) */ static int opal_info_dup_mode (opal_info_t *info, opal_info_t **newinfo, int include_system_extras, // (k/v with no corresponding __IN_k) int omit_ignored, // (__IN_k with no k/v) int show_modifications) // (pick v from k/v or __IN_k/v) { int err, flag; opal_info_entry_t *iterator; char savedkey[OPAL_MAX_INFO_KEY]; char savedval[OPAL_MAX_INFO_VAL]; char *valptr, *pkey; int is_IN_key; int exists_IN_key, exists_reg_key; OPAL_THREAD_LOCK(info->i_lock); OPAL_LIST_FOREACH(iterator, &info->super, opal_info_entry_t) { // If we see an __IN_ key but no , decide what to do based on mode. // If we see an __IN_ and a , skip since it'll be handled when // we process . is_IN_key = 0; exists_IN_key = 0; exists_reg_key = 0; pkey = iterator->ie_key; if (0 == strncmp(iterator->ie_key, "__IN_", 5)) { pkey += 5; is_IN_key = 1; exists_IN_key = 1; opal_info_get_nolock (info, pkey, 0, NULL, &flag); if (flag) { exists_reg_key = 1; } } else { is_IN_key = 0; exists_reg_key = 1; // see if there is an __IN_ for the current if (strlen(iterator->ie_key) + 5 < OPAL_MAX_INFO_KEY) { sprintf(savedkey, "__IN_%s", iterator->ie_key); opal_info_get_nolock (info, savedkey, OPAL_MAX_INFO_VAL, savedval, &flag); } else { flag = 0; } if (flag) { exists_IN_key = 1; } } if (is_IN_key) { if (exists_reg_key) { // we're processing __IN_ and there exists a so we'll handle it then continue; } else { // we're processing __IN_ and no exists // this would mean was set by the user but ignored by the system // so base our behavior on the omit_ignored if (!omit_ignored) { err = opal_info_set_nolock(*newinfo, pkey, iterator->ie_value); if (OPAL_SUCCESS != err) { OPAL_THREAD_UNLOCK(info->i_lock); return err; } } } } else { valptr = 0; if (!exists_IN_key) { // we're processing and no __IN_ exists // this would mean it's a system setting, not something that came from the user if (include_system_extras) { valptr = iterator->ie_value; } } else { // we're processing and __IN_ also exists // pick which value to use if (!show_modifications) { valptr = savedval; } else { valptr = iterator->ie_value; } } if (valptr) { err = opal_info_set_nolock(*newinfo, pkey, valptr); if (OPAL_SUCCESS != err) { OPAL_THREAD_UNLOCK(info->i_lock); return err; } } } } OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_SUCCESS; } /* * Implement opal_info_dup_mpistandard by using whatever mode * settings represent our interpretation of the standard */ int opal_info_dup_mpistandard (opal_info_t *info, opal_info_t **newinfo) { return opal_info_dup_mode (info, newinfo, 1, 1, 0); } /* * Set a value on the info */ int opal_info_set (opal_info_t *info, const char *key, const char *value) { int ret; OPAL_THREAD_LOCK(info->i_lock); ret = opal_info_set_nolock(info, key, value); OPAL_THREAD_UNLOCK(info->i_lock); return ret; } int opal_info_set_value_enum (opal_info_t *info, const char *key, int value, mca_base_var_enum_t *var_enum) { char *string_value; int ret; ret = var_enum->string_from_value (var_enum, value, &string_value); if (OPAL_SUCCESS != ret) { return ret; } return opal_info_set (info, key, string_value); } /* * Get a value from an info */ int opal_info_get (opal_info_t *info, const char *key, int valuelen, char *value, int *flag) { OPAL_THREAD_LOCK(info->i_lock); opal_info_get_nolock(info, key, valuelen, value, flag); OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_SUCCESS; } int opal_info_get_value_enum (opal_info_t *info, const char *key, int *value, int default_value, mca_base_var_enum_t *var_enum, int *flag) { opal_info_entry_t *search; int ret; *value = default_value; OPAL_THREAD_LOCK(info->i_lock); search = info_find_key (info, key); if (NULL == search){ OPAL_THREAD_UNLOCK(info->i_lock); *flag = 0; return OPAL_SUCCESS; } /* we found a mathing key. pass the string value to the enumerator and * return */ *flag = 1; ret = var_enum->value_from_string (var_enum, search->ie_value, value); OPAL_THREAD_UNLOCK(info->i_lock); return ret; } /* * Similar to opal_info_get(), but cast the result into a boolean * using some well-defined rules. */ int opal_info_get_bool(opal_info_t *info, char *key, bool *value, int *flag) { char str[256]; str[sizeof(str) - 1] = '\0'; opal_info_get(info, key, sizeof(str) - 1, str, flag); if (*flag) { *value = opal_str_to_bool(str); } return OPAL_SUCCESS; } bool opal_str_to_bool(char *str) { bool result = false; char *ptr; /* Trim whitespace */ ptr = str + sizeof(str) - 1; while (ptr >= str && isspace(*ptr)) { *ptr = '\0'; --ptr; } ptr = str; while (ptr < str + sizeof(str) - 1 && *ptr != '\0' && isspace(*ptr)) { ++ptr; } if ('\0' != *ptr) { if (isdigit(*ptr)) { result = (bool) atoi(ptr); } else if (0 == strcasecmp(ptr, "yes") || 0 == strcasecmp(ptr, "true")) { result = true; } else if (0 != strcasecmp(ptr, "no") && 0 != strcasecmp(ptr, "false")) { /* RHC unrecognized value -- print a warning? */ } } return result; } /* * Delete a key from an info */ int opal_info_delete(opal_info_t *info, const char *key) { opal_info_entry_t *search; OPAL_THREAD_LOCK(info->i_lock); search = info_find_key (info, key); if (NULL == search){ OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_ERR_NOT_FOUND; } else { /* * An entry with this key value was found. Remove the item * and free the memory allocated to it. * As this key *must* be available, we do not check for errors. */ opal_list_remove_item (&(info->super), (opal_list_item_t *)search); OBJ_RELEASE(search); } OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_SUCCESS; } /* * Return the length of a value */ int opal_info_get_valuelen (opal_info_t *info, const char *key, int *valuelen, int *flag) { opal_info_entry_t *search; OPAL_THREAD_LOCK(info->i_lock); search = info_find_key (info, key); if (NULL == search){ *flag = 0; } else { /* * We have found the element, so we can return the value * Set the flag, value_length and value */ *flag = 1; *valuelen = strlen(search->ie_value); } OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_SUCCESS; } /* * Get the nth key */ int opal_info_get_nthkey (opal_info_t *info, int n, char *key) { opal_info_entry_t *iterator; /* * Iterate over and over till we get to the nth key */ OPAL_THREAD_LOCK(info->i_lock); for (iterator = (opal_info_entry_t *)opal_list_get_first(&(info->super)); n > 0; --n) { iterator = (opal_info_entry_t *)opal_list_get_next(iterator); if (opal_list_get_end(&(info->super)) == (opal_list_item_t *) iterator) { OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_ERR_BAD_PARAM; } } /* * iterator is of the type opal_list_item_t. We have to * cast it to opal_info_entry_t before we can use it to * access the value */ strncpy(key, iterator->ie_key, OPAL_MAX_INFO_KEY); OPAL_THREAD_UNLOCK(info->i_lock); return OPAL_SUCCESS; } /* * This function is invoked when OBJ_NEW() is called. Here, we add this * info pointer to the table and then store its index as the handle */ static void info_constructor(opal_info_t *info) { info->i_lock = OBJ_NEW(opal_mutex_t); } /* * This function is called during OBJ_DESTRUCT of "info". When this * done, we need to remove the entry from the opal fortran to C * translation table */ static void info_destructor(opal_info_t *info) { opal_list_item_t *item; opal_info_entry_t *iterator; /* Remove every key in the list */ for (item = opal_list_remove_first(&(info->super)); NULL != item; item = opal_list_remove_first(&(info->super))) { iterator = (opal_info_entry_t *) item; OBJ_RELEASE(iterator); } /* Release the lock */ OBJ_RELEASE(info->i_lock); } /* * opal_info_entry_t interface functions */ static void info_entry_constructor(opal_info_entry_t *entry) { memset(entry->ie_key, 0, sizeof(entry->ie_key)); entry->ie_key[OPAL_MAX_INFO_KEY] = 0; } static void info_entry_destructor(opal_info_entry_t *entry) { if (NULL != entry->ie_value) { free(entry->ie_value); } } /* * Find a key * * Do NOT thread lock in here -- the calling function is responsible * for that. */ static opal_info_entry_t *info_find_key (opal_info_t *info, const char *key) { opal_info_entry_t *iterator; /* No thread locking in here! */ /* Iterate over all the entries. If the key is found, then * return immediately. Else, the loop will fall of the edge * and NULL is returned */ OPAL_LIST_FOREACH(iterator, &info->super, opal_info_entry_t) { if (0 == strcmp(key, iterator->ie_key)) { return iterator; } } return NULL; } int opal_info_value_to_int(char *value, int *interp) { long tmp; char *endp; if (NULL == value || '\0' == value[0]) return OPAL_ERR_BAD_PARAM; errno = 0; tmp = strtol(value, &endp, 10); /* we found something not a number */ if (*endp != '\0') return OPAL_ERR_BAD_PARAM; /* underflow */ if (tmp == 0 && errno == EINVAL) return OPAL_ERR_BAD_PARAM; *interp = (int) tmp; return OPAL_SUCCESS; } int opal_info_value_to_bool(char *value, bool *interp) { int tmp; /* idiot case */ if (NULL == value || NULL == interp) return OPAL_ERR_BAD_PARAM; /* is it true / false? */ if (0 == strcmp(value, "true")) { *interp = true; return OPAL_SUCCESS; } else if (0 == strcmp(value, "false")) { *interp = false; return OPAL_SUCCESS; /* is it a number? */ } else if (OPAL_SUCCESS == opal_info_value_to_int(value, &tmp)) { if (tmp == 0) { *interp = false; } else { *interp = true; } return OPAL_SUCCESS; } return OPAL_ERR_BAD_PARAM; }