]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gprofng/src/gp-archive.cc
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gprofng / src / gp-archive.cc
CommitLineData
fd67aa11 1/* Copyright (C) 2021-2024 Free Software Foundation, Inc.
bb368aad
VM
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)
f6ca448a 281 fprintf (stderr, GTXT ("gp-archive: %s: %s\n"), argv[last],
bb368aad
VM
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)
f6ca448a
VM
318 fprintf (stderr, GTXT ("gp-archive: %s: %s\n"), exp_path,
319 pr_mesgs (exp->fetch_errors (), "", ""));
bb368aad
VM
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)
f6ca448a 365 fprintf (stderr, GTXT ("gp-archive: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored\n"),
bb368aad
VM
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);
f6ca448a 483 fprintf (stderr, GTXT ("gp-archive: Cannot find file: `%s'\n"), df->get_name ());
bb368aad 484 }
f6ca448a
VM
485 fprintf (stderr,
486 GTXT ("\n If you know the correct location of the missing file(s)"
487 " you can help gp-archive to find them by manually editing"
488 " the .gprofng.rc file."
489 " See the gp-archive man page for more details.\n"));
bb368aad
VM
490 }
491 delete notfound_files;
492}
493
494int
495er_archive::check_args (int argc, char *argv[])
496{
497 int opt;
498 int rseen = 0;
499 int dseen = 0;
500 // Parsing the command line
501 opterr = 0;
502 optind = 1;
503 static struct option long_options[] = {
504 {"help", no_argument, 0, 'h'},
505 {"version", no_argument, 0, 'V'},
506 {"whoami", required_argument, 0, 'w'},
507 {"outfile", required_argument, 0, 'O'},
508 {NULL, 0, 0, 0}
509 };
510 while (1)
511 {
512 int option_index = 0;
513 opt = getopt_long (argc, argv, NTXT (":VFa:d:qnr:m:"),
514 long_options, &option_index);
515 if (opt == EOF)
516 break;
517 switch (opt)
518 {
519 case 'F':
520 force = 1;
521 break;
522 case 'd': // Common archive directory (absolute path)
523 if (rseen)
524 {
525 fprintf (stderr, GTXT ("Error: invalid combination of options: -r and -d are in conflict.\n"));
526 return -1;
527 }
528 if (dseen)
529 fprintf (stderr, GTXT ("Warning: option -d was specified several times. Last value is used.\n"));
530 free (common_archive_dir);
531 common_archive_dir = strdup (optarg);
532 dseen = 1;
533 break;
534 case 'q':
535 quiet = 1;
536 break;
537 case 'n':
538 descendant = 0;
539 break;
540 case 'r': // Common archive directory (relative path)
541 if (dseen)
542 {
543 fprintf (stderr, GTXT ("Error: invalid combination of options: -d and -r are in conflict.\n"));
544 return -1;
545 }
546 if (rseen)
547 fprintf (stderr, GTXT ("Warning: option -r was specified several times. Last value is used.\n"));
548 free (common_archive_dir);
549 common_archive_dir = strdup (optarg);
550 use_relative_path = 1;
551 rseen = 1;
552 break;
553 case 'a':
554 if (strcmp (optarg, "off") == 0)
555 s_option = ARCH_NOTHING;
556 else if (strcmp (optarg, "on") == 0 ||
557 strcmp (optarg, "ldobjects") == 0)
558 s_option = ARCH_EXE_ONLY;
559 else if (strcmp (optarg, "usedldobjects") == 0)
560 s_option = ARCH_USED_EXE_ONLY;
561 else if (strcmp (optarg, "usedsrc") == 0)
562 s_option = ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY;
563 else if (strcmp (optarg, "all") == 0 || strcmp (optarg, "src") == 0)
564 s_option = ARCH_ALL;
565 else
566 {
567 fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
568 optopt, optarg);
569 return -1;
570 }
571 break;
572 case 'm':
573 {
574 regex_t *regex_desc = new regex_t ();
575 if (regcomp (regex_desc, optarg, REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
576 {
577 delete regex_desc;
578 fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
579 optopt, optarg);
580 return -1;
581 }
582 if (mask == NULL)
583 mask = new Vector<regex_t *>();
584 mask->append (regex_desc);
585 break;
586 }
587 case 'O':
588 {
589 int fd = open (optarg, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
590 if (fd == -1)
591 {
f6ca448a 592 fprintf (stderr, GTXT ("gp-archive: Can't open %s: %s\n"),
bb368aad
VM
593 optarg, strerror (errno));
594 break;
595 }
596 if (dup2 (fd, 2) == -1)
597 {
598 close (fd);
f6ca448a 599 fprintf (stderr, GTXT ("gp-archive: Can't divert stderr: %s\n"),
bb368aad
VM
600 strerror (errno));
601 break;
602 }
603 if (dup2 (fd, 1) == -1)
604 {
605 close (fd);
f6ca448a 606 fprintf (stderr, GTXT ("gp-archive: Can't divert stdout: %s\n"),
bb368aad
VM
607 strerror (errno));
608 break;
609 }
610 close (fd);
611 struct timeval tp;
612 gettimeofday (&tp, NULL);
613 fprintf (stderr, "### Start %s#", ctime (&tp.tv_sec));
614 for (int i = 0; i < argc; i++)
615 fprintf (stderr, " %s", argv[i]);
616 fprintf (stderr, "\n");
617 break;
618 }
619 case 'V':
620// Ruud
621 Application::print_version_info ();
622/*
623 printf (GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
624*/
625 exit (0);
626 case 'w':
627 whoami = optarg;
628 break;
629 case 'h':
630 usage ();
631 exit (0);
632 case ':': // -s -m without operand
633 fprintf (stderr, GTXT ("Option -%c requires an operand\n"), optopt);
634 return -1;
635 case '?':
636 default:
637 fprintf (stderr, GTXT ("Unrecognized option: -%c\n"), optopt);
638 return -1;
639 }
640 }
641 return optind;
642}
643
644void
645er_archive::check_env_var ()
646{
647 char *ename = NTXT ("GPROFNG_ARCHIVE");
648 char *var = getenv (ename);
649 if (var == NULL)
650 return;
651 var = dbe_strdup (var);
652 Vector<char*> *opts = new Vector<char*>();
653 opts->append (ename);
654 for (char *s = var;;)
655 {
656 while (*s && isblank (*s))
657 s++;
658 if (*s == 0)
659 break;
660 opts->append (s);
661 while (*s && !isblank (*s))
662 s++;
663 if (*s == 0)
664 break;
665 *s = 0;
666 s++;
667 }
668 if (opts->size () > 0)
669 {
670 char **arr = (char **) malloc (sizeof (char *) *opts->size ());
671 for (long i = 0; i < opts->size (); i++)
672 arr[i] = opts->get (i);
673 if (-1 == check_args (opts->size (), arr))
674 fprintf (stderr, GTXT ("Error: Wrong SP_ER_ARCHIVE: '%s'\n"), var);
675 free (arr);
676 }
677 delete opts;
678 free (var);
679}
680
681static int
682real_main (int argc, char *argv[])
683{
684 er_archive *archive = new er_archive (argc, argv);
685 dbeSession->archive_mode = 1;
686 archive->start (argc, argv);
687 dbeSession->unlink_tmp_files ();
688 return 0;
689}
690
691/**
692 * Call catch_out_of_memory(int (*real_main)(int, char*[]), int argc, char *argv[]) which will call real_main()
693 * @param argc
694 * @param argv
695 * @return
696 */
697int
698main (int argc, char *argv[])
699{
700 return catch_out_of_memory (real_main, argc, argv);
701}