text: /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
  /*
   * Copyright (c) 2012-2015 Los Alamos National Security, LLC.  All rights
   *                         reserved.
   * Copyright (c) 2014-2020 Intel, Inc.  All rights reserved.
   * Copyright (c) 2014-2019 Research Organization for Information Science
   *                         and Technology (RIST).  All rights reserved.
   * Copyright (c) 2016      Mellanox Technologies, Inc.
   *                         All rights reserved.
   * Copyright (c) 2016-2020 Cisco Systems, Inc.  All rights reserved
   * Copyright (c) 2020      IBM Corporation.  All rights reserved.
   * Copyright (c) 2021      Nanook Consulting.  All rights reserved.
   * $COPYRIGHT$
   *
   * Additional copyrights may follow
   *
   * $HEADER$
   *
   */
  
  #include "prte_config.h"
  #include "src/include/constants.h"
  
  
  #include <regex.h>
  
  #include <time.h>
  #include <string.h>
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  #if PRTE_HAVE_ZLIB
  #include <zlib.h>
  #endif
  
  #include "src/class/prte_hash_table.h"
  #include "src/threads/threads.h"
  #include "src/util/proc_info.h"
  #include "src/runtime/prte_globals.h"
  #include "src/mca/plm/base/plm_private.h"
  #include "src/pmix/pmix-internal.h"
  
  pmix_status_t prte_pmix_convert_rc(int rc)
  {
      switch (rc) {
  
  #if PMIX_NUMERIC_VERSION >= 0x00040000
      case PRTE_ERR_HEARTBEAT_ALERT:
      case PRTE_ERR_FILE_ALERT:
      case PRTE_ERR_HEARTBEAT_LOST:
      case PRTE_ERR_SENSOR_LIMIT_EXCEEDED:
          return PMIX_ERR_JOB_SENSOR_BOUND_EXCEEDED;
  
      case PRTE_ERR_NO_EXE_SPECIFIED:
      case PRTE_ERR_NO_APP_SPECIFIED:
          return PMIX_ERR_JOB_NO_EXE_SPECIFIED;
  
      case PRTE_ERR_FAILED_TO_MAP:
          return PMIX_ERR_JOB_FAILED_TO_MAP;
  
      case PRTE_ERR_JOB_CANCELLED:
          return PMIX_ERR_JOB_CANCELED;
  #endif
  
      case PRTE_ERR_DEBUGGER_RELEASE:
          return PMIX_ERR_DEBUGGER_RELEASE;
  
      case PRTE_ERR_HANDLERS_COMPLETE:
          return PMIX_EVENT_ACTION_COMPLETE;
  
      case PRTE_ERR_PROC_ABORTED:
          return PMIX_ERR_PROC_ABORTED;
  
      case PRTE_ERR_PROC_REQUESTED_ABORT:
          return PMIX_ERR_PROC_REQUESTED_ABORT;
  
      case PRTE_ERR_PROC_ABORTING:
          return PMIX_ERR_PROC_ABORTING;
  
      case PRTE_ERR_NODE_DOWN:
          return PMIX_ERR_NODE_DOWN;
  
      case PRTE_ERR_NODE_OFFLINE:
          return PMIX_ERR_NODE_OFFLINE;
  
      case PRTE_ERR_JOB_TERMINATED:
          return PMIX_ERR_JOB_TERMINATED;
  
      case PRTE_ERR_PROC_RESTART:
          return PMIX_ERR_PROC_RESTART;
  
      case PRTE_ERR_PROC_CHECKPOINT:
          return PMIX_ERR_PROC_CHECKPOINT;
  
      case PRTE_ERR_PROC_MIGRATE:
          return PMIX_ERR_PROC_MIGRATE;
  
      case PRTE_ERR_EVENT_REGISTRATION:
          return PMIX_ERR_EVENT_REGISTRATION;
  
      case PRTE_ERR_NOT_IMPLEMENTED:
      case PRTE_ERR_NOT_SUPPORTED:
          return PMIX_ERR_NOT_SUPPORTED;
  
      case PRTE_ERR_NOT_FOUND:
          return PMIX_ERR_NOT_FOUND;
  
      case PRTE_ERR_PERM:
      case PRTE_ERR_UNREACH:
      case PRTE_ERR_SERVER_NOT_AVAIL:
          return PMIX_ERR_UNREACH;
  
      case PRTE_ERR_BAD_PARAM:
          return PMIX_ERR_BAD_PARAM;
  
      case PRTE_ERR_OUT_OF_RESOURCE:
          return PMIX_ERR_OUT_OF_RESOURCE;
  
      case PRTE_ERR_DATA_VALUE_NOT_FOUND:
          return PMIX_ERR_DATA_VALUE_NOT_FOUND;
  
      case PRTE_ERR_TIMEOUT:
          return PMIX_ERR_TIMEOUT;
  
      case PRTE_ERR_WOULD_BLOCK:
          return PMIX_ERR_WOULD_BLOCK;
  
      case PRTE_EXISTS:
          return PMIX_EXISTS;
  
      case PRTE_ERR_PARTIAL_SUCCESS:
          return PMIX_QUERY_PARTIAL_SUCCESS;
  
      case PRTE_ERR_MODEL_DECLARED:
          return PMIX_MODEL_DECLARED;
  
      case PRTE_ERROR:
          return PMIX_ERROR;
      case PRTE_SUCCESS:
          return PMIX_SUCCESS;
  
      default:
          return PMIX_ERROR;
      }
  }
  
  int prte_pmix_convert_status(pmix_status_t status)
  {
      switch (status) {
      case PMIX_ERR_DEBUGGER_RELEASE:
          return PRTE_ERR_DEBUGGER_RELEASE;
  
      case PMIX_EVENT_ACTION_COMPLETE:
          return PRTE_ERR_HANDLERS_COMPLETE;
  
      case PMIX_ERR_PROC_ABORTED:
          return PRTE_ERR_PROC_ABORTED;
  
      case PMIX_ERR_PROC_REQUESTED_ABORT:
          return PRTE_ERR_PROC_REQUESTED_ABORT;
  
      case PMIX_ERR_PROC_ABORTING:
          return PRTE_ERR_PROC_ABORTING;
  
      case PMIX_ERR_NODE_DOWN:
          return PRTE_ERR_NODE_DOWN;
  
      case PMIX_ERR_NODE_OFFLINE:
          return PRTE_ERR_NODE_OFFLINE;
  
      case PMIX_ERR_JOB_TERMINATED:
          return PRTE_ERR_JOB_TERMINATED;
  
      case PMIX_ERR_PROC_RESTART:
          return PRTE_ERR_PROC_RESTART;
  
      case PMIX_ERR_PROC_CHECKPOINT:
          return PRTE_ERR_PROC_CHECKPOINT;
  
      case PMIX_ERR_PROC_MIGRATE:
          return PRTE_ERR_PROC_MIGRATE;
  
      case PMIX_ERR_EVENT_REGISTRATION:
          return PRTE_ERR_EVENT_REGISTRATION;
  
      case PMIX_ERR_NOT_SUPPORTED:
          return PRTE_ERR_NOT_SUPPORTED;
  
      case PMIX_ERR_NOT_FOUND:
          return PRTE_ERR_NOT_FOUND;
  
      case PMIX_ERR_OUT_OF_RESOURCE:
          return PRTE_ERR_OUT_OF_RESOURCE;
  
      case PMIX_ERR_INIT:
          return PRTE_ERROR;
  
      case PMIX_ERR_BAD_PARAM:
          return PRTE_ERR_BAD_PARAM;
  
      case PMIX_ERR_UNREACH:
      case PMIX_ERR_NO_PERMISSIONS:
          return PRTE_ERR_UNREACH;
  
      case PMIX_ERR_TIMEOUT:
          return PRTE_ERR_TIMEOUT;
  
      case PMIX_ERR_WOULD_BLOCK:
          return PRTE_ERR_WOULD_BLOCK;
  
      case PMIX_ERR_LOST_CONNECTION:
          return PRTE_ERR_COMM_FAILURE;
  
      case PMIX_EXISTS:
          return PRTE_EXISTS;
  
      case PMIX_QUERY_PARTIAL_SUCCESS:
          return PRTE_ERR_PARTIAL_SUCCESS;
  
      case PMIX_MONITOR_HEARTBEAT_ALERT:
          return PRTE_ERR_HEARTBEAT_ALERT;
  
      case PMIX_MONITOR_FILE_ALERT:
          return PRTE_ERR_FILE_ALERT;
  
      case PMIX_MODEL_DECLARED:
          return PRTE_ERR_MODEL_DECLARED;
  
      case PMIX_ERROR:
          return PRTE_ERROR;
      case PMIX_SUCCESS:
      case PMIX_OPERATION_SUCCEEDED:
          return PRTE_SUCCESS;
      default:
          return status;
      }
  }
  
  pmix_proc_state_t prte_pmix_convert_state(int state)
  {
      switch(state) {
          case 0:
              return PMIX_PROC_STATE_UNDEF;
          case 1:
              return PMIX_PROC_STATE_LAUNCH_UNDERWAY;
          case 2:
              return PMIX_PROC_STATE_RESTART;
          case 3:
              return PMIX_PROC_STATE_TERMINATE;
          case 4:
              return PMIX_PROC_STATE_RUNNING;
          case 5:
              return PMIX_PROC_STATE_CONNECTED;
          case 51:
              return PMIX_PROC_STATE_KILLED_BY_CMD;
          case 52:
              return PMIX_PROC_STATE_ABORTED;
          case 53:
              return PMIX_PROC_STATE_FAILED_TO_START;
          case 54:
              return PMIX_PROC_STATE_ABORTED_BY_SIG;
          case 55:
              return PMIX_PROC_STATE_TERM_WO_SYNC;
          case 56:
              return PMIX_PROC_STATE_COMM_FAILED;
          case 58:
              return PMIX_PROC_STATE_CALLED_ABORT;
          case 59:
              return PMIX_PROC_STATE_MIGRATING;
          case 61:
              return PMIX_PROC_STATE_CANNOT_RESTART;
          case 62:
              return PMIX_PROC_STATE_TERM_NON_ZERO;
          case 63:
              return PMIX_PROC_STATE_FAILED_TO_LAUNCH;
          default:
              return PMIX_PROC_STATE_UNDEF;
      }
  }
  
  int prte_pmix_convert_pstate(pmix_proc_state_t state)
  {
      switch(state) {
          case PMIX_PROC_STATE_UNDEF:
              return 0;
          case PMIX_PROC_STATE_PREPPED:
          case PMIX_PROC_STATE_LAUNCH_UNDERWAY:
              return 1;
          case PMIX_PROC_STATE_RESTART:
              return 2;
          case PMIX_PROC_STATE_TERMINATE:
              return 3;
          case PMIX_PROC_STATE_RUNNING:
              return 4;
          case PMIX_PROC_STATE_CONNECTED:
              return 5;
          case PMIX_PROC_STATE_UNTERMINATED:
              return 15;
          case PMIX_PROC_STATE_TERMINATED:
              return 20;
          case PMIX_PROC_STATE_KILLED_BY_CMD:
              return 51;
          case PMIX_PROC_STATE_ABORTED:
              return 52;
          case PMIX_PROC_STATE_FAILED_TO_START:
              return 53;
          case PMIX_PROC_STATE_ABORTED_BY_SIG:
              return 54;
          case PMIX_PROC_STATE_TERM_WO_SYNC:
              return 55;
          case PMIX_PROC_STATE_COMM_FAILED:
              return 56;
          case PMIX_PROC_STATE_CALLED_ABORT:
              return 58;
          case PMIX_PROC_STATE_MIGRATING:
              return 60;
          case PMIX_PROC_STATE_CANNOT_RESTART:
              return 61;
          case PMIX_PROC_STATE_TERM_NON_ZERO:
              return 62;
          case PMIX_PROC_STATE_FAILED_TO_LAUNCH:
              return 63;
          default:
              return 0;  // undef
      }
  }
  
  pmix_status_t prte_pmix_convert_job_state_to_error(int state)
  {
      switch(state) {
  
  #if PMIX_NUMERIC_VERSION >= 0x00040000
          case PRTE_JOB_STATE_ALLOC_FAILED:
              return PMIX_ERR_JOB_ALLOC_FAILED;
  
          case PRTE_JOB_STATE_MAP_FAILED:
              return PMIX_ERR_JOB_FAILED_TO_MAP;
  
          case PRTE_JOB_STATE_NEVER_LAUNCHED:
          case PRTE_JOB_STATE_FAILED_TO_LAUNCH:
          case PRTE_JOB_STATE_FAILED_TO_START:
          case PRTE_JOB_STATE_CANNOT_LAUNCH:
              return PMIX_ERR_JOB_FAILED_TO_LAUNCH;
  
          case PRTE_JOB_STATE_KILLED_BY_CMD:
              return PMIX_ERR_JOB_CANCELED;
  
          case PRTE_JOB_STATE_ABORTED:
          case PRTE_JOB_STATE_CALLED_ABORT:
          case PRTE_JOB_STATE_SILENT_ABORT:
              return PMIX_ERR_JOB_ABORTED;
  
          case PRTE_JOB_STATE_ABORTED_BY_SIG:
              return PMIX_ERR_JOB_ABORTED_BY_SIG;
  
          case PRTE_JOB_STATE_ABORTED_WO_SYNC:
              return PMIX_ERR_JOB_TERM_WO_SYNC;
  #endif
  
          case PRTE_JOB_STATE_TERMINATED:
              return PMIX_ERR_JOB_TERMINATED;
  
          default:
              return PMIX_ERROR;
      }
  }
  
  pmix_status_t prte_pmix_convert_proc_state_to_error(int state)
  {
      switch(state) {
          default:
              return PMIX_ERROR;
      }
  }
  
  static void cleanup_cbfunc(pmix_status_t status,
                             pmix_info_t *info, size_t ninfo,
                             void *cbdata,
                             pmix_release_cbfunc_t release_fn,
                             void *release_cbdata)
  {
      prte_pmix_lock_t *lk = (prte_pmix_lock_t*)cbdata;
  
      PRTE_POST_OBJECT(lk);
  
      /* let the library release the data and cleanup from
       * the operation */
      if (NULL != release_fn) {
          release_fn(release_cbdata);
      }
  
      /* release the block */
      lk->status = status;
      PRTE_PMIX_WAKEUP_THREAD(lk);
  }
  
  int prte_pmix_register_cleanup(char *path, bool directory, bool ignore, bool jobscope)
  {
      prte_pmix_lock_t lk;
      pmix_info_t pinfo[3];
      size_t n, ninfo=0;
      pmix_status_t rc, ret;
  
      PRTE_PMIX_CONSTRUCT_LOCK(&lk);
  
      if (ignore) {
          /* they want this path ignored */
          PMIX_INFO_LOAD(&pinfo[ninfo], PMIX_CLEANUP_IGNORE, path, PMIX_STRING);
          ++ninfo;
      } else {
          if (directory) {
              PMIX_INFO_LOAD(&pinfo[ninfo], PMIX_REGISTER_CLEANUP_DIR, path, PMIX_STRING);
              ++ninfo;
              /* recursively cleanup directories */
              PMIX_INFO_LOAD(&pinfo[ninfo], PMIX_CLEANUP_RECURSIVE, NULL, PMIX_BOOL);
              ++ninfo;
          } else {
              /* order cleanup of the provided path */
              PMIX_INFO_LOAD(&pinfo[ninfo], PMIX_REGISTER_CLEANUP, path, PMIX_STRING);
              ++ninfo;
          }
      }
  
      /* if they want this applied to the job, then indicate so */
      if (jobscope) {
          rc = PMIx_Job_control_nb(NULL, 0, pinfo, ninfo, cleanup_cbfunc, (void*)&lk);
      } else {
          rc = PMIx_Job_control_nb(PRTE_PROC_MY_NAME, 1, pinfo, ninfo, cleanup_cbfunc, (void*)&lk);
      }
      if (PMIX_SUCCESS != rc) {
          ret = rc;
      } else {
  #if PMIX_VERSION_MAJOR == 3 && PMIX_VERSION_MINOR == 0 && PMIX_VERSION_RELEASE < 3
          /* There is a bug in PMIx 3.0.0 up to 3.0.2 that causes the callback never
           * being called, so assumes the everything went well and avoid a deadlock. */
          cleanup_cbfunc(PMIX_SUCCESS, NULL, 0, (void *)&lk, NULL, NULL);
  #endif
          PRTE_PMIX_WAIT_THREAD(&lk);
          ret = lk.status;
      }
      PRTE_PMIX_DESTRUCT_LOCK(&lk);
      for (n=0; n < ninfo; n++) {
          PMIX_INFO_DESTRUCT(&pinfo[n]);
      }
      return ret;
  }
  
  /* CLASS INSTANTIATIONS */
  static void dsicon(prte_ds_info_t *p)
  {
      PMIX_PROC_CONSTRUCT(&p->source);
      p->info = NULL;
      p->persistence = PMIX_PERSIST_INVALID;
  }
  PRTE_EXPORT PRTE_CLASS_INSTANCE(prte_ds_info_t,
                                    prte_list_item_t,
                                    dsicon, NULL);
  
  static void infoitmcon(prte_info_item_t *p)
  {
      PMIX_INFO_CONSTRUCT(&p->info);
  }
  static void infoitdecon(prte_info_item_t *p)
  {
      PMIX_INFO_DESTRUCT(&p->info);
  }
  PRTE_EXPORT PRTE_CLASS_INSTANCE(prte_info_item_t,
                                    prte_list_item_t,
                                    infoitmcon, infoitdecon);
  
  static void arritmcon(prte_info_array_item_t *p)
  {
      PRTE_CONSTRUCT(&p->infolist, prte_list_t);
  }
  static void arritdecon(prte_info_array_item_t *p)
  {
      PRTE_LIST_DESTRUCT(&p->infolist);
  }
  PRTE_EXPORT PRTE_CLASS_INSTANCE(prte_info_array_item_t,
                                    prte_list_item_t,
                                    arritmcon, arritdecon);
  
  static void pvcon(prte_value_t *p)
  {
      PMIX_VALUE_CONSTRUCT(&p->value);
  }
  static void pvdes(prte_value_t *p)
  {
      PMIX_VALUE_DESTRUCT(&p->value);
  }
  PRTE_EXPORT PRTE_CLASS_INSTANCE(prte_value_t,
                                  prte_list_item_t,
                                  pvcon, pvdes);
  
  #if PMIX_NUMERIC_VERSION < 0x00040100
  #define PMIX_EMBED_DATA_BUFFER(b, db)                       \
      do {                                                    \
          (b)->type = pmix_globals.mypeer->nptr->compat.type; \
          (b)->base_ptr = (db)->base_ptr;                     \
          (b)->pack_ptr = (db)->pack_ptr;                     \
          (b)->unpack_ptr = (db)->unpack_ptr;                 \
          (b)->bytes_allocated = (db)->bytes_allocated;       \
          (b)->bytes_used = (db)->bytes_used;                 \
          (db)->base_ptr = NULL;                              \
          (db)->pack_ptr = NULL;                              \
          (db)->unpack_ptr = NULL;                            \
          (db)->bytes_allocated = 0;                          \
          (db)->bytes_used = 0;                               \
      } while (0)
  
  #define PMIX_EXTRACT_DATA_BUFFER(b, db)                 \
      do {                                                \
          (db)->base_ptr = (b)->base_ptr;                 \
          (db)->pack_ptr = (b)->pack_ptr;                 \
          (db)->unpack_ptr = (b)->unpack_ptr;             \
          (db)->bytes_allocated = (b)->bytes_allocated;   \
          (db)->bytes_used = (b)->bytes_used;             \
          (b)->base_ptr = NULL;                           \
          (b)->pack_ptr = NULL;                           \
          (b)->unpack_ptr = NULL;                         \
          (b)->bytes_allocated = 0;                       \
          (b)->bytes_used = 0;                            \
      } while (0)
  
  pmix_status_t PMIx_Data_unload(pmix_data_buffer_t *buffer,
                                 pmix_byte_object_t *payload)
  {
      /* check that buffer is not null */
      if (!buffer) {
          return PMIX_ERR_BAD_PARAM;
      }
  
      /* were we given someplace to point to the payload */
      if (NULL == payload) {
          return PMIX_ERR_BAD_PARAM;
      }
  
      /* init default response */
      PMIX_BYTE_OBJECT_CONSTRUCT(payload);
  
      /* anything in the buffer - if not, nothing to do */
      if (NULL == buffer->base_ptr || 0 == buffer->bytes_used) {
          return PMIX_SUCCESS;
      }
  
      /* if nothing has been unpacked, we can pass the entire
       * region back and protect it - no need to copy. This is
       * an optimization */
      if (buffer->unpack_ptr == buffer->base_ptr) {
          payload->bytes = buffer->base_ptr;
          payload->size = buffer->bytes_used;
          buffer->base_ptr = NULL;
          buffer->bytes_used = 0;
          goto cleanup;
      }
  
      /* okay, we have something to provide - pass it back */
      payload->size = buffer->bytes_used - (buffer->unpack_ptr - buffer->base_ptr);
      if (0 < payload->size) {
          /* we cannot just set the pointer as it might be
           * partway in a malloc'd region */
          payload->bytes = (char*)malloc(payload->size);
          memcpy(payload->bytes, buffer->unpack_ptr, payload->size);
      }
  
  cleanup:
      /* All done - reset the buffer */
      PMIX_DATA_BUFFER_DESTRUCT(buffer);
      PMIX_DATA_BUFFER_CONSTRUCT(buffer);
      return PMIX_SUCCESS;
  }
  
  pmix_status_t PMIx_Data_load(pmix_data_buffer_t *buffer,
                               pmix_byte_object_t *payload)
  {
      /* check to see if the buffer has been initialized */
      if (NULL == buffer) {
          return PMIX_ERR_BAD_PARAM;
      }
  
      /* check if buffer already has payload - free it if so */
      PMIX_DATA_BUFFER_DESTRUCT(buffer);
      PMIX_DATA_BUFFER_CONSTRUCT(buffer);
  
      /* if it's a NULL payload, just set things and return */
      if (NULL == payload) {
          return PMIX_SUCCESS;
      }
  
      /* populate the buffer */
      buffer->base_ptr = payload->bytes;
  
      /* set pack/unpack pointers */
      buffer->pack_ptr = ((char*)buffer->base_ptr) + payload->size;
      buffer->unpack_ptr = buffer->base_ptr;
  
      /* set counts for size and space */
      buffer->bytes_allocated = buffer->bytes_used = payload->size;
  
      /* protect the payload */
      payload->bytes = NULL;
      payload->size = 0;
  
      /* All done */
  
      return PMIX_SUCCESS;
  }
  
  bool PMIx_Data_compress(uint8_t *inbytes,
                          size_t inlen,
                          uint8_t **outbytes,
                          size_t *outlen)
  {
      z_stream strm;
      size_t len, len2;
      uint8_t *tmp, *ptr;
      int rc;
  
      if (NULL == inbytes) {
          return false;
      }
  
      /* set default output */
      *outbytes = NULL;
      *outlen = 0;
  
      /* setup the stream */
      memset (&strm, 0, sizeof (strm));
      deflateInit (&strm, 9);
  
      /* get an upper bound on the required output storage */
      len = deflateBound(&strm, inlen);
      /* if this isn't going to result in a smaller footprint,
       * then don't do it */
      if (len >= inlen) {
          (void)deflateEnd(&strm);
          return false;
      }
  
      if (NULL == (tmp = (uint8_t*)malloc(len))) {
          (void)deflateEnd(&strm);
          return false;
      }
      strm.next_in = inbytes;
      strm.avail_in = inlen;
  
      /* allocating the upper bound guarantees zlib will
       * always successfully compress into the available space */
      strm.avail_out = len;
      strm.next_out = tmp;
  
      rc = deflate (&strm, Z_FINISH);
      (void)deflateEnd (&strm);
      if (Z_OK != rc && Z_STREAM_END != rc) {
          free(tmp);
          return false;
      }
  
      /* allocate 4 bytes beyond the size reqd by zlib so we
       * can pass the size of the uncompressed block to the
       * decompress side */
      len2 = len - strm.avail_out + sizeof(uint32_t);
      ptr = (uint8_t*)malloc(len2);
      if (NULL == ptr) {
          free(tmp);
          return false;
      }
      *outbytes = ptr;
      *outlen = len2;
  
      /* fold the uncompressed length into the buffer */
      memcpy(ptr, &inlen, sizeof(uint32_t));
      ptr += sizeof(uint32_t);
      /* bring over the compressed data */
      memcpy(ptr, tmp, len2-sizeof(uint32_t));
      free(tmp);
      return true;  // we did the compression
  }
  
  bool PMIx_Data_decompress(uint8_t **outbytes,
                            size_t *outlen,
                            uint8_t *inbytes,
                            size_t inlen)
  {
      int32_t len2;
      int rc;
      uint8_t *input;
      uint8_t *dest;
      z_stream strm;
  
      if (NULL == inbytes) {
          return PMIX_ERR_BAD_PARAM;
      }
  
      /* set the default error answer */
      *outbytes = NULL;
      *outlen = 0;
  
      /* the first 4 bytes contains the uncompressed size */
      memcpy(&len2, inbytes, sizeof(uint32_t));
      input = (uint8_t*)(inbytes + sizeof(uint32_t));  // step over the size
  
      /* setting destination to the fully decompressed size */
      dest = (uint8_t*)malloc(len2);
      if (NULL == dest) {
          return false;
      }
      memset(dest, 0, len2);
  
      memset (&strm, 0, sizeof (strm));
      if (Z_OK != inflateInit(&strm)) {
          free(dest);
          return false;
      }
      strm.avail_in = inlen;
      strm.next_in = inbytes;
      strm.avail_out = len2;
      strm.next_out = dest;
  
      rc = inflate (&strm, Z_FINISH);
      inflateEnd (&strm);
      if (Z_OK == rc) {
          *outbytes = dest;
          *outlen = len2;
          return true;
      }
      free(dest);
      return false;
  }
  
  pmix_status_t PMIx_Data_embed(pmix_data_buffer_t *buffer,
                                const pmix_byte_object_t *payload)
  {
      pmix_data_buffer_t src;
      pmix_status_t rc;
  
      /* check to see if the buffer has been initialized */
      if (NULL == buffer) {
          return PMIX_ERR_BAD_PARAM;
      }
  
      /* check if buffer already has payload - free it if so */
      PMIX_DATA_BUFFER_DESTRUCT(buffer);
      PMIX_DATA_BUFFER_CONSTRUCT(buffer);
  
      /* if it's a NULL payload, we are done */
      if (NULL == payload) {
          return PMIX_SUCCESS;
      }
  
      /* setup the source */
      src.base_ptr = payload->bytes;
      src.pack_ptr = ((char*)src.base_ptr) + payload->size;
      src.unpack_ptr = src.base_ptr;
      src.bytes_allocated =src.bytes_used = payload->size;
  
      /* execute a copy operation */
      rc = PMIx_Data_copy_payload(buffer, &src);
      /* do NOT destruct the source as that would release
       * data in the payload */
  
      return rc;
  }
  #endif
  