]>
Commit | Line | Data |
---|---|---|
252b5132 | 1 | /* bucomm.c -- Bin Utils COMmon code. |
fd67aa11 | 2 | Copyright (C) 1991-2024 Free Software Foundation, Inc. |
252b5132 RH |
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 | |
32866df7 | 8 | the Free Software Foundation; either version 3 of the License, or |
252b5132 RH |
9 | (at your option) 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 | |
b43b5d5f NC |
18 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA |
19 | 02110-1301, USA. */ | |
252b5132 RH |
20 | \f |
21 | /* We might put this in a library someday so it could be dynamically | |
22 | loaded, but for now it's not necessary. */ | |
23 | ||
3db64b00 | 24 | #include "sysdep.h" |
252b5132 RH |
25 | #include "bfd.h" |
26 | #include "libiberty.h" | |
5af11cab | 27 | #include "filenames.h" |
87b9f255 | 28 | #include <time.h> |
77f762d6 | 29 | #include <assert.h> |
3db64b00 | 30 | #include "bucomm.h" |
252b5132 | 31 | \f |
06d86cf7 | 32 | /* Error reporting. */ |
252b5132 RH |
33 | |
34 | char *program_name; | |
35 | ||
36 | void | |
2da42df6 | 37 | bfd_nonfatal (const char *string) |
252b5132 | 38 | { |
a8c62f1c | 39 | const char *errmsg; |
a68aa5d3 | 40 | enum bfd_error err = bfd_get_error (); |
252b5132 | 41 | |
a68aa5d3 NC |
42 | if (err == bfd_error_no_error) |
43 | errmsg = _("cause of error unknown"); | |
44 | else | |
45 | errmsg = bfd_errmsg (err); | |
8e085dd2 | 46 | fflush (stdout); |
252b5132 RH |
47 | if (string) |
48 | fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); | |
49 | else | |
50 | fprintf (stderr, "%s: %s\n", program_name, errmsg); | |
51 | } | |
52 | ||
2db6cde7 NS |
53 | /* Issue a non fatal error message. FILENAME, or if NULL then BFD, |
54 | are used to indicate the problematic file. SECTION, if non NULL, | |
55 | is used to provide a section name. If FORMAT is non-null, then it | |
56 | is used to print additional information via vfprintf. Finally the | |
57 | bfd error message is printed. In summary, error messages are of | |
58 | one of the following forms: | |
59 | ||
df56ecde AM |
60 | PROGRAM: file: bfd-error-message |
61 | PROGRAM: file[section]: bfd-error-message | |
62 | PROGRAM: file: printf-message: bfd-error-message | |
63 | PROGRAM: file[section]: printf-message: bfd-error-message. */ | |
2db6cde7 NS |
64 | |
65 | void | |
66 | bfd_nonfatal_message (const char *filename, | |
91d6fa6a NC |
67 | const bfd *abfd, |
68 | const asection *section, | |
2db6cde7 NS |
69 | const char *format, ...) |
70 | { | |
a8c62f1c AM |
71 | const char *errmsg; |
72 | const char *section_name; | |
a68aa5d3 | 73 | enum bfd_error err = bfd_get_error (); |
2db6cde7 | 74 | |
a68aa5d3 NC |
75 | if (err == bfd_error_no_error) |
76 | errmsg = _("cause of error unknown"); | |
77 | else | |
78 | errmsg = bfd_errmsg (err); | |
8e085dd2 | 79 | fflush (stdout); |
a8c62f1c | 80 | section_name = NULL; |
2db6cde7 | 81 | fprintf (stderr, "%s", program_name); |
3aade688 | 82 | |
91d6fa6a | 83 | if (abfd) |
2db6cde7 NS |
84 | { |
85 | if (!filename) | |
91d6fa6a | 86 | filename = bfd_get_archive_filename (abfd); |
2db6cde7 | 87 | if (section) |
fd361982 | 88 | section_name = bfd_section_name (section); |
2db6cde7 NS |
89 | } |
90 | if (section_name) | |
df56ecde | 91 | fprintf (stderr, ": %s[%s]", filename, section_name); |
2db6cde7 | 92 | else |
df56ecde | 93 | fprintf (stderr, ": %s", filename); |
2db6cde7 NS |
94 | |
95 | if (format) | |
96 | { | |
bd84a8e2 AM |
97 | va_list args; |
98 | va_start (args, format); | |
2db6cde7 NS |
99 | fprintf (stderr, ": "); |
100 | vfprintf (stderr, format, args); | |
bd84a8e2 | 101 | va_end (args); |
2db6cde7 NS |
102 | } |
103 | fprintf (stderr, ": %s\n", errmsg); | |
2db6cde7 NS |
104 | } |
105 | ||
252b5132 | 106 | void |
2da42df6 | 107 | bfd_fatal (const char *string) |
252b5132 RH |
108 | { |
109 | bfd_nonfatal (string); | |
110 | xexit (1); | |
111 | } | |
112 | ||
cba12006 | 113 | void |
2da42df6 | 114 | report (const char * format, va_list args) |
252b5132 | 115 | { |
a8c62f1c | 116 | fflush (stdout); |
252b5132 RH |
117 | fprintf (stderr, "%s: ", program_name); |
118 | vfprintf (stderr, format, args); | |
119 | putc ('\n', stderr); | |
120 | } | |
121 | ||
252b5132 | 122 | void |
1651e569 | 123 | fatal (const char *format, ...) |
252b5132 | 124 | { |
1651e569 TT |
125 | va_list args; |
126 | ||
127 | va_start (args, format); | |
252b5132 | 128 | |
252b5132 | 129 | report (format, args); |
1651e569 | 130 | va_end (args); |
252b5132 RH |
131 | xexit (1); |
132 | } | |
133 | ||
134 | void | |
1651e569 | 135 | non_fatal (const char *format, ...) |
252b5132 | 136 | { |
1651e569 TT |
137 | va_list args; |
138 | ||
139 | va_start (args, format); | |
252b5132 | 140 | |
252b5132 | 141 | report (format, args); |
1651e569 | 142 | va_end (args); |
252b5132 | 143 | } |
252b5132 | 144 | |
0772dacc AM |
145 | /* Like xmalloc except that ABFD's objalloc memory is returned. |
146 | Use objalloc_free_block to free this memory and all more recently | |
147 | allocated, or more usually, leave it to bfd_close to free. */ | |
148 | ||
149 | void * | |
150 | bfd_xalloc (bfd *abfd, size_t size) | |
151 | { | |
152 | void *ret = bfd_alloc (abfd, size); | |
153 | if (ret == NULL) | |
154 | bfd_fatal (NULL); | |
155 | return ret; | |
156 | } | |
157 | ||
252b5132 RH |
158 | /* Set the default BFD target based on the configured target. Doing |
159 | this permits the binutils to be configured for a particular target, | |
160 | and linked against a shared BFD library which was configured for a | |
161 | different target. */ | |
162 | ||
163 | void | |
2da42df6 | 164 | set_default_bfd_target (void) |
252b5132 RH |
165 | { |
166 | /* The macro TARGET is defined by Makefile. */ | |
167 | const char *target = TARGET; | |
168 | ||
169 | if (! bfd_set_default_target (target)) | |
170 | fatal (_("can't set BFD default target to `%s': %s"), | |
171 | target, bfd_errmsg (bfd_get_error ())); | |
172 | } | |
173 | ||
b34976b6 | 174 | /* After a FALSE return from bfd_check_format_matches with |
252b5132 | 175 | bfd_get_error () == bfd_error_file_ambiguously_recognized, print |
370426d0 | 176 | the possible matching targets and free the list of targets. */ |
252b5132 RH |
177 | |
178 | void | |
370426d0 | 179 | list_matching_formats (char **matching) |
252b5132 | 180 | { |
a8c62f1c | 181 | fflush (stdout); |
252b5132 | 182 | fprintf (stderr, _("%s: Matching formats:"), program_name); |
370426d0 | 183 | char **p = matching; |
252b5132 RH |
184 | while (*p) |
185 | fprintf (stderr, " %s", *p++); | |
370426d0 | 186 | free (matching); |
252b5132 RH |
187 | fputc ('\n', stderr); |
188 | } | |
189 | ||
190 | /* List the supported targets. */ | |
191 | ||
192 | void | |
2da42df6 | 193 | list_supported_targets (const char *name, FILE *f) |
252b5132 | 194 | { |
252b5132 | 195 | int t; |
a8c62f1c | 196 | const char **targ_names; |
252b5132 RH |
197 | |
198 | if (name == NULL) | |
199 | fprintf (f, _("Supported targets:")); | |
200 | else | |
201 | fprintf (f, _("%s: supported targets:"), name); | |
48417c1a | 202 | |
a8c62f1c | 203 | targ_names = bfd_target_list (); |
48417c1a AM |
204 | for (t = 0; targ_names[t] != NULL; t++) |
205 | fprintf (f, " %s", targ_names[t]); | |
252b5132 | 206 | fprintf (f, "\n"); |
48417c1a | 207 | free (targ_names); |
252b5132 | 208 | } |
2f83960e AM |
209 | |
210 | /* List the supported architectures. */ | |
211 | ||
212 | void | |
2da42df6 | 213 | list_supported_architectures (const char *name, FILE *f) |
2f83960e | 214 | { |
d25576aa NC |
215 | const char ** arch; |
216 | const char ** arches; | |
2f83960e AM |
217 | |
218 | if (name == NULL) | |
219 | fprintf (f, _("Supported architectures:")); | |
220 | else | |
221 | fprintf (f, _("%s: supported architectures:"), name); | |
222 | ||
d25576aa | 223 | for (arch = arches = bfd_arch_list (); *arch; arch++) |
2f83960e AM |
224 | fprintf (f, " %s", *arch); |
225 | fprintf (f, "\n"); | |
d25576aa | 226 | free (arches); |
2f83960e | 227 | } |
252b5132 | 228 | \f |
06d86cf7 | 229 | static const char * |
2da42df6 | 230 | endian_string (enum bfd_endian endian) |
06d86cf7 NC |
231 | { |
232 | switch (endian) | |
233 | { | |
9cf03b7e NC |
234 | case BFD_ENDIAN_BIG: return _("big endian"); |
235 | case BFD_ENDIAN_LITTLE: return _("little endian"); | |
236 | default: return _("endianness unknown"); | |
06d86cf7 NC |
237 | } |
238 | } | |
239 | ||
aac502f7 AM |
240 | /* Data passed to do_display_target and other target iterators. */ |
241 | ||
242 | struct display_target { | |
243 | /* Temp file. */ | |
244 | char *filename; | |
245 | /* Return status. */ | |
246 | int error; | |
247 | /* Number of targets. */ | |
248 | int count; | |
249 | /* Size of info in bytes. */ | |
250 | size_t alloc; | |
251 | /* Per-target info. */ | |
252 | struct { | |
253 | /* Target name. */ | |
254 | const char *name; | |
255 | /* Non-zero if target/arch combination supported. */ | |
256 | unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1]; | |
257 | } *info; | |
258 | }; | |
259 | ||
06d86cf7 | 260 | /* List the targets that BFD is configured to support, each followed |
aac502f7 AM |
261 | by its endianness and the architectures it supports. Also build |
262 | info about target/archs. */ | |
06d86cf7 NC |
263 | |
264 | static int | |
aac502f7 | 265 | do_display_target (const bfd_target *targ, void *data) |
06d86cf7 | 266 | { |
aac502f7 AM |
267 | struct display_target *param = (struct display_target *) data; |
268 | bfd *abfd; | |
269 | size_t amt; | |
06d86cf7 | 270 | |
aac502f7 AM |
271 | param->count += 1; |
272 | amt = param->count * sizeof (*param->info); | |
273 | if (param->alloc < amt) | |
06d86cf7 | 274 | { |
aac502f7 AM |
275 | size_t size = ((param->count < 64 ? 64 : param->count) |
276 | * sizeof (*param->info) * 2); | |
277 | param->info = xrealloc (param->info, size); | |
278 | memset ((char *) param->info + param->alloc, 0, size - param->alloc); | |
279 | param->alloc = size; | |
280 | } | |
281 | param->info[param->count - 1].name = targ->name; | |
06d86cf7 | 282 | |
aac502f7 AM |
283 | printf (_("%s\n (header %s, data %s)\n"), targ->name, |
284 | endian_string (targ->header_byteorder), | |
285 | endian_string (targ->byteorder)); | |
06d86cf7 | 286 | |
aac502f7 AM |
287 | abfd = bfd_openw (param->filename, targ->name); |
288 | if (abfd == NULL) | |
289 | { | |
290 | bfd_nonfatal (param->filename); | |
291 | param->error = 1; | |
292 | } | |
293 | else if (!bfd_set_format (abfd, bfd_object)) | |
294 | { | |
295 | if (bfd_get_error () != bfd_error_invalid_operation) | |
06d86cf7 | 296 | { |
aac502f7 AM |
297 | bfd_nonfatal (targ->name); |
298 | param->error = 1; | |
06d86cf7 | 299 | } |
aac502f7 AM |
300 | } |
301 | else | |
302 | { | |
303 | enum bfd_architecture a; | |
06d86cf7 | 304 | |
91610c0c | 305 | for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) |
aac502f7 AM |
306 | if (bfd_set_arch_mach (abfd, a, 0)) |
307 | { | |
308 | printf (" %s\n", bfd_printable_arch_mach (a, 0)); | |
309 | param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1; | |
310 | } | |
06d86cf7 | 311 | } |
aac502f7 AM |
312 | if (abfd != NULL) |
313 | bfd_close_all_done (abfd); | |
06d86cf7 | 314 | |
aac502f7 | 315 | return param->error; |
06d86cf7 NC |
316 | } |
317 | ||
aac502f7 AM |
318 | static void |
319 | display_target_list (struct display_target *arg) | |
320 | { | |
321 | arg->filename = make_temp_file (NULL); | |
322 | arg->error = 0; | |
323 | arg->count = 0; | |
324 | arg->alloc = 0; | |
325 | arg->info = NULL; | |
326 | ||
327 | bfd_iterate_over_targets (do_display_target, arg); | |
328 | ||
329 | unlink (arg->filename); | |
330 | free (arg->filename); | |
331 | } | |
332 | ||
333 | /* Calculate how many targets we can print across the page. */ | |
06d86cf7 NC |
334 | |
335 | static int | |
aac502f7 | 336 | do_info_size (int targ, int width, const struct display_target *arg) |
06d86cf7 | 337 | { |
aac502f7 AM |
338 | while (targ < arg->count) |
339 | { | |
340 | width -= strlen (arg->info[targ].name) + 1; | |
341 | if (width < 0) | |
342 | return targ; | |
343 | ++targ; | |
344 | } | |
345 | return targ; | |
346 | } | |
347 | ||
348 | /* Print header of target names. */ | |
06d86cf7 | 349 | |
aac502f7 AM |
350 | static void |
351 | do_info_header (int targ, int stop_targ, const struct display_target *arg) | |
352 | { | |
353 | while (targ != stop_targ) | |
354 | printf ("%s ", arg->info[targ++].name); | |
355 | } | |
356 | ||
357 | /* Print a table row. */ | |
358 | ||
359 | static void | |
360 | do_info_row (int targ, int stop_targ, enum bfd_architecture a, | |
361 | const struct display_target *arg) | |
362 | { | |
363 | while (targ != stop_targ) | |
364 | { | |
365 | if (arg->info[targ].arch[a - bfd_arch_obscure - 1]) | |
366 | fputs (arg->info[targ].name, stdout); | |
367 | else | |
368 | { | |
369 | int l = strlen (arg->info[targ].name); | |
370 | while (l--) | |
371 | putchar ('-'); | |
372 | } | |
373 | ++targ; | |
374 | if (targ != stop_targ) | |
375 | putchar (' '); | |
376 | } | |
06d86cf7 NC |
377 | } |
378 | ||
379 | /* Print tables of all the target-architecture combinations that | |
380 | BFD has been configured to support. */ | |
381 | ||
aac502f7 AM |
382 | static void |
383 | display_target_tables (const struct display_target *arg) | |
06d86cf7 | 384 | { |
aac502f7 AM |
385 | const char *columns; |
386 | int width, start_targ, stop_targ; | |
387 | enum bfd_architecture arch; | |
388 | int longest_arch = 0; | |
389 | ||
390 | for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) | |
06d86cf7 | 391 | { |
aac502f7 AM |
392 | const char *s = bfd_printable_arch_mach (arch, 0); |
393 | int len = strlen (s); | |
394 | if (len > longest_arch) | |
395 | longest_arch = len; | |
396 | } | |
06d86cf7 | 397 | |
aac502f7 AM |
398 | width = 0; |
399 | columns = getenv ("COLUMNS"); | |
400 | if (columns != NULL) | |
401 | width = atoi (columns); | |
402 | if (width == 0) | |
403 | width = 80; | |
404 | ||
405 | for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ) | |
406 | { | |
407 | stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg); | |
408 | ||
409 | printf ("\n%*s", longest_arch + 1, " "); | |
410 | do_info_header (start_targ, stop_targ, arg); | |
411 | putchar ('\n'); | |
06d86cf7 | 412 | |
aac502f7 AM |
413 | for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) |
414 | { | |
415 | if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0) | |
416 | { | |
417 | printf ("%*s ", longest_arch, | |
418 | bfd_printable_arch_mach (arch, 0)); | |
419 | ||
420 | do_info_row (start_targ, stop_targ, arch, arg); | |
421 | putchar ('\n'); | |
422 | } | |
06d86cf7 | 423 | } |
06d86cf7 | 424 | } |
06d86cf7 NC |
425 | } |
426 | ||
427 | int | |
2da42df6 | 428 | display_info (void) |
06d86cf7 | 429 | { |
aac502f7 AM |
430 | struct display_target arg; |
431 | ||
06d86cf7 | 432 | printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); |
aac502f7 AM |
433 | |
434 | display_target_list (&arg); | |
435 | if (!arg.error) | |
436 | display_target_tables (&arg); | |
437 | ||
438 | return arg.error; | |
06d86cf7 NC |
439 | } |
440 | \f | |
252b5132 RH |
441 | /* Display the archive header for an element as if it were an ls -l listing: |
442 | ||
443 | Mode User\tGroup\tSize\tDate Name */ | |
444 | ||
445 | void | |
015dc7e1 | 446 | print_arelt_descr (FILE *file, bfd *abfd, bool verbose, bool offsets) |
252b5132 RH |
447 | { |
448 | struct stat buf; | |
449 | ||
450 | if (verbose) | |
451 | { | |
452 | if (bfd_stat_arch_elt (abfd, &buf) == 0) | |
453 | { | |
454 | char modebuf[11]; | |
455 | char timebuf[40]; | |
456 | time_t when = buf.st_mtime; | |
b1f88ebe | 457 | const char *ctime_result = (const char *) ctime (&when); |
252b5132 | 458 | |
0593bd3a NC |
459 | /* PR binutils/17605: Check for corrupt time values. */ |
460 | if (ctime_result == NULL) | |
461 | sprintf (timebuf, _("<time data corrupt>")); | |
462 | else | |
463 | /* POSIX format: skip weekday and seconds from ctime output. */ | |
464 | sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); | |
252b5132 RH |
465 | |
466 | mode_string (buf.st_mode, modebuf); | |
467 | modebuf[10] = '\0'; | |
468 | /* POSIX 1003.2/D11 says to skip first character (entry type). */ | |
b8281767 | 469 | fprintf (file, "%s %ld/%ld %6" PRIu64 " %s ", modebuf + 1, |
252b5132 | 470 | (long) buf.st_uid, (long) buf.st_gid, |
b8281767 | 471 | (uint64_t) buf.st_size, timebuf); |
252b5132 RH |
472 | } |
473 | } | |
474 | ||
1869e86f AB |
475 | fprintf (file, "%s", bfd_get_filename (abfd)); |
476 | ||
477 | if (offsets) | |
478 | { | |
479 | if (bfd_is_thin_archive (abfd) && abfd->proxy_origin) | |
480 | fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin); | |
481 | else if (!bfd_is_thin_archive (abfd) && abfd->origin) | |
482 | fprintf (file, " 0x%lx", (unsigned long) abfd->origin); | |
483 | } | |
484 | ||
485 | fprintf (file, "\n"); | |
252b5132 RH |
486 | } |
487 | ||
485be063 AM |
488 | /* Return a path for a new temporary file in the same directory |
489 | as file PATH. */ | |
252b5132 | 490 | |
485be063 AM |
491 | static char * |
492 | template_in_dir (const char *path) | |
252b5132 | 493 | { |
485be063 | 494 | #define template "stXXXXXX" |
2946671e | 495 | const char *slash = strrchr (path, '/'); |
252b5132 | 496 | char *tmpname; |
485be063 | 497 | size_t len; |
252b5132 | 498 | |
5af11cab AM |
499 | #ifdef HAVE_DOS_BASED_FILE_SYSTEM |
500 | { | |
501 | /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ | |
485be063 | 502 | char *bslash = strrchr (path, '\\'); |
f9c026a8 | 503 | |
2ab47eed | 504 | if (slash == NULL || (bslash != NULL && bslash > slash)) |
5af11cab | 505 | slash = bslash; |
485be063 | 506 | if (slash == NULL && path[0] != '\0' && path[1] == ':') |
2946671e | 507 | slash = path + 1; |
5af11cab | 508 | } |
252b5132 RH |
509 | #endif |
510 | ||
511 | if (slash != (char *) NULL) | |
512 | { | |
485be063 | 513 | len = slash - path; |
3f5e193b | 514 | tmpname = (char *) xmalloc (len + sizeof (template) + 2); |
485be063 | 515 | memcpy (tmpname, path, len); |
252b5132 | 516 | |
5af11cab AM |
517 | #ifdef HAVE_DOS_BASED_FILE_SYSTEM |
518 | /* If tmpname is "X:", appending a slash will make it a root | |
519 | directory on drive X, which is NOT the same as the current | |
520 | directory on drive X. */ | |
485be063 AM |
521 | if (len == 2 && tmpname[1] == ':') |
522 | tmpname[len++] = '.'; | |
5af11cab | 523 | #endif |
485be063 | 524 | tmpname[len++] = '/'; |
252b5132 RH |
525 | } |
526 | else | |
527 | { | |
3f5e193b | 528 | tmpname = (char *) xmalloc (sizeof (template)); |
485be063 | 529 | len = 0; |
f9c026a8 | 530 | } |
485be063 AM |
531 | |
532 | memcpy (tmpname + len, template, sizeof (template)); | |
533 | return tmpname; | |
534 | #undef template | |
535 | } | |
536 | ||
537 | /* Return the name of a created temporary file in the same directory | |
538 | as FILENAME. */ | |
539 | ||
540 | char * | |
365f5fb6 | 541 | make_tempname (const char *filename, int *ofd) |
485be063 AM |
542 | { |
543 | char *tmpname = template_in_dir (filename); | |
544 | int fd; | |
545 | ||
546 | #ifdef HAVE_MKSTEMP | |
547 | fd = mkstemp (tmpname); | |
548 | #else | |
549 | tmpname = mktemp (tmpname); | |
550 | if (tmpname == NULL) | |
d6e1d48c AM |
551 | fd = -1; |
552 | else | |
553 | fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); | |
f9c026a8 | 554 | #endif |
485be063 | 555 | if (fd == -1) |
c48d800e NC |
556 | { |
557 | free (tmpname); | |
5e39600a | 558 | bfd_set_error (bfd_error_system_call); |
c48d800e NC |
559 | return NULL; |
560 | } | |
365f5fb6 | 561 | *ofd = fd; |
f9c026a8 NC |
562 | return tmpname; |
563 | } | |
564 | ||
485be063 AM |
565 | /* Return the name of a created temporary directory inside the |
566 | directory containing FILENAME. */ | |
f9c026a8 NC |
567 | |
568 | char * | |
1ff5d5c4 | 569 | make_tempdir (const char *filename) |
f9c026a8 | 570 | { |
485be063 | 571 | char *tmpname = template_in_dir (filename); |
d6e1d48c | 572 | char *ret; |
f9c026a8 | 573 | |
485be063 | 574 | #ifdef HAVE_MKDTEMP |
d6e1d48c | 575 | ret = mkdtemp (tmpname); |
485be063 | 576 | #else |
d6e1d48c | 577 | ret = mktemp (tmpname); |
485be063 AM |
578 | #if defined (_WIN32) && !defined (__CYGWIN32__) |
579 | if (mkdir (tmpname) != 0) | |
d6e1d48c | 580 | ret = NULL; |
485be063 AM |
581 | #else |
582 | if (mkdir (tmpname, 0700) != 0) | |
d6e1d48c | 583 | ret = NULL; |
f9c026a8 | 584 | #endif |
485be063 | 585 | #endif |
d6e1d48c | 586 | if (ret == NULL) |
5e39600a AM |
587 | { |
588 | free (tmpname); | |
589 | bfd_set_error (bfd_error_system_call); | |
590 | } | |
d6e1d48c | 591 | return ret; |
252b5132 RH |
592 | } |
593 | ||
594 | /* Parse a string into a VMA, with a fatal error if it can't be | |
595 | parsed. */ | |
596 | ||
597 | bfd_vma | |
2da42df6 | 598 | parse_vma (const char *s, const char *arg) |
252b5132 RH |
599 | { |
600 | bfd_vma ret; | |
601 | const char *end; | |
602 | ||
603 | ret = bfd_scan_vma (s, &end, 0); | |
f462a9ea | 604 | |
252b5132 RH |
605 | if (*end != '\0') |
606 | fatal (_("%s: bad number: %s"), arg, s); | |
607 | ||
608 | return ret; | |
609 | } | |
f24ddbdd NC |
610 | |
611 | /* Returns the size of the named file. If the file does not | |
612 | exist, or if it is not a real file, then a suitable non-fatal | |
a3029abd | 613 | error message is printed and (off_t) -1 is returned. */ |
f24ddbdd NC |
614 | |
615 | off_t | |
616 | get_file_size (const char * file_name) | |
617 | { | |
618 | struct stat statbuf; | |
3aade688 | 619 | |
740a4630 NC |
620 | if (file_name == NULL) |
621 | return (off_t) -1; | |
622 | ||
f24ddbdd NC |
623 | if (stat (file_name, &statbuf) < 0) |
624 | { | |
625 | if (errno == ENOENT) | |
626 | non_fatal (_("'%s': No such file"), file_name); | |
627 | else | |
628 | non_fatal (_("Warning: could not locate '%s'. reason: %s"), | |
629 | file_name, strerror (errno)); | |
3aade688 | 630 | } |
0602cdad NC |
631 | else if (S_ISDIR (statbuf.st_mode)) |
632 | non_fatal (_("Warning: '%s' is a directory"), file_name); | |
f24ddbdd NC |
633 | else if (! S_ISREG (statbuf.st_mode)) |
634 | non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); | |
9849fbfc NC |
635 | else if (statbuf.st_size < 0) |
636 | non_fatal (_("Warning: '%s' has negative size, probably it is too large"), | |
637 | file_name); | |
a7ad3cb1 EZ |
638 | #if defined (_WIN32) && !defined (__CYGWIN__) |
639 | else if (statbuf.st_size == 0) | |
640 | { | |
887854ba EZ |
641 | /* MS-Windows 'stat' reports the null device as a regular file; |
642 | fix that. */ | |
a7ad3cb1 EZ |
643 | int fd = open (file_name, O_RDONLY | O_BINARY); |
644 | if (isatty (fd)) | |
645 | { | |
646 | close (fd); | |
647 | non_fatal (_("Warning: '%s' is not an ordinary file"), | |
648 | /* libtool wants to see /dev/null in the output. */ | |
649 | strcasecmp (file_name, "nul") ? file_name : "/dev/null"); | |
650 | } | |
651 | } | |
652 | #endif | |
f24ddbdd NC |
653 | else |
654 | return statbuf.st_size; | |
655 | ||
52a476ee | 656 | return (off_t) -1; |
f24ddbdd | 657 | } |
77f762d6 L |
658 | |
659 | /* Return the filename in a static buffer. */ | |
660 | ||
661 | const char * | |
8d8e0703 | 662 | bfd_get_archive_filename (const bfd *abfd) |
77f762d6 L |
663 | { |
664 | static size_t curr = 0; | |
665 | static char *buf; | |
666 | size_t needed; | |
667 | ||
668 | assert (abfd != NULL); | |
3aade688 | 669 | |
b0cffb47 AM |
670 | if (abfd->my_archive == NULL |
671 | || bfd_is_thin_archive (abfd->my_archive)) | |
77f762d6 L |
672 | return bfd_get_filename (abfd); |
673 | ||
674 | needed = (strlen (bfd_get_filename (abfd->my_archive)) | |
675 | + strlen (bfd_get_filename (abfd)) + 3); | |
676 | if (needed > curr) | |
677 | { | |
678 | if (curr) | |
679 | free (buf); | |
680 | curr = needed + (needed >> 1); | |
76e7a751 | 681 | buf = (char *) xmalloc (curr); |
77f762d6 L |
682 | } |
683 | sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), | |
684 | bfd_get_filename (abfd)); | |
685 | return buf; | |
686 | } | |
dd9b91de NC |
687 | |
688 | /* Returns TRUE iff PATHNAME, a filename of an archive member, | |
689 | is valid for writing. For security reasons absolute paths | |
690 | and paths containing /../ are not allowed. See PR 17533. */ | |
691 | ||
015dc7e1 | 692 | bool |
dd9b91de NC |
693 | is_valid_archive_path (char const * pathname) |
694 | { | |
695 | const char * n = pathname; | |
696 | ||
697 | if (IS_ABSOLUTE_PATH (n)) | |
015dc7e1 | 698 | return false; |
dd9b91de NC |
699 | |
700 | while (*n) | |
701 | { | |
702 | if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n))) | |
015dc7e1 | 703 | return false; |
dd9b91de NC |
704 | |
705 | while (*n && ! IS_DIR_SEPARATOR (*n)) | |
706 | n++; | |
707 | while (IS_DIR_SEPARATOR (*n)) | |
708 | n++; | |
709 | } | |
710 | ||
015dc7e1 | 711 | return true; |
dd9b91de | 712 | } |