123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- /* bucomm.c -- Bin Utils COMmon code.
- Copyright (C) 1991-2017 Free Software Foundation, Inc.
- This file is part of GNU Binutils.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
- /* We might put this in a library someday so it could be dynamically
- loaded, but for now it's not necessary. */
- #include "sysdep.h"
- #include "bfd.h"
- #include "libiberty.h"
- #include "filenames.h"
- #include <time.h> /* ctime, maybe time_t */
- #include <assert.h>
- #include "bucomm.h"
- #ifndef HAVE_TIME_T_IN_TIME_H
- #ifndef HAVE_TIME_T_IN_TYPES_H
- typedef long time_t;
- #endif
- #endif
- /* Error reporting. */
- char *program_name;
- void
- bfd_nonfatal (const char *string)
- {
- const char *errmsg;
- errmsg = bfd_errmsg (bfd_get_error ());
- fflush (stdout);
- if (string)
- fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
- else
- fprintf (stderr, "%s: %s\n", program_name, errmsg);
- }
- /* Issue a non fatal error message. FILENAME, or if NULL then BFD,
- are used to indicate the problematic file. SECTION, if non NULL,
- is used to provide a section name. If FORMAT is non-null, then it
- is used to print additional information via vfprintf. Finally the
- bfd error message is printed. In summary, error messages are of
- one of the following forms:
- PROGRAM:file: bfd-error-message
- PROGRAM:file[section]: bfd-error-message
- PROGRAM:file: printf-message: bfd-error-message
- PROGRAM:file[section]: printf-message: bfd-error-message. */
- void
- bfd_nonfatal_message (const char *filename,
- const bfd *abfd,
- const asection *section,
- const char *format, ...)
- {
- const char *errmsg;
- const char *section_name;
- va_list args;
- errmsg = bfd_errmsg (bfd_get_error ());
- fflush (stdout);
- section_name = NULL;
- va_start (args, format);
- fprintf (stderr, "%s", program_name);
- if (abfd)
- {
- if (!filename)
- filename = bfd_get_archive_filename (abfd);
- if (section)
- section_name = bfd_get_section_name (abfd, section);
- }
- if (section_name)
- fprintf (stderr, ":%s[%s]", filename, section_name);
- else
- fprintf (stderr, ":%s", filename);
- if (format)
- {
- fprintf (stderr, ": ");
- vfprintf (stderr, format, args);
- }
- fprintf (stderr, ": %s\n", errmsg);
- va_end (args);
- }
- void
- bfd_fatal (const char *string)
- {
- bfd_nonfatal (string);
- xexit (1);
- }
- void
- report (const char * format, va_list args)
- {
- fflush (stdout);
- fprintf (stderr, "%s: ", program_name);
- vfprintf (stderr, format, args);
- putc ('\n', stderr);
- }
- void
- fatal (const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- report (format, args);
- va_end (args);
- xexit (1);
- }
- void
- non_fatal (const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- report (format, args);
- va_end (args);
- }
- /* Set the default BFD target based on the configured target. Doing
- this permits the binutils to be configured for a particular target,
- and linked against a shared BFD library which was configured for a
- different target. */
- void
- set_default_bfd_target (void)
- {
- /* The macro TARGET is defined by Makefile. */
- const char *target = TARGET;
- if (! bfd_set_default_target (target))
- fatal (_("can't set BFD default target to `%s': %s"),
- target, bfd_errmsg (bfd_get_error ()));
- }
- /* After a FALSE return from bfd_check_format_matches with
- bfd_get_error () == bfd_error_file_ambiguously_recognized, print
- the possible matching targets. */
- void
- list_matching_formats (char **p)
- {
- fflush (stdout);
- fprintf (stderr, _("%s: Matching formats:"), program_name);
- while (*p)
- fprintf (stderr, " %s", *p++);
- fputc ('\n', stderr);
- }
- /* List the supported targets. */
- void
- list_supported_targets (const char *name, FILE *f)
- {
- int t;
- const char **targ_names;
- if (name == NULL)
- fprintf (f, _("Supported targets:"));
- else
- fprintf (f, _("%s: supported targets:"), name);
- targ_names = bfd_target_list ();
- for (t = 0; targ_names[t] != NULL; t++)
- fprintf (f, " %s", targ_names[t]);
- fprintf (f, "\n");
- free (targ_names);
- }
- /* List the supported architectures. */
- void
- list_supported_architectures (const char *name, FILE *f)
- {
- const char ** arch;
- const char ** arches;
- if (name == NULL)
- fprintf (f, _("Supported architectures:"));
- else
- fprintf (f, _("%s: supported architectures:"), name);
- for (arch = arches = bfd_arch_list (); *arch; arch++)
- fprintf (f, " %s", *arch);
- fprintf (f, "\n");
- free (arches);
- }
- static const char *
- endian_string (enum bfd_endian endian)
- {
- switch (endian)
- {
- case BFD_ENDIAN_BIG: return _("big endian");
- case BFD_ENDIAN_LITTLE: return _("little endian");
- default: return _("endianness unknown");
- }
- }
- /* Data passed to do_display_target and other target iterators. */
- struct display_target {
- /* Temp file. */
- char *filename;
- /* Return status. */
- int error;
- /* Number of targets. */
- int count;
- /* Size of info in bytes. */
- size_t alloc;
- /* Per-target info. */
- struct {
- /* Target name. */
- const char *name;
- /* Non-zero if target/arch combination supported. */
- unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1];
- } *info;
- };
- /* List the targets that BFD is configured to support, each followed
- by its endianness and the architectures it supports. Also build
- info about target/archs. */
- static int
- do_display_target (const bfd_target *targ, void *data)
- {
- struct display_target *param = (struct display_target *) data;
- bfd *abfd;
- size_t amt;
- param->count += 1;
- amt = param->count * sizeof (*param->info);
- if (param->alloc < amt)
- {
- size_t size = ((param->count < 64 ? 64 : param->count)
- * sizeof (*param->info) * 2);
- param->info = xrealloc (param->info, size);
- memset ((char *) param->info + param->alloc, 0, size - param->alloc);
- param->alloc = size;
- }
- param->info[param->count - 1].name = targ->name;
- printf (_("%s\n (header %s, data %s)\n"), targ->name,
- endian_string (targ->header_byteorder),
- endian_string (targ->byteorder));
- abfd = bfd_openw (param->filename, targ->name);
- if (abfd == NULL)
- {
- bfd_nonfatal (param->filename);
- param->error = 1;
- }
- else if (!bfd_set_format (abfd, bfd_object))
- {
- if (bfd_get_error () != bfd_error_invalid_operation)
- {
- bfd_nonfatal (targ->name);
- param->error = 1;
- }
- }
- else
- {
- enum bfd_architecture a;
- for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
- if (bfd_set_arch_mach (abfd, a, 0))
- {
- printf (" %s\n", bfd_printable_arch_mach (a, 0));
- param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
- }
- }
- if (abfd != NULL)
- bfd_close_all_done (abfd);
- return param->error;
- }
- static void
- display_target_list (struct display_target *arg)
- {
- arg->filename = make_temp_file (NULL);
- arg->error = 0;
- arg->count = 0;
- arg->alloc = 0;
- arg->info = NULL;
- bfd_iterate_over_targets (do_display_target, arg);
- unlink (arg->filename);
- free (arg->filename);
- }
- /* Calculate how many targets we can print across the page. */
- static int
- do_info_size (int targ, int width, const struct display_target *arg)
- {
- while (targ < arg->count)
- {
- width -= strlen (arg->info[targ].name) + 1;
- if (width < 0)
- return targ;
- ++targ;
- }
- return targ;
- }
- /* Print header of target names. */
- static void
- do_info_header (int targ, int stop_targ, const struct display_target *arg)
- {
- while (targ != stop_targ)
- printf ("%s ", arg->info[targ++].name);
- }
- /* Print a table row. */
- static void
- do_info_row (int targ, int stop_targ, enum bfd_architecture a,
- const struct display_target *arg)
- {
- while (targ != stop_targ)
- {
- if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
- fputs (arg->info[targ].name, stdout);
- else
- {
- int l = strlen (arg->info[targ].name);
- while (l--)
- putchar ('-');
- }
- ++targ;
- if (targ != stop_targ)
- putchar (' ');
- }
- }
- /* Print tables of all the target-architecture combinations that
- BFD has been configured to support. */
- static void
- display_target_tables (const struct display_target *arg)
- {
- const char *columns;
- int width, start_targ, stop_targ;
- enum bfd_architecture arch;
- int longest_arch = 0;
- for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
- {
- const char *s = bfd_printable_arch_mach (arch, 0);
- int len = strlen (s);
- if (len > longest_arch)
- longest_arch = len;
- }
- width = 0;
- columns = getenv ("COLUMNS");
- if (columns != NULL)
- width = atoi (columns);
- if (width == 0)
- width = 80;
- for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
- {
- stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
- printf ("\n%*s", longest_arch + 1, " ");
- do_info_header (start_targ, stop_targ, arg);
- putchar ('\n');
- for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
- {
- if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
- {
- printf ("%*s ", longest_arch,
- bfd_printable_arch_mach (arch, 0));
- do_info_row (start_targ, stop_targ, arch, arg);
- putchar ('\n');
- }
- }
- }
- }
- int
- display_info (void)
- {
- struct display_target arg;
- printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
- display_target_list (&arg);
- if (!arg.error)
- display_target_tables (&arg);
- return arg.error;
- }
- /* Display the archive header for an element as if it were an ls -l listing:
- Mode User\tGroup\tSize\tDate Name */
- void
- print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose)
- {
- struct stat buf;
- if (verbose)
- {
- if (bfd_stat_arch_elt (abfd, &buf) == 0)
- {
- char modebuf[11];
- char timebuf[40];
- time_t when = buf.st_mtime;
- const char *ctime_result = (const char *) ctime (&when);
- bfd_size_type size;
- /* PR binutils/17605: Check for corrupt time values. */
- if (ctime_result == NULL)
- sprintf (timebuf, _("<time data corrupt>"));
- else
- /* POSIX format: skip weekday and seconds from ctime output. */
- sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
- mode_string (buf.st_mode, modebuf);
- modebuf[10] = '\0';
- size = buf.st_size;
- /* POSIX 1003.2/D11 says to skip first character (entry type). */
- fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1,
- (long) buf.st_uid, (long) buf.st_gid,
- size, timebuf);
- }
- }
- fprintf (file, "%s\n", bfd_get_filename (abfd));
- }
- /* Return a path for a new temporary file in the same directory
- as file PATH. */
- static char *
- template_in_dir (const char *path)
- {
- #define template "stXXXXXX"
- const char *slash = strrchr (path, '/');
- char *tmpname;
- size_t len;
- #ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (path, '\\');
- if (slash == NULL || (bslash != NULL && bslash > slash))
- slash = bslash;
- if (slash == NULL && path[0] != '\0' && path[1] == ':')
- slash = path + 1;
- }
- #endif
- if (slash != (char *) NULL)
- {
- len = slash - path;
- tmpname = (char *) xmalloc (len + sizeof (template) + 2);
- memcpy (tmpname, path, len);
- #ifdef HAVE_DOS_BASED_FILE_SYSTEM
- /* If tmpname is "X:", appending a slash will make it a root
- directory on drive X, which is NOT the same as the current
- directory on drive X. */
- if (len == 2 && tmpname[1] == ':')
- tmpname[len++] = '.';
- #endif
- tmpname[len++] = '/';
- }
- else
- {
- tmpname = (char *) xmalloc (sizeof (template));
- len = 0;
- }
- memcpy (tmpname + len, template, sizeof (template));
- return tmpname;
- #undef template
- }
- /* Return the name of a created temporary file in the same directory
- as FILENAME. */
- char *
- make_tempname (char *filename)
- {
- char *tmpname = template_in_dir (filename);
- int fd;
- #ifdef HAVE_MKSTEMP
- fd = mkstemp (tmpname);
- #else
- tmpname = mktemp (tmpname);
- if (tmpname == NULL)
- return NULL;
- fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
- #endif
- if (fd == -1)
- {
- free (tmpname);
- return NULL;
- }
- close (fd);
- return tmpname;
- }
- /* Return the name of a created temporary directory inside the
- directory containing FILENAME. */
- char *
- make_tempdir (char *filename)
- {
- char *tmpname = template_in_dir (filename);
- #ifdef HAVE_MKDTEMP
- return mkdtemp (tmpname);
- #else
- tmpname = mktemp (tmpname);
- if (tmpname == NULL)
- return NULL;
- #if defined (_WIN32) && !defined (__CYGWIN32__)
- if (mkdir (tmpname) != 0)
- return NULL;
- #else
- if (mkdir (tmpname, 0700) != 0)
- return NULL;
- #endif
- return tmpname;
- #endif
- }
- /* Parse a string into a VMA, with a fatal error if it can't be
- parsed. */
- bfd_vma
- parse_vma (const char *s, const char *arg)
- {
- bfd_vma ret;
- const char *end;
- ret = bfd_scan_vma (s, &end, 0);
- if (*end != '\0')
- fatal (_("%s: bad number: %s"), arg, s);
- return ret;
- }
- /* Returns the size of the named file. If the file does not
- exist, or if it is not a real file, then a suitable non-fatal
- error message is printed and (off_t) -1 is returned. */
- off_t
- get_file_size (const char * file_name)
- {
- struct stat statbuf;
- if (file_name == NULL)
- return (off_t) -1;
- if (stat (file_name, &statbuf) < 0)
- {
- if (errno == ENOENT)
- non_fatal (_("'%s': No such file"), file_name);
- else
- non_fatal (_("Warning: could not locate '%s'. reason: %s"),
- file_name, strerror (errno));
- }
- else if (S_ISDIR (statbuf.st_mode))
- non_fatal (_("Warning: '%s' is a directory"), file_name);
- else if (! S_ISREG (statbuf.st_mode))
- non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
- else if (statbuf.st_size < 0)
- non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
- file_name);
- else
- return statbuf.st_size;
- return (off_t) -1;
- }
- /* Return the filename in a static buffer. */
- const char *
- bfd_get_archive_filename (const bfd *abfd)
- {
- static size_t curr = 0;
- static char *buf;
- size_t needed;
- assert (abfd != NULL);
- if (abfd->my_archive == NULL
- || bfd_is_thin_archive (abfd->my_archive))
- return bfd_get_filename (abfd);
- needed = (strlen (bfd_get_filename (abfd->my_archive))
- + strlen (bfd_get_filename (abfd)) + 3);
- if (needed > curr)
- {
- if (curr)
- free (buf);
- curr = needed + (needed >> 1);
- buf = (char *) xmalloc (curr);
- }
- sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
- bfd_get_filename (abfd));
- return buf;
- }
- /* Returns TRUE iff PATHNAME, a filename of an archive member,
- is valid for writing. For security reasons absolute paths
- and paths containing /../ are not allowed. See PR 17533. */
- bfd_boolean
- is_valid_archive_path (char const * pathname)
- {
- const char * n = pathname;
- if (IS_ABSOLUTE_PATH (n))
- return FALSE;
- while (*n)
- {
- if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
- return FALSE;
- while (*n && ! IS_DIR_SEPARATOR (*n))
- n++;
- while (IS_DIR_SEPARATOR (*n))
- n++;
- }
- return TRUE;
- }
|