Beispiel #1
0
static int do_a_command(FILE *input, BSOCK *UA_sock)
{
   unsigned int i;
   int status;
   int found;
   int len;
   char *cmd;

   found = 0;
   status = 1;

   Dmsg1(120, "Command: %s\n", UA_sock->msg);
   if (argc == 0) {
      return 1;
   }

   cmd = argk[0]+1;
   if (*cmd == '#') {                 /* comment */
      return 1;
   }
   len = strlen(cmd);
   for (i=0; i<comsize; i++) {     /* search for command */
      if (bstrncasecmp(cmd,  _(commands[i].key), len)) {
         status = (*commands[i].func)(input, UA_sock);   /* go execute command */
         found = 1;
         break;
      }
   }
   if (!found) {
      pm_strcat(&UA_sock->msg, _(": is an invalid command\n"));
      UA_sock->msglen = strlen(UA_sock->msg);
      sendit(UA_sock->msg);
   }
   return status;
}
Beispiel #2
0
static inline backend_interface_mapping_t *lookup_backend_interface_mapping(const char *interface_name)
{
   backend_interface_mapping_t *backend_interface_mapping;

   for (backend_interface_mapping = backend_interface_mappings;
        backend_interface_mapping->interface_name != NULL;
        backend_interface_mapping++) {

      Dmsg3(100, "db_init_database: Trying to find mapping of given interfacename %s to mapping interfacename %s, partly_compare = %s\n",
            interface_name, backend_interface_mapping->interface_name, (backend_interface_mapping->partly_compare) ? "true" : "false");

      /*
       * See if this is a match.
       */
      if (backend_interface_mapping->partly_compare) {
         if (bstrncasecmp(interface_name, backend_interface_mapping->interface_name,
                              strlen(backend_interface_mapping->interface_name))) {
            return backend_interface_mapping;
         }
      } else {
         if (bstrcasecmp(interface_name, backend_interface_mapping->interface_name)) {
            return backend_interface_mapping;
         }
      }
   }

   return NULL;
}
Beispiel #3
0
/*
 * Execute a command from the UA
 */
bool do_a_dot_command(UAContext *ua)
{
   int i;
   int len;
   bool ok = false;
   bool found = false;
   BSOCK *user = ua->UA_sock;

   Dmsg1(1400, "Dot command: %s\n", user->msg);
   if (ua->argc == 0) {
      return false;
   }

   len = strlen(ua->argk[0]);
   if (len == 1) {
      if (ua->api) user->signal(BNET_CMD_BEGIN);
      if (ua->api) user->signal(BNET_CMD_OK);
      return true;                    /* no op */
   }
   for (i=0; i<comsize; i++) {     /* search for command */
      if (bstrncasecmp(ua->argk[0],  _(commands[i].key), len)) {
         /* Check if this command is authorized in RunScript */
         if (ua->runscript && !commands[i].use_in_rs) {
            ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
            break;
         }
         bool gui = ua->gui;
         /* Check if command permitted, but "quit" is always OK */
         if (!bstrcmp(ua->argk[0], NT_(".quit")) &&
             !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
            break;
         }
         Dmsg1(100, "Cmd: %s\n", ua->cmd);
         ua->gui = true;
         if (ua->api) user->signal(BNET_CMD_BEGIN);
         ok = (*commands[i].func)(ua, ua->cmd);   /* go execute command */
         if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
         ua->gui = gui;
         found = true;
         break;
      }
   }
   if (!found) {
      ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n"));
      ok = false;
   }
   return ok;
}
Beispiel #4
0
Datei: edit.c Projekt: AlD/bareos
static bool strunit_to_uint64(char *str, uint64_t *value, const char **mod)
{
   int i, mod_len;
   double val;
   char mod_str[20];
   char num_str[50];
   const int64_t mult[] = {1,             /* byte */
                           1024,          /* kilobyte */
                           1000,          /* kb kilobyte */
                           1048576,       /* megabyte */
                           1000000,       /* mb megabyte */
                           1073741824,    /* gigabyte */
                           1000000000};   /* gb gigabyte */

   if (!get_modifier(str, num_str, sizeof(num_str), mod_str, sizeof(mod_str))) {
      return 0;
   }
   /* Now find the multiplier corresponding to the modifier */
   mod_len = strlen(mod_str);
   if (mod_len == 0) {
      i = 0;                          /* default with no modifier = 1 */
   } else {
      for (i=0; mod[i]; i++) {
         if (bstrncasecmp(mod_str, mod[i], mod_len)) {
            break;
         }
      }
      if (mod[i] == NULL) {
         return false;
      }
   }
   Dmsg2(900, "str=%s: mult=%d\n", str, mult[i]);
   errno = 0;
   val = strtod(num_str, NULL);
   if (errno != 0 || val < 0) {
      return false;
   }
   *value = (utime_t)(val * mult[i]);
   return true;
}
Beispiel #5
0
Datei: edit.c Projekt: AlD/bareos
/*
 * Convert a string duration to utime_t (64 bit seconds)
 * Returns false: if error
           true:  if OK, and value stored in value
 */
bool duration_to_utime(char *str, utime_t *value)
{
   int i, mod_len;
   double val, total = 0.0;
   char mod_str[20];
   char num_str[50];
   /*
    * The "n" = mins and months appears before minutes so that m maps to months.
    */
   static const char *mod[] = {
      "n",
      "seconds",
      "months",
      "minutes",
      "mins",
      "hours",
      "days",
      "weeks",
      "quarters",
      "years",
      (char *)NULL
   };
   static const int32_t mult[] = {
      60,
      1,
      60 * 60 * 24 * 30,
      60,
      60,
      3600,
      3600 * 24,
      3600 * 24 * 7,
      3600 * 24 * 91,
      3600 * 24 * 365,
      0
   };

   while (*str) {
      if (!get_modifier(str, num_str, sizeof(num_str), mod_str, sizeof(mod_str))) {
         return false;
      }
      /* Now find the multiplier corresponding to the modifier */
      mod_len = strlen(mod_str);
      if (mod_len == 0) {
         i = 1;                          /* default to seconds */
      } else {
         for (i=0; mod[i]; i++) {
            if (bstrncasecmp(mod_str, mod[i], mod_len)) {
               break;
            }
         }
         if (mod[i] == NULL) {
            return false;
         }
      }
      Dmsg2(900, "str=%s: mult=%d\n", num_str, mult[i]);
      errno = 0;
      val = strtod(num_str, NULL);
      if (errno != 0 || val < 0) {
         return false;
      }
      total += val * mult[i];
   }
   *value = (utime_t)total;
   return true;
}
/*
 * Open a volume using libdroplet.
 */
int object_store_device::d_open(const char *pathname, int flags, int mode)
{
   dpl_status_t status;
   dpl_vfile_flag_t dpl_flags;
   dpl_option_t dpl_options;

#if 1
   Mmsg1(errmsg, _("Object Storage devices are not yet supported, please disable %s\n"), dev_name);
   return -1;
#endif

   /*
    * Initialize the droplet library when its not done previously.
    */
   P(mutex);
   if (droplet_reference_count == 0) {
      status = dpl_init();
      if (status != DPL_SUCCESS) {
         V(mutex);
         return -1;
      }

      dpl_set_log_func(object_store_logfunc);
      droplet_reference_count++;
   }
   V(mutex);

   if (!m_object_configstring) {
      int len;
      char *bp, *next_option;
      bool done;

      if (!dev_options) {
         Mmsg0(errmsg, _("No device options configured\n"));
         Emsg0(M_FATAL, 0, errmsg);
         return -1;
      }

      m_object_configstring = bstrdup(dev_options);

      bp = m_object_configstring;
      while (bp) {
         next_option = strchr(bp, ',');
         if (next_option) {
            *next_option++ = '\0';
         }

         done = false;
         for (int i = 0; !done && device_options[i].name; i++) {
            /*
             * Try to find a matching device option.
             */
            if (bstrncasecmp(bp, device_options[i].name, device_options[i].compare_size)) {
               switch (device_options[i].type) {
               case argument_profile:
                  m_profile = bp + device_options[i].compare_size;
                  done = true;
                  break;
               case argument_bucket:
                  m_object_bucketname = bp + device_options[i].compare_size;
                  done = true;
                  break;
               default:
                  break;
               }
            }
         }

         if (!done) {
            Mmsg1(errmsg, _("Unable to parse device option: %s\n"), bp);
            Emsg0(M_FATAL, 0, errmsg);
            goto bail_out;
         }

         bp = next_option;
      }

      if (!m_profile) {
         Mmsg0(errmsg, _("No droplet profile configured\n"));
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      /*
       * Strip any .profile prefix from the libdroplet profile name.
       */
      len = strlen(m_profile);
      if (len > 8 && bstrcasecmp(m_profile + (len - 8), ".profile")) {
         m_profile[len - 8] = '\0';
      }
   }

   /*
    * See if we need to setup a new context for this device.
    */
   if (!m_ctx) {
      char *bp;

      /*
       * See if this is a path.
       */
      bp = strrchr(m_object_configstring, '/');
      if (!bp) {
         /*
          * Only a profile name.
          */
         m_ctx = dpl_ctx_new(NULL, m_object_configstring);
      } else {
         if (bp == m_object_configstring) {
            /*
             * Profile in root of filesystem
             */
            m_ctx = dpl_ctx_new("/", bp + 1);
         } else {
            /*
             * Profile somewhere else.
             */
            *bp++ = '\0';
            m_ctx = dpl_ctx_new(m_object_configstring, bp);
         }
      }

      /*
       * If we failed to allocate a new context fail the open.
       */
      if (!m_ctx) {
         Mmsg1(errmsg, _("Failed to create a new context using config %s\n"), dev_options);
         return -1;
      }

      /*
       * Login if that is needed for this backend.
       */
      status = dpl_login(m_ctx);
      switch (status) {
      case DPL_SUCCESS:
         break;
      case DPL_ENOTSUPP:
         /*
          * Backend doesn't support login which is fine.
          */
         break;
      default:
         Mmsg2(errmsg, _("Failed to login for voume %s using dpl_login(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return -1;
      }

      /*
       * If a bucketname was defined set it in the context.
       */
      if (m_object_bucketname) {
         m_ctx->cur_bucket = m_object_bucketname;
      }
   }

   /*
    * See if we don't have a file open already.
    */
   if (m_vfd) {
      dpl_close(m_vfd);
      m_vfd = NULL;
   }

   /*
    * Create some options for libdroplet.
    *
    * DPL_OPTION_NOALLOC - we provide the buffer to copy the data into
    *                      no need to let the library allocate memory we
    *                      need to free after copying the data.
    */
   memset(&dpl_options, 0, sizeof(dpl_options));
   dpl_options.mask |= DPL_OPTION_NOALLOC;

   if (flags & O_CREAT) {
      dpl_flags = DPL_VFILE_FLAG_CREAT | DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);
   } else {
      dpl_flags = DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);
   }

   switch (status) {
   case DPL_SUCCESS:
      m_offset = 0;
      return 0;
   default:
      Mmsg2(errmsg, _("Failed to open %s using dpl_open(): ERR=%s.\n"),
            getVolCatName(), dpl_status_str(status));
      m_vfd = NULL;
      return droplet_errno_to_system_errno(status);
   }

bail_out:
   return -1;
}
Beispiel #7
0
/*
 *  Displays Resources
 *
 *  show all
 *  show <resource-keyword-name>  e.g. show directors
 *  show <resource-keyword-name>=<name> e.g. show director=HeadMan
 *  show disabled    shows disabled jobs
 *
 */
int show_cmd(UAContext *ua, const char *cmd)
{
   int i, j, type, len;
   int recurse;
   char *res_name;
   RES *res = NULL;

   Dmsg1(20, "show: %s\n", ua->UA_sock->msg);

   LockRes();
   for (i=1; i<ua->argc; i++) {
      if (bstrcasecmp(ua->argk[i], _("disabled"))) {
         show_disabled_jobs(ua);
         goto bail_out;
      }
      type = 0;
      res_name = ua->argk[i];
      if (!ua->argv[i]) {             /* was a name given? */
         /* No name, dump all resources of specified type */
         recurse = 1;
         len = strlen(res_name);
         for (j=0; avail_resources[j].res_name; j++) {
            if (bstrncasecmp(res_name, _(avail_resources[j].res_name), len)) {
               type = avail_resources[j].type;
               if (type > 0) {
                  res = res_head[type-r_first];
               } else {
                  res = NULL;
               }
               break;
            }
         }
      } else {
         /* Dump a single resource with specified name */
         recurse = 0;
         len = strlen(res_name);
         for (j=0; avail_resources[j].res_name; j++) {
            if (bstrncasecmp(res_name, _(avail_resources[j].res_name), len)) {
               type = avail_resources[j].type;
               res = (RES *)GetResWithName(type, ua->argv[i]);
               if (!res) {
                  type = -3;
               }
               break;
            }
         }
      }

      switch (type) {
      case -1:                           /* all */
         for (j=r_first; j<=r_last; j++) {
            dump_resource(j, res_head[j-r_first], bsendmsg, ua);
         }
         break;
      case -2:
         ua->send_msg(_("Keywords for the show command are:\n"));
         for (j=0; avail_resources[j].res_name; j++) {
            ua->error_msg("%s\n", _(avail_resources[j].res_name));
         }
         goto bail_out;
      case -3:
         ua->error_msg(_("%s resource %s not found.\n"), res_name, ua->argv[i]);
         goto bail_out;
      case 0:
         ua->error_msg(_("Resource %s not found\n"), res_name);
         goto bail_out;
      default:
         dump_resource(recurse?type:-type, res, bsendmsg, ua);
         break;
      }
   }
bail_out:
   UnlockRes();
   return 1;
}
Beispiel #8
0
/*
 * Parse a gluster definition into something we can use for setting
 * up the right connection to a gluster management server and get access
 * to a gluster volume.
 *
 * Syntax:
 *
 * gluster[+transport]://[server[:port]]/volname[/dir][?socket=...]
 *
 * 'gluster' is the protocol.
 *
 * 'transport' specifies the transport type used to connect to gluster
 * management daemon (glusterd). Valid transport types are tcp, unix
 * and rdma. If a transport type isn't specified, then tcp type is assumed.
 *
 * 'server' specifies the server where the volume file specification for
 * the given volume resides. This can be either hostname, ipv4 address
 * or ipv6 address. ipv6 address needs to be within square brackets [ ].
 * If transport type is 'unix', then 'server' field should not be specifed.
 * The 'socket' field needs to be populated with the path to unix domain
 * socket.
 *
 * 'port' is the port number on which glusterd is listening. This is optional
 * and if not specified, QEMU will send 0 which will make gluster to use the
 * default port. If the transport type is unix, then 'port' should not be
 * specified.
 *
 * 'volname' is the name of the gluster volume which contains the backup images.
 *
 * 'dir' is an optional directory on the 'volname'
 *
 * Examples:
 *
 * gluster://1.2.3.4/testvol[/dir]
 * gluster+tcp://1.2.3.4/testvol[/dir]
 * gluster+tcp://1.2.3.4:24007/testvol[/dir]
 * gluster+tcp://[1:2:3:4:5:6:7:8]/testvol[/dir]
 * gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol[/dir]
 * gluster+tcp://server.domain.com:24007/testvol[/dir]
 * gluster+unix:///testvol[/dir]?socket=/tmp/glusterd.socket
 * gluster+rdma://1.2.3.4:24007/testvol[/dir]
 */
static inline bool parse_gfapi_devicename(char *devicename,
                                          char **transport,
                                          char **servername,
                                          char **volumename,
                                          char **dir,
                                          int *serverport)
{
   char *bp;

   /*
    * Make sure its a URI that starts with gluster.
    */
   if (!bstrncasecmp(devicename, "gluster", 7)) {
      return false;
   }

   /*
    * Parse any explicit protocol.
    */
   bp = strchr(devicename, '+');
   if (bp) {
      *transport = ++bp;
      bp = strchr(bp, ':');
      if (bp) {
         *bp++ = '\0';
      } else {
         goto bail_out;
      }
   } else {
      *transport = NULL;
      bp = strchr(devicename, ':');
      if (!bp) {
         goto bail_out;
      }
   }

   /*
    * When protocol is not UNIX parse servername and portnr.
    */
   if (!*transport || !bstrcasecmp(*transport, "unix")) {
      /*
       * Parse servername of gluster management server.
       */
      bp = strchr(bp, '/');

      /*
       * Validate URI.
       */
      if (!bp || !*bp == '/') {
         goto bail_out;
      }

      /*
       * Skip the two //
       */
      *bp++ = '\0';
      bp++;
      *servername = bp;

      /*
       * Parse any explicit server portnr.
       * We search reverse in the string for a : what indicates
       * a port specification but in that string there may not contain a ']'
       * because then we searching in a IPv6 string.
       */
      bp = strrchr(bp, ':');
      if (bp && !strchr(bp, ']')) {
         char *port;

         *bp++ = '\0';
         port = bp;
         bp = strchr(bp, '/');
         if (!bp) {
            goto bail_out;
         }
         *bp++ = '\0';
         *serverport = str_to_int64(port);
         *volumename = bp;

         /*
          * See if there is a dir specified.
          */
         bp = strchr(bp, '/');
         if (bp) {
            *bp++ = '\0';
            *dir = bp;
         }
      } else {
         *serverport = 0;
         bp = *servername;

         /*
          * Parse the volume name.
          */
         bp = strchr(bp, '/');
         if (!bp) {
            goto bail_out;
         }
         *bp++ = '\0';
         *volumename = bp;

         /*
          * See if there is a dir specified.
          */
         bp = strchr(bp, '/');
         if (bp) {
            *bp++ = '\0';
            *dir = bp;
         }
      }
   } else {
      /*
       * For UNIX serverport is zero.
       */
      *serverport = 0;

      /*
       * Validate URI.
       */
      if (*bp != '/' || *(bp + 1) != '/') {
         goto bail_out;
      }

      /*
       * Skip the two //
       */
      *bp++ = '\0';
      bp++;

      /*
       * For UNIX URIs the server part of the URI needs to be empty.
       */
      if (*bp++ != '/') {
         goto bail_out;
      }
      *volumename = bp;

      /*
       * See if there is a dir specified.
       */
      bp = strchr(bp, '/');
      if (bp) {
         *bp++ = '\0';
         *dir = bp;
      }

      /*
       * Parse any socket parameters.
       */
      bp = strchr(bp, '?');
      if (bp) {
         if (bstrncasecmp(bp + 1, "socket=", 7)) {
            *bp = '\0';
            *servername = bp + 8;
         }
      }
   }

   return true;

bail_out:
   return false;
}
Beispiel #9
0
/*
 * Parse the plugin definition passed in.
 *
 * The definition is in this form:
 *
 * bpipe:file=<filepath>:read=<readprogram>:write=<writeprogram>
 */
static bRC parse_plugin_definition(bpContext *ctx, void *value)
{
   int i, cnt;
   char *plugin_definition, *bp, *argument, *argument_value;
   plugin_ctx *p_ctx = (plugin_ctx *)ctx->pContext;
   bool keep_existing;
   bool compatible = true;

   if (!p_ctx || !value) {
      return bRC_Error;
   }

   keep_existing = (p_ctx->plugin_options) ? true : false;

   /*
    * Parse the plugin definition.
    * Make a private copy of the whole string.
    */
   plugin_definition = bstrdup((char *)value);

   bp = strchr(plugin_definition, ':');
   if (!bp) {
      Jmsg(ctx, M_FATAL, "bpipe-fd: Illegal plugin definition %s\n", plugin_definition);
      Dmsg(ctx, dbglvl, "bpipe-fd: Illegal plugin definition %s\n", plugin_definition);
      goto bail_out;
   }

   /*
    * Skip the first ':'
    */
   bp++;

   /*
    * See if we are parsing a new plugin definition e.g. one with keywords.
    */
   argument = bp;
   while (argument) {
      if (strlen(argument) == 0) {
         break;
      }

      for (i = 0; plugin_arguments[i].name; i++) {
         if (bstrncasecmp(argument, plugin_arguments[i].name, strlen(plugin_arguments[i].name))) {
            compatible = false;
            break;
         }
      }

      if (!plugin_arguments[i].name && !compatible) {
         /*
          * Parsing something fishy ? e.g. partly with known keywords.
          */
         Jmsg(ctx, M_FATAL, "bpipe-fd: Found mixing of old and new syntax, please fix your plugin definition\n", plugin_definition);
         Dmsg(ctx, dbglvl, "bpipe-fd: Found mixing of old and new syntax, please fix your plugin definition\n", plugin_definition);
         goto bail_out;
      }

      argument = strchr(argument, ':');
      if (argument) {
         argument++;
      }
   }

   /*
    * Start processing the definition, if compatible is left set we are pretending that we are
    * parsing a plugin definition in the old syntax and hope for the best.
    */
   cnt = 1;
   while (bp) {
      if (strlen(bp) == 0) {
         break;
      }

      argument = bp;
      if (compatible) {
         char **str_destination = NULL;

         /*
          * See if there are more arguments and setup for the next run.
          */
         do {
            bp = strchr(bp, ':');
            if (bp) {
               if (*(bp - 1) != '\\') {
                  *bp++ = '\0';
                  break;
               } else {
                  bp++;
               }
            }
         } while (bp);

         /*
          * See which field this is in the argument string.
          */
         switch (cnt) {
         case 1:
            str_destination = &p_ctx->fname;
            break;
         case 2:
            str_destination = &p_ctx->reader;
            break;
         case 3:
            str_destination = &p_ctx->writer;
            break;
         default:
            break;
         }

         if (str_destination) {
            if (keep_existing) {
               /*
                * Keep the first value, ignore any next setting.
                */
               set_string_if_null(str_destination, argument);
            } else {
               /*
                * Overwrite any existing value.
                */
               set_string(str_destination, argument);
            }
         }
      } else {
         /*
          * Each argument is in the form:
          *    <argument> = <argument_value>
          *
          * So we setup the right pointers here, argument to the beginning
          * of the argument, argument_value to the beginning of the argument_value.
          */
         argument_value = strchr(bp, '=');
         *argument_value++ = '\0';

         /*
          * See if there are more arguments and setup for the next run.
          */
         bp = argument_value;
         do {
            bp = strchr(bp, ':');
            if (bp) {
               if (*(bp - 1) != '\\') {
                  *bp++ = '\0';
                  break;
               } else {
                  bp++;
               }
            }
         } while (bp);

         for (i = 0; plugin_arguments[i].name; i++) {
            if (bstrncasecmp(argument, plugin_arguments[i].name, plugin_arguments[i].cmp_length)) {
               char **str_destination = NULL;

               switch (plugin_arguments[i].type) {
               case argument_file:
                  str_destination = &p_ctx->fname;
                  break;
               case argument_reader:
                  str_destination = &p_ctx->reader;
                  break;
               case argument_writer:
                  str_destination = &p_ctx->writer;
                  break;
               default:
                  break;
               }

               if (str_destination) {
                  if (keep_existing) {
                     /*
                      * Keep the first value, ignore any next setting.
                      */
                     set_string_if_null(str_destination, argument_value);
                  } else {
                     /*
                      * Overwrite any existing value.
                      */
                     set_string(str_destination, argument_value);
                  }
               }

               /*
                * When we have a match break the loop.
                */
               break;
            }
         }

         /*
          * Got an invalid keyword ?
          */
         if (!plugin_arguments[i].name) {
            Jmsg(ctx, M_FATAL, "bpipe-fd: Illegal argument %s with value %s in plugin definition\n", argument, argument_value);
            Dmsg(ctx, dbglvl, "bpipe-fd: Illegal argument %s with value %s in plugin definition\n", argument, argument_value);
            goto bail_out;
         }
      }
      cnt++;
   }

   free(plugin_definition);
   return bRC_OK;

bail_out:
   free(plugin_definition);
   return bRC_Error;
}