]>
Commit | Line | Data |
---|---|---|
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 | ||
39 | er_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 | ||
50 | er_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 | ||
65 | int | |
66 | er_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 | ||
79 | void | |
80 | er_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 | ||
150 | Vector <LoadObject*> * | |
151 | er_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 | */ | |
204 | int | |
205 | er_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 | ||
267 | void | |
268 | er_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 | ||
494 | int | |
495 | er_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 | ||
644 | void | |
645 | er_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 | ||
681 | static int | |
682 | real_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 | */ | |
697 | int | |
698 | main (int argc, char *argv[]) | |
699 | { | |
700 | return catch_out_of_memory (real_main, argc, argv); | |
701 | } |