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