~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

All of the outstanding plugin loader system cleanups:
Libraries know how to load and unload themselves.
Error message constants changed name to be generic.
Plugins dlopen() once and only once and also always dlclose().

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#include "drizzled/error.h"
37
37
#include "drizzled/gettext.h"
38
38
#include "drizzled/errmsg_print.h"
39
 
 
 
39
#include "drizzled/plugin/library.h"
40
40
 
41
41
/* FreeBSD 2.2.2 does not define RTLD_NOW) */
42
42
#ifndef RTLD_NOW
61
61
const char *opt_plugin_load_default= PANDORA_PLUGIN_LIST;
62
62
char *opt_plugin_dir_ptr;
63
63
char opt_plugin_dir[FN_REFLEN];
64
 
static const char *plugin_declarations_sym= "_drizzled_plugin_declaration_";
65
64
 
66
65
/* Note that 'int version' must be the first field of every plugin
67
66
   sub-structure (plugin->info).
69
68
 
70
69
static bool initialized= false;
71
70
 
72
 
static DYNAMIC_ARRAY plugin_dl_array;
73
 
static DYNAMIC_ARRAY module_array;
74
71
 
75
72
static bool reap_needed= false;
76
73
 
155
152
/* prototypes */
156
153
static bool plugin_load_list(plugin::Registry &registry,
157
154
                             MEM_ROOT *tmp_root, int *argc, char **argv,
158
 
                             const char *list);
 
155
                             string plugin_list);
159
156
static int test_plugin_options(MEM_ROOT *, plugin::Module *,
160
157
                               int *, char **);
161
 
static bool register_builtin(plugin::Registry &registry,
162
 
                             plugin::Module *,
163
 
                             plugin::Module **);
164
158
static void unlock_variables(Session *session, struct system_variables *vars);
165
159
static void cleanup_variables(Session *session, struct system_variables *vars);
166
160
static void plugin_vars_free_values(sys_var *vars);
167
161
static void plugin_opt_set_limits(struct my_option *options,
168
162
                                  const struct st_mysql_sys_var *opt);
169
 
static void reap_plugins(plugin::Registry &plugins);
 
163
static void reap_plugins(plugin::Registry &registry);
170
164
 
171
165
 
172
166
/* declared in set_var.cc */
239
233
  Plugin support code
240
234
****************************************************************************/
241
235
 
242
 
static plugin::Library *plugin_dl_find(const LEX_STRING *dl)
243
 
{
244
 
  uint32_t i;
245
 
  plugin::Library *tmp;
246
 
 
247
 
  for (i= 0; i < plugin_dl_array.elements; i++)
248
 
  {
249
 
    tmp= *dynamic_element(&plugin_dl_array, i, plugin::Library **);
250
 
    if (! my_strnncoll(files_charset_info,
251
 
                       (const unsigned char *)dl->str, dl->length,
252
 
                       (const unsigned char *)tmp->dl.str, tmp->dl.length))
253
 
      return(tmp);
254
 
  }
255
 
  return(0);
256
 
}
257
 
 
258
 
static plugin::Library *plugin_dl_insert_or_reuse(plugin::Library *plugin_dl)
259
 
{
260
 
  uint32_t i;
261
 
  plugin::Library *tmp;
262
 
 
263
 
  for (i= 0; i < plugin_dl_array.elements; i++)
264
 
  {
265
 
    tmp= *dynamic_element(&plugin_dl_array, i, plugin::Library **);
266
 
    {
267
 
      memcpy(tmp, plugin_dl, sizeof(plugin::Library));
268
 
      return(tmp);
269
 
    }
270
 
  }
271
 
  if (insert_dynamic(&plugin_dl_array, (unsigned char*)&plugin_dl))
272
 
    return(0);
273
 
  tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
274
 
                        plugin::Library **)=
275
 
      (plugin::Library *) memdup_root(&plugin_mem_root,
276
 
                                      (unsigned char*)plugin_dl,
277
 
                                      sizeof(plugin::Library));
278
 
  return(tmp);
279
 
}
280
 
 
281
 
static inline void free_plugin_mem(plugin::Library *p)
282
 
{
283
 
  if (p->handle)
284
 
    dlclose(p->handle);
285
 
  free(p->dl.str);
286
 
}
287
 
 
288
 
 
289
 
static plugin::Library *plugin_dl_add(const LEX_STRING *dl)
290
 
{
291
 
  string dlpath;
292
 
  uint32_t plugin_dir_len;
293
 
  plugin::Library *tmp, plugin_dl;
294
 
  void *sym;
295
 
  plugin_dir_len= strlen(opt_plugin_dir);
296
 
  dlpath.reserve(FN_REFLEN);
297
 
  /*
298
 
    Ensure that the dll doesn't have a path.
299
 
    This is done to ensure that only approved libraries from the
300
 
    plugin directory are used (to make this even remotely secure).
301
 
  */
302
 
  if (strchr(dl->str, FN_LIBCHAR) ||
303
 
      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
304
 
                               system_charset_info, 1) ||
305
 
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
306
 
  {
307
 
    errmsg_printf(ERRMSG_LVL_ERROR, "%s",ER(ER_UDF_NO_PATHS));
308
 
    return NULL;
309
 
  }
310
 
  /* If this dll is already loaded just increase ref_count. */
311
 
  if ((tmp= plugin_dl_find(dl)))
312
 
  {
313
 
    return(tmp);
314
 
  }
315
 
  memset(&plugin_dl, 0, sizeof(plugin_dl));
316
 
  /* Compile dll path */
317
 
  dlpath.append(opt_plugin_dir);
318
 
  dlpath.append("/");
319
 
  dlpath.append("lib");
320
 
  dlpath.append(dl->str);
321
 
  dlpath.append("_plugin.so");
322
 
  /* Open new dll handle */
323
 
  if (!(plugin_dl.handle= dlopen(dlpath.c_str(), RTLD_NOW|RTLD_GLOBAL)))
324
 
  {
325
 
    const char *errmsg= dlerror();
326
 
    uint32_t dlpathlen= dlpath.length();
327
 
    if (!dlpath.compare(0, dlpathlen, errmsg))
328
 
    { // if errmsg starts from dlpath, trim this prefix.
329
 
      errmsg+=dlpathlen;
330
 
      if (*errmsg == ':') errmsg++;
331
 
      if (*errmsg == ' ') errmsg++;
332
 
    }
333
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_OPEN_LIBRARY), dlpath.c_str(), errno, errmsg);
334
 
 
335
 
    // This is, in theory, should cause dlerror() to deallocate the error
336
 
    // message. Found this via Google'ing :)
337
 
    (void)dlerror();
338
 
 
339
 
    return NULL;
340
 
  }
341
 
 
342
 
  /* Find plugin declarations */
343
 
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
344
 
  {
345
 
    free_plugin_mem(&plugin_dl);
346
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
347
 
    return NULL;
348
 
  }
349
 
 
350
 
  plugin_dl.plugins= static_cast<plugin::Manifest *>(sym);
351
 
 
352
 
  /* Duplicate and convert dll name */
353
 
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
354
 
  if (! (plugin_dl.dl.str= (char*) calloc(plugin_dl.dl.length, sizeof(char))))
355
 
  {
356
 
    free_plugin_mem(&plugin_dl);
357
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
358
 
    return NULL;
359
 
  }
360
 
  strcpy(plugin_dl.dl.str, dl->str);
361
 
  /* Add this dll to array */
362
 
  if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
363
 
  {
364
 
    free_plugin_mem(&plugin_dl);
365
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY),
366
 
                  sizeof(plugin::Library));
367
 
    return NULL;
368
 
  }
369
 
  return(tmp);
370
 
}
371
 
 
372
 
 
373
 
static void plugin_dl_del(const LEX_STRING *dl)
374
 
{
375
 
  uint32_t i;
376
 
 
377
 
  for (i= 0; i < plugin_dl_array.elements; i++)
378
 
  {
379
 
    plugin::Library *tmp= *dynamic_element(&plugin_dl_array, i,
380
 
                                           plugin::Library **);
381
 
    if (! my_strnncoll(files_charset_info,
382
 
                       (const unsigned char *)dl->str, dl->length,
383
 
                       (const unsigned char *)tmp->dl.str, tmp->dl.length))
384
 
    {
385
 
      /* Do not remove this element, unless no other plugin uses this dll. */
386
 
      {
387
 
        free_plugin_mem(tmp);
388
 
        memset(tmp, 0, sizeof(plugin::Library));
389
 
      }
390
 
      break;
391
 
    }
392
 
  }
393
 
  return;
394
 
}
395
 
 
396
 
 
397
 
 
398
 
static plugin::Module *plugin_insert_or_reuse(plugin::Module *module)
399
 
{
400
 
  if (insert_dynamic(&module_array, (unsigned char*)&module))
401
 
    return NULL;
402
 
  module= *dynamic_element(&module_array, module_array.elements - 1,
403
 
                           plugin::Module **);
404
 
  return module;
405
 
}
 
236
 
406
237
 
407
238
 
408
239
/*
410
241
    Requires that a write-lock is held on LOCK_system_variables_hash
411
242
*/
412
243
static bool plugin_add(plugin::Registry &registry, MEM_ROOT *tmp_root,
413
 
                       const LEX_STRING *name, const LEX_STRING *dl,
 
244
                       plugin::Library *library,
414
245
                       int *argc, char **argv)
415
246
{
416
 
  plugin::Manifest *manifest;
417
247
  if (! initialized)
418
 
    return(0);
 
248
    return true;
419
249
 
420
 
  if (registry.find(name))
 
250
  if (registry.find(library->getName()))
421
251
  {
422
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UDF_EXISTS), name->str);
423
 
    return(true);
 
252
    errmsg_printf(ERRMSG_LVL_WARN, ER(ER_PLUGIN_EXISTS),
 
253
                  library->getName().c_str());
 
254
    return false;
424
255
  }
425
 
  plugin::Library *library= plugin_dl_add(dl);
426
 
  if (library == NULL)
427
 
    return true;
428
256
 
429
257
  plugin::Module *tmp= NULL;
430
258
  /* Find plugin by name */
431
 
  for (manifest= library->plugins; manifest->name; manifest++)
 
259
  const plugin::Manifest *manifest= library->getManifest();
 
260
 
 
261
  tmp= new (std::nothrow) plugin::Module(manifest, library);
 
262
  if (tmp == NULL)
 
263
    return true;
 
264
 
 
265
  if (!test_plugin_options(tmp_root, tmp, argc, argv))
432
266
  {
433
 
    if (! my_strnncoll(system_charset_info,
434
 
                       (const unsigned char *)name->str, name->length,
435
 
                       (const unsigned char *)manifest->name,
436
 
                       strlen(manifest->name)))
437
 
    {
438
 
      tmp= new (std::nothrow) plugin::Module(manifest, library);
439
 
      if (tmp == NULL)
440
 
        return true;
441
 
 
442
 
      if (!test_plugin_options(tmp_root, tmp, argc, argv))
443
 
      {
444
 
        if ((tmp= plugin_insert_or_reuse(tmp)))
445
 
        {
446
 
          registry.add(tmp);
447
 
          init_alloc_root(&tmp->mem_root, 4096, 4096);
448
 
          return(false);
449
 
        }
450
 
        mysql_del_sys_var_chain(tmp->system_vars);
451
 
        goto err;
452
 
      }
453
 
      /* plugin was disabled */
454
 
      plugin_dl_del(dl);
455
 
      return(false);
456
 
    }
 
267
    registry.add(tmp);
 
268
    init_alloc_root(&tmp->mem_root, 4096, 4096);
 
269
    return false;
457
270
  }
458
 
  errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY), name->str);
459
 
err:
460
 
  plugin_dl_del(dl);
461
 
  return(true);
 
271
  errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY),
 
272
                library->getName().c_str());
 
273
  return true;
462
274
}
463
275
 
464
276
 
479
291
 
480
292
  /* Free allocated strings before deleting the plugin. */
481
293
  plugin_vars_free_values(module->system_vars);
482
 
  if (module->plugin_dl)
483
 
    plugin_dl_del(&module->plugin_dl->dl);
484
294
  module->isInited= false;
485
295
  pthread_rwlock_wrlock(&LOCK_system_variables_hash);
486
296
  mysql_del_sys_var_chain(module->system_vars);
488
298
  delete module;
489
299
}
490
300
 
491
 
static void reap_plugins(plugin::Registry &plugins)
 
301
 
 
302
static void reap_plugins(plugin::Registry &registry)
492
303
{
493
 
  size_t count;
494
 
  uint32_t idx;
495
304
  plugin::Module *module;
496
305
 
497
 
  count= module_array.elements;
498
 
 
499
 
  for (idx= 0; idx < count; idx++)
 
306
  std::map<std::string, plugin::Module *>::const_iterator modules=
 
307
    registry.getModulesMap().begin();
 
308
    
 
309
  while (modules != registry.getModulesMap().end())
500
310
  {
501
 
    module= *dynamic_element(&module_array, idx, plugin::Module **);
502
 
    delete_module(plugins, module);
 
311
    module= (*modules).second;
 
312
    delete_module(registry, module);
 
313
    ++modules;
503
314
  }
504
315
  drizzle_del_plugin_sysvar();
505
316
}
574
385
*/
575
386
int plugin_init(plugin::Registry &registry, int *argc, char **argv, int flags)
576
387
{
577
 
  uint32_t idx;
578
388
  plugin::Manifest **builtins;
579
389
  plugin::Manifest *manifest;
580
390
  plugin::Module *module;
588
398
 
589
399
  if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
590
400
                  get_bookmark_hash_key, NULL, HASH_UNIQUE))
591
 
      goto err;
592
 
 
593
 
 
594
 
  if (my_init_dynamic_array(&plugin_dl_array,
595
 
                            sizeof(plugin::Library *),16,16) ||
596
 
      my_init_dynamic_array(&module_array,
597
 
                            sizeof(plugin::Module *),16,16))
598
 
    goto err;
 
401
  {
 
402
    free_root(&tmp_root, MYF(0));
 
403
    return(1);
 
404
  }
 
405
 
599
406
 
600
407
  initialized= 1;
601
408
 
614
421
      if (test_plugin_options(&tmp_root, module, argc, argv))
615
422
        continue;
616
423
 
617
 
      if (register_builtin(registry, module, &module))
618
 
        goto err_unlock;
 
424
      registry.add(module);
619
425
 
620
426
      plugin_initialize_vars(module);
621
427
 
622
428
      if (! (flags & PLUGIN_INIT_SKIP_INITIALIZATION))
623
429
      {
624
430
        if (plugin_initialize(registry, module))
625
 
          goto err_unlock;
 
431
        {
 
432
          free_root(&tmp_root, MYF(0));
 
433
          return(1);
 
434
        }
626
435
      }
627
436
    }
628
437
  }
643
452
        tmp_plugin_list.push_back(',');
644
453
        tmp_plugin_list.append(opt_plugin_add);
645
454
      }
646
 
      plugin_load_list(registry, &tmp_root, argc, argv, tmp_plugin_list.c_str());
 
455
      plugin_load_list(registry, &tmp_root, argc, argv, tmp_plugin_list);
647
456
    }
648
457
  }
649
458
 
650
459
  if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
651
 
    goto end;
 
460
  {
 
461
    free_root(&tmp_root, MYF(0));
 
462
    return(0);
 
463
  }
652
464
 
653
465
  /*
654
466
    Now we initialize all remaining plugins
655
467
  */
656
 
  for (idx= 0; idx < module_array.elements; idx++)
 
468
  std::map<std::string, plugin::Module *>::const_iterator modules=
 
469
    registry.getModulesMap().begin();
 
470
    
 
471
  while (modules != registry.getModulesMap().end())
657
472
  {
658
 
    module= *dynamic_element(&module_array, idx, plugin::Module **);
 
473
    module= (*modules).second;
 
474
    ++modules;
659
475
    if (module->isInited == false)
660
476
    {
661
477
      plugin_initialize_vars(module);
666
482
  }
667
483
 
668
484
 
669
 
end:
670
 
  free_root(&tmp_root, MYF(0));
671
 
 
672
 
  return(0);
673
 
 
674
 
err_unlock:
675
 
err:
676
 
  free_root(&tmp_root, MYF(0));
677
 
  return(1);
678
 
}
679
 
 
680
 
 
681
 
static bool register_builtin(plugin::Registry &registry,
682
 
                             plugin::Module *tmp,
683
 
                             plugin::Module **ptr)
684
 
{
685
 
 
686
 
  tmp->isInited= false;
687
 
  tmp->plugin_dl= 0;
688
 
 
689
 
  if (insert_dynamic(&module_array, (unsigned char*)&tmp))
690
 
    return(1);
691
 
 
692
 
  *ptr= *dynamic_element(&module_array, module_array.elements - 1,
693
 
                         plugin::Module **);
694
 
 
695
 
  registry.add(*ptr);
696
 
 
697
 
  return(0);
698
 
}
 
485
  free_root(&tmp_root, MYF(0));
 
486
 
 
487
  return(0);
 
488
}
 
489
 
699
490
 
700
491
 
701
492
/*
702
493
  called only by plugin_init()
703
494
*/
704
 
static bool plugin_load_list(plugin::Registry &plugins,
 
495
static bool plugin_load_list(plugin::Registry &registry,
705
496
                             MEM_ROOT *tmp_root, int *argc, char **argv,
706
 
                             const char *list)
 
497
                             string plugin_list)
707
498
{
708
 
  char buffer[FN_REFLEN];
709
 
  LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
710
 
  plugin::Library *plugin_dl;
711
 
  plugin::Manifest *plugin;
712
 
  char *p= buffer;
713
 
  while (list)
 
499
  plugin::Library *library= NULL;
 
500
 
 
501
  const string DELIMITER(",");
 
502
  string::size_type last_pos= plugin_list.find_first_not_of(DELIMITER);
 
503
  string::size_type pos= plugin_list.find_first_of(DELIMITER, last_pos);
 
504
  while (string::npos != pos || string::npos != last_pos)
714
505
  {
715
 
    if (p == buffer + sizeof(buffer) - 1)
716
 
    {
717
 
      errmsg_printf(ERRMSG_LVL_ERROR, _("plugin-load parameter too long"));
718
 
      return(true);
719
 
    }
720
 
 
721
 
    switch ((*(p++)= *(list++))) {
722
 
    case '\0':
723
 
      list= NULL; /* terminate the loop */
724
 
      /* fall through */
725
 
    case ':':     /* can't use this as delimiter as it may be drive letter */
726
 
    case ',':
727
 
      str->str[str->length]= '\0';
728
 
      if (str == &name)  // load all plugins in named module
729
 
      {
730
 
        if (!name.length)
731
 
        {
732
 
          p--;    /* reset pointer */
733
 
          continue;
734
 
        }
735
 
 
736
 
        dl= name;
737
 
        if ((plugin_dl= plugin_dl_add(&dl)))
738
 
        {
739
 
          for (plugin= plugin_dl->plugins; plugin->name; plugin++)
740
 
          {
741
 
            name.str= (char *) plugin->name;
742
 
            name.length= strlen(name.str);
743
 
 
744
 
            free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
745
 
            if (plugin_add(plugins, tmp_root, &name, &dl, argc, argv))
746
 
              goto error;
747
 
          }
748
 
          plugin_dl_del(&dl); // reduce ref count
749
 
        }
750
 
      }
751
 
      else
752
 
      {
753
 
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
754
 
        if (plugin_add(plugins, tmp_root, &name, &dl, argc, argv))
755
 
          goto error;
756
 
      }
757
 
      name.length= dl.length= 0;
758
 
      dl.str= NULL; name.str= p= buffer;
759
 
      str= &name;
760
 
      continue;
761
 
    case '=':
762
 
    case '#':
763
 
      if (str == &name)
764
 
      {
765
 
        name.str[name.length]= '\0';
766
 
        str= &dl;
767
 
        str->str= p;
768
 
        continue;
769
 
      }
770
 
    default:
771
 
      str->length++;
772
 
      continue;
773
 
    }
 
506
    const string plugin_name(plugin_list.substr(last_pos, pos - last_pos));
 
507
 
 
508
    library= registry.addLibrary(plugin_name);
 
509
    if (library == NULL)
 
510
    {
 
511
      errmsg_printf(ERRMSG_LVL_ERROR,
 
512
                    _("Couldn't load plugin library named '%s'."),
 
513
                    plugin_name.c_str());
 
514
      return true;
 
515
    }
 
516
 
 
517
    free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
518
    if (plugin_add(registry, tmp_root, library, argc, argv))
 
519
    {
 
520
      registry.removeLibrary(plugin_name);
 
521
      errmsg_printf(ERRMSG_LVL_ERROR,
 
522
                    _("Couldn't load plugin named '%s'."),
 
523
                    plugin_name.c_str());
 
524
      return true;
 
525
 
 
526
    }
 
527
    last_pos= plugin_list.find_first_not_of(DELIMITER, pos);
 
528
    pos= plugin_list.find_first_of(DELIMITER, last_pos);
774
529
  }
775
 
  return(false);
776
 
error:
777
 
  errmsg_printf(ERRMSG_LVL_ERROR, _("Couldn't load plugin named '%s' with soname '%s'."),
778
 
                  name.str, dl.str);
779
 
  return(true);
 
530
  return false;
780
531
}
781
532
 
782
533
 
783
534
void plugin_shutdown(plugin::Registry &registry)
784
535
{
785
 
  uint32_t idx;
786
 
  size_t count= module_array.elements;
787
 
  vector<plugin::Library *> dl;
788
536
 
789
537
  if (initialized)
790
538
  {
802
550
 
803
551
  /* Dispose of the memory */
804
552
 
805
 
  delete_dynamic(&module_array);
806
 
 
807
 
  count= plugin_dl_array.elements;
808
 
  dl.reserve(count);
809
 
  for (idx= 0; idx < count; idx++)
810
 
    dl.push_back(*dynamic_element(&plugin_dl_array, idx,
811
 
                 plugin::Library **));
812
 
  for (idx= 0; idx < count; idx++)
813
 
    free_plugin_mem(dl[idx]);
814
 
  delete_dynamic(&plugin_dl_array);
815
 
 
816
553
  hash_free(&bookmark_hash);
817
554
  free_root(&plugin_mem_root, MYF(0));
818
555
 
2281
2018
 
2282
2019
void my_print_help_inc_plugins(my_option *main_options)
2283
2020
{
 
2021
  plugin::Registry &registry= plugin::Registry::singleton();
2284
2022
  vector<my_option> all_options;
2285
2023
  plugin::Module *p;
2286
2024
  MEM_ROOT mem_root;
2289
2027
  init_alloc_root(&mem_root, 4096, 4096);
2290
2028
 
2291
2029
  if (initialized)
2292
 
    for (uint32_t idx= 0; idx < module_array.elements; idx++)
 
2030
  {
 
2031
    std::map<std::string, plugin::Module *>::const_iterator modules=
 
2032
      registry.getModulesMap().begin();
 
2033
    
 
2034
    while (modules != registry.getModulesMap().end())
2293
2035
    {
2294
 
      p= *dynamic_element(&module_array, idx, plugin::Module **);
 
2036
      p= (*modules).second;
 
2037
      ++modules;
2295
2038
 
2296
2039
      if (p->getManifest().system_vars == NULL)
2297
2040
        continue;
2310
2053
        }
2311
2054
      }
2312
2055
    }
 
2056
  }
2313
2057
 
2314
2058
  for (;main_options->id; main_options++)
2315
2059
  {