1/* bucomm.c -- Bin Utils COMmon code.
2   Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003
3   Free Software Foundation, Inc.
4
5   This file is part of GNU Binutils.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20   02110-1301, USA.  */
21
22/* We might put this in a library someday so it could be dynamically
23   loaded, but for now it's not necessary.  */
24
25#include "bfd.h"
26#include "bfdver.h"
27#include "libiberty.h"
28#include "bucomm.h"
29#include "filenames.h"
30#include "libbfd.h"
31
32#include <sys/stat.h>
33#include <time.h>		/* ctime, maybe time_t */
34#include <assert.h>
35
36#ifndef HAVE_TIME_T_IN_TIME_H
37#ifndef HAVE_TIME_T_IN_TYPES_H
38typedef long time_t;
39#endif
40#endif
41
42static const char * endian_string (enum bfd_endian);
43static int display_target_list (void);
44static int display_info_table (int, int);
45static int display_target_tables (void);
46
47/* Error reporting.  */
48
49char *program_name;
50
51void
52bfd_nonfatal (const char *string)
53{
54  const char *errmsg = bfd_errmsg (bfd_get_error ());
55
56  if (string)
57    fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
58  else
59    fprintf (stderr, "%s: %s\n", program_name, errmsg);
60}
61
62void
63bfd_fatal (const char *string)
64{
65  bfd_nonfatal (string);
66  xexit (1);
67}
68
69void
70report (const char * format, va_list args)
71{
72  fprintf (stderr, "%s: ", program_name);
73  vfprintf (stderr, format, args);
74  putc ('\n', stderr);
75}
76
77void
78fatal VPARAMS ((const char *format, ...))
79{
80  VA_OPEN (args, format);
81  VA_FIXEDARG (args, const char *, format);
82
83  report (format, args);
84  VA_CLOSE (args);
85  xexit (1);
86}
87
88void
89non_fatal VPARAMS ((const char *format, ...))
90{
91  VA_OPEN (args, format);
92  VA_FIXEDARG (args, const char *, format);
93
94  report (format, args);
95  VA_CLOSE (args);
96}
97
98/* Set the default BFD target based on the configured target.  Doing
99   this permits the binutils to be configured for a particular target,
100   and linked against a shared BFD library which was configured for a
101   different target.  */
102
103void
104set_default_bfd_target (void)
105{
106  /* The macro TARGET is defined by Makefile.  */
107  const char *target = TARGET;
108
109  if (! bfd_set_default_target (target))
110    fatal (_("can't set BFD default target to `%s': %s"),
111	   target, bfd_errmsg (bfd_get_error ()));
112}
113
114/* After a FALSE return from bfd_check_format_matches with
115   bfd_get_error () == bfd_error_file_ambiguously_recognized, print
116   the possible matching targets.  */
117
118void
119list_matching_formats (char **p)
120{
121  fprintf (stderr, _("%s: Matching formats:"), program_name);
122  while (*p)
123    fprintf (stderr, " %s", *p++);
124  fputc ('\n', stderr);
125}
126
127/* List the supported targets.  */
128
129void
130list_supported_targets (const char *name, FILE *f)
131{
132  int t;
133  const char **targ_names = bfd_target_list ();
134
135  if (name == NULL)
136    fprintf (f, _("Supported targets:"));
137  else
138    fprintf (f, _("%s: supported targets:"), name);
139
140  for (t = 0; targ_names[t] != NULL; t++)
141    fprintf (f, " %s", targ_names[t]);
142  fprintf (f, "\n");
143  free (targ_names);
144}
145
146/* List the supported architectures.  */
147
148void
149list_supported_architectures (const char *name, FILE *f)
150{
151  const char **arch;
152
153  if (name == NULL)
154    fprintf (f, _("Supported architectures:"));
155  else
156    fprintf (f, _("%s: supported architectures:"), name);
157
158  for (arch = bfd_arch_list (); *arch; arch++)
159    fprintf (f, " %s", *arch);
160  fprintf (f, "\n");
161}
162
163/* The length of the longest architecture name + 1.  */
164#define LONGEST_ARCH sizeof ("powerpc:common")
165
166static const char *
167endian_string (enum bfd_endian endian)
168{
169  switch (endian)
170    {
171    case BFD_ENDIAN_BIG: return "big endian";
172    case BFD_ENDIAN_LITTLE: return "little endian";
173    default: return "endianness unknown";
174    }
175}
176
177/* List the targets that BFD is configured to support, each followed
178   by its endianness and the architectures it supports.  */
179
180static int
181display_target_list (void)
182{
183  char *dummy_name;
184  int t;
185  int ret = 1;
186
187  dummy_name = make_temp_file (NULL);
188  for (t = 0; bfd_target_vector[t]; t++)
189    {
190      const bfd_target *p = bfd_target_vector[t];
191      bfd *abfd = bfd_openw (dummy_name, p->name);
192      enum bfd_architecture a;
193
194      printf ("%s\n (header %s, data %s)\n", p->name,
195	      endian_string (p->header_byteorder),
196	      endian_string (p->byteorder));
197
198      if (abfd == NULL)
199	{
200          bfd_nonfatal (dummy_name);
201          ret = 0;
202	  continue;
203	}
204
205      if (! bfd_set_format (abfd, bfd_object))
206	{
207	  if (bfd_get_error () != bfd_error_invalid_operation)
208            {
209	      bfd_nonfatal (p->name);
210              ret = 0;
211            }
212	  bfd_close_all_done (abfd);
213	  continue;
214	}
215
216      for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
217	if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0))
218	  printf ("  %s\n",
219		  bfd_printable_arch_mach ((enum bfd_architecture) a, 0));
220      bfd_close_all_done (abfd);
221    }
222  unlink (dummy_name);
223  free (dummy_name);
224
225  return ret;
226}
227
228/* Print a table showing which architectures are supported for entries
229   FIRST through LAST-1 of bfd_target_vector (targets across,
230   architectures down).  */
231
232static int
233display_info_table (int first, int last)
234{
235  int t;
236  int ret = 1;
237  char *dummy_name;
238  enum bfd_architecture a;
239
240  /* Print heading of target names.  */
241  printf ("\n%*s", (int) LONGEST_ARCH, " ");
242  for (t = first; t < last && bfd_target_vector[t]; t++)
243    printf ("%s ", bfd_target_vector[t]->name);
244  putchar ('\n');
245
246  dummy_name = make_temp_file (NULL);
247  for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
248    if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0)
249      {
250	printf ("%*s ", (int) LONGEST_ARCH - 1,
251		bfd_printable_arch_mach (a, 0));
252	for (t = first; t < last && bfd_target_vector[t]; t++)
253	  {
254	    const bfd_target *p = bfd_target_vector[t];
255	    bfd_boolean ok = TRUE;
256	    bfd *abfd = bfd_openw (dummy_name, p->name);
257
258	    if (abfd == NULL)
259	      {
260		bfd_nonfatal (p->name);
261                ret = 0;
262		ok = FALSE;
263	      }
264
265	    if (ok)
266	      {
267		if (! bfd_set_format (abfd, bfd_object))
268		  {
269		    if (bfd_get_error () != bfd_error_invalid_operation)
270                      {
271		        bfd_nonfatal (p->name);
272                        ret = 0;
273                      }
274		    ok = FALSE;
275		  }
276	      }
277
278	    if (ok)
279	      {
280		if (! bfd_set_arch_mach (abfd, a, 0))
281		  ok = FALSE;
282	      }
283
284	    if (ok)
285	      printf ("%s ", p->name);
286	    else
287	      {
288		int l = strlen (p->name);
289		while (l--)
290		  putchar ('-');
291		putchar (' ');
292	      }
293	    if (abfd != NULL)
294	      bfd_close_all_done (abfd);
295	  }
296	putchar ('\n');
297      }
298  unlink (dummy_name);
299  free (dummy_name);
300
301  return ret;
302}
303
304/* Print tables of all the target-architecture combinations that
305   BFD has been configured to support.  */
306
307static int
308display_target_tables (void)
309{
310  int t;
311  int columns;
312  int ret = 1;
313  char *colum;
314
315  columns = 0;
316  colum = getenv ("COLUMNS");
317  if (colum != NULL)
318    columns = atoi (colum);
319  if (columns == 0)
320    columns = 80;
321
322  t = 0;
323  while (bfd_target_vector[t] != NULL)
324    {
325      int oldt = t, wid;
326
327      wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1;
328      ++t;
329      while (wid < columns && bfd_target_vector[t] != NULL)
330	{
331	  int newwid;
332
333	  newwid = wid + strlen (bfd_target_vector[t]->name) + 1;
334	  if (newwid >= columns)
335	    break;
336	  wid = newwid;
337	  ++t;
338	}
339      if (! display_info_table (oldt, t))
340        ret = 0;
341    }
342
343  return ret;
344}
345
346int
347display_info (void)
348{
349  printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
350  if (! display_target_list () || ! display_target_tables ())
351    return 1;
352  else
353    return 0;
354}
355
356/* Display the archive header for an element as if it were an ls -l listing:
357
358   Mode       User\tGroup\tSize\tDate               Name */
359
360void
361print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose)
362{
363  struct stat buf;
364
365  if (verbose)
366    {
367      if (bfd_stat_arch_elt (abfd, &buf) == 0)
368	{
369	  char modebuf[11];
370	  char timebuf[40];
371	  time_t when = buf.st_mtime;
372	  const char *ctime_result = (const char *) ctime (&when);
373
374	  /* POSIX format:  skip weekday and seconds from ctime output.  */
375	  sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
376
377	  mode_string (buf.st_mode, modebuf);
378	  modebuf[10] = '\0';
379	  /* POSIX 1003.2/D11 says to skip first character (entry type).  */
380	  fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1,
381		   (long) buf.st_uid, (long) buf.st_gid,
382		   (long) buf.st_size, timebuf);
383	}
384    }
385
386  fprintf (file, "%s\n", bfd_get_filename (abfd));
387}
388
389/* Return the name of a temporary file in the same directory as FILENAME.  */
390
391char *
392make_tempname (char *filename)
393{
394  static char template[] = "stXXXXXX";
395  char *tmpname;
396  char *slash = strrchr (filename, '/');
397
398#ifdef HAVE_DOS_BASED_FILE_SYSTEM
399  {
400    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
401    char *bslash = strrchr (filename, '\\');
402    if (slash == NULL || (bslash != NULL && bslash > slash))
403      slash = bslash;
404    if (slash == NULL && filename[0] != '\0' && filename[1] == ':')
405      slash = filename + 1;
406  }
407#endif
408
409  if (slash != (char *) NULL)
410    {
411      char c;
412
413      c = *slash;
414      *slash = 0;
415      tmpname = xmalloc (strlen (filename) + sizeof (template) + 2);
416      strcpy (tmpname, filename);
417#ifdef HAVE_DOS_BASED_FILE_SYSTEM
418      /* If tmpname is "X:", appending a slash will make it a root
419	 directory on drive X, which is NOT the same as the current
420	 directory on drive X.  */
421      if (tmpname[1] == ':' && tmpname[2] == '\0')
422	strcat (tmpname, ".");
423#endif
424      strcat (tmpname, "/");
425      strcat (tmpname, template);
426      mktemp (tmpname);
427      *slash = c;
428    }
429  else
430    {
431      tmpname = xmalloc (sizeof (template));
432      strcpy (tmpname, template);
433      mktemp (tmpname);
434    }
435  return tmpname;
436}
437
438/* Parse a string into a VMA, with a fatal error if it can't be
439   parsed.  */
440
441bfd_vma
442parse_vma (const char *s, const char *arg)
443{
444  bfd_vma ret;
445  const char *end;
446
447  ret = bfd_scan_vma (s, &end, 0);
448
449  if (*end != '\0')
450    fatal (_("%s: bad number: %s"), arg, s);
451
452  return ret;
453}
454
455/* Returns the size of the named file.  If the file does not
456   exist, or if it is not a real file, then a suitable non-fatal
457   error message is printed and zero is returned.  */
458
459off_t
460get_file_size (const char * file_name)
461{
462  struct stat statbuf;
463
464  if (stat (file_name, &statbuf) < 0)
465    {
466      if (errno == ENOENT)
467	non_fatal (_("'%s': No such file"), file_name);
468      else
469	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
470		   file_name, strerror (errno));
471    }
472  else if (! S_ISREG (statbuf.st_mode))
473    non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
474  else
475    return statbuf.st_size;
476
477  return 0;
478}
479
480/* Return the filename in a static buffer.  */
481
482const char *
483bfd_get_archive_filename (bfd *abfd)
484{
485  static size_t curr = 0;
486  static char *buf;
487  size_t needed;
488
489  assert (abfd != NULL);
490
491  if (!abfd->my_archive)
492    return bfd_get_filename (abfd);
493
494  needed = (strlen (bfd_get_filename (abfd->my_archive))
495	    + strlen (bfd_get_filename (abfd)) + 3);
496  if (needed > curr)
497    {
498      if (curr)
499	free (buf);
500      curr = needed + (needed >> 1);
501      buf = bfd_malloc (curr);
502      /* If we can't malloc, fail safe by returning just the file name.
503	 This function is only used when building error messages.  */
504      if (!buf)
505	{
506	  curr = 0;
507	  return bfd_get_filename (abfd);
508	}
509    }
510  sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
511	   bfd_get_filename (abfd));
512  return buf;
513}
514