1/* Copyright (C) 2021 Free Software Foundation, Inc. 2 Contributed by Oracle. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21#include "config.h" 22#include <ctype.h> 23#include <errno.h> 24#include <unistd.h> 25#include <getopt.h> 26 27#include "util.h" 28#include "StringMap.h" 29#include "LoadObject.h" 30#include "DbeSession.h" 31#include "DbeFile.h" 32#include "SourceFile.h" 33#include "Elf.h" 34#include "gp-archive.h" 35#include "ArchiveExp.h" 36#include "Print.h" 37#include "Module.h" 38 39er_archive::er_archive (int argc, char *argv[]) : DbeApplication (argc, argv) 40{ 41 force = 0; 42 common_archive_dir = NULL; 43 quiet = 0; 44 descendant = 1; 45 use_relative_path = 0; 46 s_option = ARCH_EXE_ONLY; 47 mask = NULL; 48} 49 50er_archive::~er_archive () 51{ 52 if (mask) 53 { 54 for (long i = 0, sz = mask->size (); i < sz; i++) 55 { 56 regex_t *regex_desc = mask->get (i); 57 regfree (regex_desc); 58 delete regex_desc; 59 } 60 delete mask; 61 } 62 delete common_archive_dir; 63} 64 65int 66er_archive::mask_is_on (const char *str) 67{ 68 if (mask == NULL) 69 return 1; 70 for (long i = 0, sz = mask->size (); i < sz; i++) 71 { 72 regex_t *regex_desc = mask->get (i); 73 if (regexec (regex_desc, str, 0, NULL, 0) == 0) 74 return 1; 75 } 76 return 0; 77} 78 79void 80er_archive::usage () 81{ 82/* 83 fprintf (stderr, GTXT ("Usage: %s [-nqFV] [-a on|ldobjects|src|usedldobjects|usedsrc|off] [-m regexp] experiment\n"), whoami); 84*/ 85 86/* 87 Ruud - Isolate this line because it has an argument. Otherwise it would be at the 88 end of this long list. 89*/ 90 printf ( GTXT ( 91 "Usage: gprofng archive [OPTION(S)] EXPERIMENT\n")); 92 93 printf ( GTXT ( 94 "\n" 95 "Archive the associated application binaries and source files in a gprofng\n" 96 "experiment to make it self contained and portable.\n" 97 "\n" 98 "Options:\n" 99 "\n" 100 " --version print the version number and exit.\n" 101 " --help print usage information and exit.\n" 102 " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n" 103 "\n" 104 " -a {off|on|ldobjects|src|usedldobjects|usedsrc} specify archiving of binaries and other files;\n" 105 " in addition to disable this feature (off), or enable archiving off all\n" 106 " loadobjects and sources (on), the other options support a more\n" 107 " refined selection. All of these options enable archiving, but the\n" 108 " keyword controls what exactly is selected: all load objects (ldobjects),\n" 109 " all source files (src), the loadobjects asscoiated with a program counter\n" 110 " (usedldobjects), or the source files associated with a program counter\n" 111 " (usedsrc); the default is \"-a ldobjects\".\n" 112 "\n" 113 " -n archive the named experiment only, not any of its descendants.\n" 114 "\n" 115 " -q do not write any warnings to stderr; messages are archived and\n" 116 " can be retrieved later.\n" 117 "\n" 118 " -F force writing or rewriting of the archive; ignored with the -n\n" 119 " or -m options, or if this is a subexperiment.\n" 120 "\n" 121 " -d <path> specifies the location of a common archive; this is a directory that\n" 122 " contains archived files.\n" 123 "\n" 124 " -m <regex> archive only those source, object, and debug info files whose full\n" 125 " path name matches the given POSIX compliant regular expression.\n" 126 "\n" 127 "Limitations:\n" 128 "\n" 129 "Default archiving does not occur in case the application profiled terminates prematurely,\n" 130 "or if archiving is disabled when collecting the performance data. In such cases, this\n" 131 "tool can be used to afterwards archive the information, but it has to run on the same \n" 132 "system where the profiling data was recorded.\n" 133 "\n" 134 "Documentation:\n" 135 "\n" 136 "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n" 137 "gprofng programs are properly installed at your site, the command \"info gprofng\"\n" 138 "should give you access to this document.\n" 139 "\n" 140 "See also:\n" 141 "\n" 142 "gprofng(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n")); 143// Ruud 144/* 145 fprintf (stderr, GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION); 146*/ 147 exit (1); 148} 149 150Vector <LoadObject*> * 151er_archive::get_loadObjs () 152{ 153 Vector <LoadObject*> *objs = new Vector<LoadObject*>(); 154 Vector <LoadObject*> *loadObjs = dbeSession->get_text_segments (); 155 if (s_option != ARCH_NOTHING) 156 { 157 for (long i = 0, sz = VecSize(loadObjs); i < sz; i++) 158 { 159 LoadObject *lo = loadObjs->get (i); 160 if ((lo->flags & SEG_FLAG_DYNAMIC) != 0) 161 continue; 162 DbeFile *df = lo->dbeFile; 163 if (df && ((df->filetype & DbeFile::F_FICTION) != 0)) 164 continue; 165 if (!lo->isUsed && ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0)) 166 continue; 167 objs->append (lo); 168 } 169 } 170 if (DEBUG_ARCHIVE) 171 { 172 Dprintf (DEBUG_ARCHIVE, NTXT ("get_text_segments(): %d\n"), 173 (int) (loadObjs ? loadObjs->size () : -1)); 174 for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++) 175 { 176 LoadObject *lo = loadObjs->get (i); 177 Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d [%2ld] %s\n"), 178 get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ())); 179 } 180 Dprintf (DEBUG_ARCHIVE, NTXT ("\nget_loadObjs(): %d\n"), 181 (int) (objs ? objs->size () : -1)); 182 for (long i = 0, sz = VecSize(objs); i < sz; i++) 183 { 184 LoadObject *lo = objs->get (i); 185 Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d [%2ld] %s\n"), 186 get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ())); 187 } 188 } 189 delete loadObjs; 190 return objs; 191} 192 193/** 194 * Clean old archive 195 * Except the following cases: 196 * 1. Founder experiment is an MPI experiment 197 * 2. "-n" option is passed (do not archive descendants) 198 * 3. "-m" option is passed (partial archiving) 199 * 4. Experiment name is not the founder experiment (it is a sub-experiment) 200 * @param expname 201 * @param founder_exp 202 * @return 0 - success 203 */ 204int 205er_archive::clean_old_archive (char *expname, ArchiveExp *founder_exp) 206{ 207 if (0 == descendant) 208 { // do not archive descendants 209 fprintf (stderr, GTXT ("Warning: Option -F is ignored because -n option is specified (do not archive descendants)\n")); 210 return 1; 211 } 212 if (NULL != mask) 213 { // partial archiving 214 fprintf (stderr, GTXT ("Warning: Option -F is ignored because -m option is specified\n")); 215 return 1; 216 } 217 // Check if the experiment is the founder 218 char *s1 = dbe_strdup (expname); 219 char *s2 = dbe_strdup (founder_exp->get_expt_name ()); 220 if (!s1 || !s2) 221 { 222 fprintf (stderr, GTXT ("Cannot allocate memory\n")); 223 exit (1); 224 } 225 // remove trailing slashes 226 for (int n = strlen (s1); n > 0; n--) 227 { 228 if ('/' != s1[n - 1]) 229 break; 230 s1[n - 1] = 0; 231 } 232 for (int n = strlen (s2); n > 0; n--) 233 { 234 if ('/' != s2[n - 1]) 235 break; 236 s2[n - 1] = 0; 237 } 238 if (strcmp (s1, s2) != 0) 239 { // not founder 240 fprintf (stderr, GTXT ("Warning: Option -F is ignored because specified experiment name %s does not match founder experiment name %s\n"), s1, s2); 241 free (s1); 242 free (s2); 243 return 1; 244 } 245 // Remove old "archives" 246 char *arch = founder_exp->get_arch_name (); 247 fprintf (stderr, GTXT ("INFO: removing existing archive: %s\n"), arch); 248 if (dbe_stat (arch, NULL) == 0) 249 { 250 char *cmd = dbe_sprintf ("/bin/rm -rf %s", arch); 251 system (cmd); 252 free (cmd); 253 if (dbe_stat (arch, NULL) != 0) 254 { // create "archives" 255 if (!founder_exp->create_dir (founder_exp->get_arch_name ())) 256 { 257 fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ()); 258 exit (1); 259 } 260 } 261 } 262 free (s1); 263 free (s2); 264 return 0; 265} // clean_old_archive_if_necessary 266 267void 268er_archive::start (int argc, char *argv[]) 269{ 270 int last = argc - 1; 271 if (check_args (argc, argv) != last) 272 usage (); 273 check_env_var (); 274 if (s_option == ARCH_NOTHING) 275 return; 276 277 ArchiveExp *founder_exp = new ArchiveExp (argv[last]); 278 if (founder_exp->get_status () == Experiment::FAILURE) 279 { 280 if (!quiet) 281 fprintf (stderr, GTXT ("er_archive: %s: %s\n"), argv[last], 282 pr_mesgs (founder_exp->fetch_errors (), NTXT (""), NTXT (""))); 283 exit (1); 284 } 285 if (!founder_exp->create_dir (founder_exp->get_arch_name ())) 286 { 287 fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ()); 288 exit (1); 289 } 290 if (!common_archive_dir) 291 common_archive_dir = dbe_strdup (getenv ("GPROFNG_ARCHIVE_COMMON_DIR")); 292 if (common_archive_dir) 293 { 294 if (!founder_exp->create_dir (common_archive_dir)) 295 if (dbe_stat (common_archive_dir, NULL) != 0) 296 { 297 fprintf (stderr, GTXT ("Unable to create directory for common archive `%s'\n"), common_archive_dir); 298 exit (1); 299 } 300 } 301 // Clean old archives if necessary 302 if (force) 303 clean_old_archive (argv[last], founder_exp); 304 Vector<ArchiveExp*> *exps = new Vector<ArchiveExp*>(); 305 exps->append (founder_exp); 306 if (descendant) 307 { 308 Vector<char*> *exp_names = founder_exp->get_descendants_names (); 309 if (exp_names) 310 { 311 for (long i = 0, sz = exp_names->size (); i < sz; i++) 312 { 313 char *exp_path = exp_names->get (i); 314 ArchiveExp *exp = new ArchiveExp (exp_path); 315 if (exp->get_status () == Experiment::FAILURE) 316 { 317 if (!quiet) 318 fprintf (stderr, GTXT ("er_archive: %s: %s\n"), exp_path, 319 pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT (""))); 320 delete exp; 321 continue; 322 } 323 exps->append (exp); 324 } 325 exp_names->destroy (); 326 delete exp_names; 327 } 328 } 329 for (long i = 0, sz = exps->size (); i < sz; i++) 330 { 331 ArchiveExp *exp = exps->get (i); 332 exp->read_data (s_option); 333 } 334 335 Vector <DbeFile*> *copy_files = new Vector<DbeFile*>(); 336 Vector <LoadObject*> *loadObjs = get_loadObjs (); 337 for (long i = 0, sz = VecSize(loadObjs); i < sz; i++) 338 { 339 LoadObject *lo = loadObjs->get (i); 340 if (strcmp (lo->get_pathname (), "LinuxKernel") == 0) 341 continue; 342 DbeFile *df = lo->dbeFile; 343 if ((df->filetype & DbeFile::F_FICTION) != 0) 344 continue; 345 if (df->get_location () == NULL) 346 { 347 copy_files->append (df); 348 continue; 349 } 350 if ((df->filetype & DbeFile::F_JAVACLASS) != 0) 351 { 352 if (df->container) 353 { // Found in .jar file 354 copy_files->append (df->container); 355 } 356 copy_files->append (df); 357 if ((s_option & ARCH_EXE_ONLY) != 0) 358 continue; 359 } 360 lo->sync_read_stabs (); 361 Elf *elf = lo->get_elf (); 362 if (elf && (lo->checksum != 0) && (lo->checksum != elf->elf_checksum ())) 363 { 364 if (!quiet) 365 fprintf (stderr, GTXT ("er_archive: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored\n"), 366 df->get_location ()); 367 continue; 368 } 369 copy_files->append (df); 370 if (elf) 371 { 372 Elf *f = elf->find_ancillary_files (lo->get_pathname ()); 373 if (f) 374 copy_files->append (f->dbeFile); 375 for (long i1 = 0, sz1 = VecSize(elf->ancillary_files); i1 < sz1; i1++) 376 { 377 Elf *ancElf = elf->ancillary_files->get (i1); 378 copy_files->append (ancElf->dbeFile); 379 } 380 } 381 Vector<Module*> *modules = lo->seg_modules; 382 for (long i1 = 0, sz1 = VecSize(modules); i1 < sz1; i1++) 383 { 384 Module *mod = modules->get (i1); 385 if ((mod->flags & MOD_FLAG_UNKNOWN) != 0) 386 continue; 387 else if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0 && 388 !mod->isUsed) 389 continue; 390 if ((s_option & ARCH_ALL) != 0) 391 mod->read_stabs (false); // Find all Sources 392 if (mod->dot_o_file && mod->dot_o_file->dbeFile) 393 copy_files->append (mod->dot_o_file->dbeFile); 394 } 395 } 396 delete loadObjs; 397 398 int bmask = DbeFile::F_LOADOBJ | DbeFile::F_JAVACLASS | DbeFile::F_JAR_FILE | 399 DbeFile::F_DOT_O | DbeFile::F_DEBUG_FILE; 400 if ((s_option & (ARCH_USED_SRC_ONLY | ARCH_ALL)) != 0) 401 { 402 bmask |= DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE; 403 Vector<SourceFile*> *sources = dbeSession->get_sources (); 404 for (long i = 0, sz = VecSize(sources); i < sz; i++) 405 { 406 SourceFile *src = sources->get (i); 407 if ((src->flags & SOURCE_FLAG_UNKNOWN) != 0) 408 continue; 409 else if ((s_option & ARCH_USED_SRC_ONLY) != 0) 410 { 411 if ((src->dbeFile->filetype & DbeFile::F_JAVA_SOURCE) != 0 && 412 !src->isUsed) 413 continue; 414 } 415 if (src->dbeFile) 416 copy_files->append (src->dbeFile); 417 } 418 } 419 420 Vector <DbeFile*> *notfound_files = new Vector<DbeFile*>(); 421 for (long i = 0, sz = VecSize(copy_files); i < sz; i++) 422 { 423 DbeFile *df = copy_files->get (i); 424 char *fnm = df->get_location (); 425 char *nm = df->get_name (); 426 Dprintf (DEBUG_ARCHIVE, 427 "%s::%d copy_files[%ld] filetype=%4d inArchive=%d '%s' --> '%s'\n", 428 get_basename (__FILE__), (int) __LINE__, i, 429 df->filetype, df->inArchive ? 1 : 0, STR (nm), STR (fnm)); 430 Dprintf (DEBUG_ARCHIVE && df->container, 431 " copy_files[%ld]: Found '%s' in '%s'\n", 432 i, STR (nm), STR (df->container->get_name ())); 433 if (fnm == NULL) 434 { 435 if (!quiet) 436 notfound_files->append (df); 437 continue; 438 } 439 else if (df->inArchive) 440 { 441 Dprintf (DEBUG_ARCHIVE, 442 " NOT COPIED: copy_files[%ld]: inArchive=1 '%s'\n", 443 i, STR (nm)); 444 continue; 445 } 446 else if ((df->filetype & bmask) == 0) 447 { 448 Dprintf (DEBUG_ARCHIVE, 449 " NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n", 450 i, df->container, df->filetype, bmask, STR (nm)); 451 continue; 452 } 453 else if (df->container && 454 (df->filetype & (DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE)) == 0) 455 { 456 Dprintf (DEBUG_ARCHIVE, 457 " NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n", 458 i, df->container, df->filetype, bmask, STR (nm)); 459 continue; 460 } 461 else if (!mask_is_on (df->get_name ())) 462 { 463 Dprintf (DEBUG_ARCHIVE, 464 " NOT COPIED: copy_files[%ld]: mask is off for '%s'\n", 465 i, STR (nm)); 466 continue; 467 } 468 char *anm = founder_exp->getNameInArchive (nm, false); 469 if (force) 470 unlink (anm); 471 int res = founder_exp->copy_file (fnm, anm, quiet, common_archive_dir, use_relative_path); 472 if (0 == res) // file successfully archived 473 df->inArchive = 1; 474 delete anm; 475 } 476 delete copy_files; 477 478 if (notfound_files->size () > 0) 479 { 480 for (long i = 0, sz = notfound_files->size (); i < sz; i++) 481 { 482 DbeFile *df = notfound_files->get (i); 483 fprintf (stderr, GTXT ("er_archive: Cannot find file: `%s'\n"), df->get_name ()); 484 } 485 fprintf (stderr, GTXT ("\n If you know the correct location of the missing file(s)" 486 " you can help %s to find them by manually editing the .gprofng.rc file." 487 " See %s man pages for more details.\n"), 488 whoami, whoami); 489 } 490 delete notfound_files; 491} 492 493int 494er_archive::check_args (int argc, char *argv[]) 495{ 496 int opt; 497 int rseen = 0; 498 int dseen = 0; 499 // Parsing the command line 500 opterr = 0; 501 optind = 1; 502 static struct option long_options[] = { 503 {"help", no_argument, 0, 'h'}, 504 {"version", no_argument, 0, 'V'}, 505 {"whoami", required_argument, 0, 'w'}, 506 {"outfile", required_argument, 0, 'O'}, 507 {NULL, 0, 0, 0} 508 }; 509 while (1) 510 { 511 int option_index = 0; 512 opt = getopt_long (argc, argv, NTXT (":VFa:d:qnr:m:"), 513 long_options, &option_index); 514 if (opt == EOF) 515 break; 516 switch (opt) 517 { 518 case 'F': 519 force = 1; 520 break; 521 case 'd': // Common archive directory (absolute path) 522 if (rseen) 523 { 524 fprintf (stderr, GTXT ("Error: invalid combination of options: -r and -d are in conflict.\n")); 525 return -1; 526 } 527 if (dseen) 528 fprintf (stderr, GTXT ("Warning: option -d was specified several times. Last value is used.\n")); 529 free (common_archive_dir); 530 common_archive_dir = strdup (optarg); 531 dseen = 1; 532 break; 533 case 'q': 534 quiet = 1; 535 break; 536 case 'n': 537 descendant = 0; 538 break; 539 case 'r': // Common archive directory (relative path) 540 if (dseen) 541 { 542 fprintf (stderr, GTXT ("Error: invalid combination of options: -d and -r are in conflict.\n")); 543 return -1; 544 } 545 if (rseen) 546 fprintf (stderr, GTXT ("Warning: option -r was specified several times. Last value is used.\n")); 547 free (common_archive_dir); 548 common_archive_dir = strdup (optarg); 549 use_relative_path = 1; 550 rseen = 1; 551 break; 552 case 'a': 553 if (strcmp (optarg, "off") == 0) 554 s_option = ARCH_NOTHING; 555 else if (strcmp (optarg, "on") == 0 || 556 strcmp (optarg, "ldobjects") == 0) 557 s_option = ARCH_EXE_ONLY; 558 else if (strcmp (optarg, "usedldobjects") == 0) 559 s_option = ARCH_USED_EXE_ONLY; 560 else if (strcmp (optarg, "usedsrc") == 0) 561 s_option = ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY; 562 else if (strcmp (optarg, "all") == 0 || strcmp (optarg, "src") == 0) 563 s_option = ARCH_ALL; 564 else 565 { 566 fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"), 567 optopt, optarg); 568 return -1; 569 } 570 break; 571 case 'm': 572 { 573 regex_t *regex_desc = new regex_t (); 574 if (regcomp (regex_desc, optarg, REG_EXTENDED | REG_NOSUB | REG_NEWLINE)) 575 { 576 delete regex_desc; 577 fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"), 578 optopt, optarg); 579 return -1; 580 } 581 if (mask == NULL) 582 mask = new Vector<regex_t *>(); 583 mask->append (regex_desc); 584 break; 585 } 586 case 'O': 587 { 588 int fd = open (optarg, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 589 if (fd == -1) 590 { 591 fprintf (stderr, GTXT ("er_archive: Can't open %s: %s\n"), 592 optarg, strerror (errno)); 593 break; 594 } 595 if (dup2 (fd, 2) == -1) 596 { 597 close (fd); 598 fprintf (stderr, GTXT ("er_archive: Can't divert stderr: %s\n"), 599 strerror (errno)); 600 break; 601 } 602 if (dup2 (fd, 1) == -1) 603 { 604 close (fd); 605 fprintf (stderr, GTXT ("er_archive: Can't divert stdout: %s\n"), 606 strerror (errno)); 607 break; 608 } 609 close (fd); 610 struct timeval tp; 611 gettimeofday (&tp, NULL); 612 fprintf (stderr, "### Start %s#", ctime (&tp.tv_sec)); 613 for (int i = 0; i < argc; i++) 614 fprintf (stderr, " %s", argv[i]); 615 fprintf (stderr, "\n"); 616 break; 617 } 618 case 'V': 619// Ruud 620 Application::print_version_info (); 621/* 622 printf (GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION); 623*/ 624 exit (0); 625 case 'w': 626 whoami = optarg; 627 break; 628 case 'h': 629 usage (); 630 exit (0); 631 case ':': // -s -m without operand 632 fprintf (stderr, GTXT ("Option -%c requires an operand\n"), optopt); 633 return -1; 634 case '?': 635 default: 636 fprintf (stderr, GTXT ("Unrecognized option: -%c\n"), optopt); 637 return -1; 638 } 639 } 640 return optind; 641} 642 643void 644er_archive::check_env_var () 645{ 646 char *ename = NTXT ("GPROFNG_ARCHIVE"); 647 char *var = getenv (ename); 648 if (var == NULL) 649 return; 650 var = dbe_strdup (var); 651 Vector<char*> *opts = new Vector<char*>(); 652 opts->append (ename); 653 for (char *s = var;;) 654 { 655 while (*s && isblank (*s)) 656 s++; 657 if (*s == 0) 658 break; 659 opts->append (s); 660 while (*s && !isblank (*s)) 661 s++; 662 if (*s == 0) 663 break; 664 *s = 0; 665 s++; 666 } 667 if (opts->size () > 0) 668 { 669 char **arr = (char **) malloc (sizeof (char *) *opts->size ()); 670 for (long i = 0; i < opts->size (); i++) 671 arr[i] = opts->get (i); 672 if (-1 == check_args (opts->size (), arr)) 673 fprintf (stderr, GTXT ("Error: Wrong SP_ER_ARCHIVE: '%s'\n"), var); 674 free (arr); 675 } 676 delete opts; 677 free (var); 678} 679 680static int 681real_main (int argc, char *argv[]) 682{ 683 er_archive *archive = new er_archive (argc, argv); 684 dbeSession->archive_mode = 1; 685 archive->start (argc, argv); 686 dbeSession->unlink_tmp_files (); 687 return 0; 688} 689 690/** 691 * Call catch_out_of_memory(int (*real_main)(int, char*[]), int argc, char *argv[]) which will call real_main() 692 * @param argc 693 * @param argv 694 * @return 695 */ 696int 697main (int argc, char *argv[]) 698{ 699 return catch_out_of_memory (real_main, argc, argv); 700} 701