Home | History | Annotate | Line # | Download | only in binutils
      1   1.1  christos /* arsup.c - Archive support for MRI compatibility
      2  1.10  christos    Copyright (C) 1992-2025 Free Software Foundation, Inc.
      3   1.1  christos 
      4   1.1  christos    This file is part of GNU Binutils.
      5   1.1  christos 
      6   1.1  christos    This program is free software; you can redistribute it and/or modify
      7   1.1  christos    it under the terms of the GNU General Public License as published by
      8   1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9   1.1  christos    (at your option) any later version.
     10   1.1  christos 
     11   1.1  christos    This program is distributed in the hope that it will be useful,
     12   1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14   1.1  christos    GNU General Public License for more details.
     15   1.1  christos 
     16   1.1  christos    You should have received a copy of the GNU General Public License
     17   1.1  christos    along with this program; if not, write to the Free Software
     18   1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19   1.1  christos    MA 02110-1301, USA.  */
     20   1.1  christos 
     21   1.1  christos 
     22   1.1  christos /* Contributed by Steve Chamberlain
     23   1.1  christos    sac (at) cygnus.com
     24   1.1  christos 
     25   1.1  christos    This file looks after requests from arparse.y, to provide the MRI
     26   1.1  christos    style librarian command syntax + 1 word LIST.  */
     27   1.1  christos 
     28   1.1  christos #include "sysdep.h"
     29   1.1  christos #include "bfd.h"
     30   1.1  christos #include "libiberty.h"
     31   1.1  christos #include "filenames.h"
     32   1.1  christos #include "bucomm.h"
     33   1.1  christos #include "arsup.h"
     34   1.1  christos 
     35   1.1  christos static void map_over_list
     36   1.1  christos   (bfd *, void (*function) (bfd *, bfd *), struct list *);
     37   1.1  christos static void ar_directory_doer (bfd *, bfd *);
     38   1.1  christos static void ar_addlib_doer (bfd *, bfd *);
     39   1.1  christos 
     40   1.1  christos extern int verbose;
     41   1.3  christos extern int deterministic;
     42   1.1  christos 
     43   1.1  christos static bfd *obfd;
     44   1.1  christos static char *real_name;
     45   1.8  christos static char *temp_name;
     46   1.8  christos static int temp_fd;
     47   1.1  christos static FILE *outfile;
     48   1.1  christos 
     49   1.1  christos static void
     50   1.1  christos map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
     51   1.1  christos {
     52   1.1  christos   bfd *head;
     53   1.1  christos 
     54   1.1  christos   if (list == NULL)
     55   1.1  christos     {
     56   1.1  christos       bfd *next;
     57   1.1  christos 
     58   1.1  christos       head = arch->archive_next;
     59   1.1  christos       while (head != NULL)
     60   1.1  christos 	{
     61   1.1  christos 	  next = head->archive_next;
     62   1.1  christos 	  function (head, (bfd *) NULL);
     63   1.1  christos 	  head = next;
     64   1.1  christos 	}
     65   1.1  christos     }
     66   1.1  christos   else
     67   1.1  christos     {
     68   1.1  christos       struct list *ptr;
     69   1.1  christos 
     70   1.1  christos       /* This may appear to be a baroque way of accomplishing what we
     71   1.1  christos 	 want.  however we have to iterate over the filenames in order
     72   1.1  christos 	 to notice where a filename is requested but does not exist in
     73   1.1  christos 	 the archive.  Ditto mapping over each file each time -- we
     74   1.1  christos 	 want to hack multiple references.  */
     75   1.1  christos       for (ptr = list; ptr; ptr = ptr->next)
     76   1.1  christos 	{
     77   1.8  christos 	  bool found = false;
     78   1.1  christos 	  bfd *prev = arch;
     79   1.1  christos 
     80   1.1  christos 	  for (head = arch->archive_next; head; head = head->archive_next)
     81   1.1  christos 	    {
     82   1.8  christos 	      if (bfd_get_filename (head) != NULL
     83   1.8  christos 		  && FILENAME_CMP (ptr->name, bfd_get_filename (head)) == 0)
     84   1.1  christos 		{
     85   1.8  christos 		  found = true;
     86   1.1  christos 		  function (head, prev);
     87   1.1  christos 		}
     88   1.1  christos 	      prev = head;
     89   1.1  christos 	    }
     90   1.1  christos 	  if (! found)
     91   1.1  christos 	    fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
     92   1.1  christos 	}
     93   1.1  christos     }
     94   1.1  christos }
     95   1.1  christos 
     96   1.1  christos 
     97   1.1  christos 
     98   1.1  christos static void
     99   1.1  christos ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
    100   1.1  christos {
    101   1.8  christos   print_arelt_descr(outfile, abfd, verbose, false);
    102   1.1  christos }
    103   1.1  christos 
    104   1.1  christos void
    105   1.1  christos ar_directory (char *ar_name, struct list *list, char *output)
    106   1.1  christos {
    107   1.1  christos   bfd *arch;
    108   1.1  christos 
    109   1.1  christos   arch = open_inarch (ar_name, (char *) NULL);
    110   1.1  christos   if (output)
    111   1.1  christos     {
    112   1.1  christos       outfile = fopen(output,"w");
    113   1.1  christos       if (outfile == 0)
    114   1.1  christos 	{
    115   1.1  christos 	  outfile = stdout;
    116   1.1  christos 	  fprintf (stderr,_("Can't open file %s\n"), output);
    117   1.1  christos 	  output = 0;
    118   1.1  christos 	}
    119   1.1  christos     }
    120   1.1  christos   else
    121   1.1  christos     outfile = stdout;
    122   1.1  christos 
    123   1.1  christos   map_over_list (arch, ar_directory_doer, list);
    124   1.1  christos 
    125   1.1  christos   bfd_close (arch);
    126   1.1  christos 
    127   1.1  christos   if (output)
    128   1.1  christos    fclose (outfile);
    129   1.1  christos }
    130   1.1  christos 
    131   1.1  christos void
    132   1.1  christos prompt (void)
    133   1.1  christos {
    134   1.1  christos   extern int interactive;
    135   1.1  christos 
    136   1.1  christos   if (interactive)
    137   1.1  christos     {
    138   1.1  christos       printf ("AR >");
    139   1.1  christos       fflush (stdout);
    140   1.1  christos     }
    141   1.1  christos }
    142   1.1  christos 
    143   1.1  christos void
    144   1.1  christos maybequit (void)
    145   1.1  christos {
    146   1.1  christos   if (! interactive)
    147   1.1  christos     xexit (9);
    148   1.1  christos }
    149   1.1  christos 
    150   1.1  christos 
    151   1.1  christos void
    152   1.1  christos ar_open (char *name, int t)
    153   1.1  christos {
    154   1.8  christos   real_name = xstrdup (name);
    155   1.8  christos   temp_name = make_tempname (real_name, &temp_fd);
    156   1.8  christos 
    157   1.8  christos   if (temp_name == NULL)
    158   1.1  christos     {
    159   1.8  christos       fprintf (stderr, _("%s: Can't open temporary file (%s)\n"),
    160   1.7  christos 	       program_name, strerror(errno));
    161   1.1  christos       maybequit ();
    162   1.1  christos       return;
    163   1.1  christos     }
    164   1.1  christos 
    165   1.8  christos   obfd = bfd_fdopenw (temp_name, NULL, temp_fd);
    166   1.1  christos 
    167   1.1  christos   if (!obfd)
    168   1.1  christos     {
    169   1.1  christos       fprintf (stderr,
    170   1.1  christos 	       _("%s: Can't open output archive %s\n"),
    171   1.8  christos 	       program_name, temp_name);
    172   1.1  christos 
    173   1.1  christos       maybequit ();
    174   1.1  christos     }
    175   1.1  christos   else
    176   1.1  christos     {
    177   1.1  christos       if (!t)
    178   1.1  christos 	{
    179   1.1  christos 	  bfd **ptr;
    180   1.1  christos 	  bfd *element;
    181   1.1  christos 	  bfd *ibfd;
    182   1.1  christos 
    183   1.8  christos #if BFD_SUPPORTS_PLUGINS
    184   1.8  christos 	  ibfd = bfd_openr (name, "plugin");
    185   1.8  christos #else
    186   1.1  christos 	  ibfd = bfd_openr (name, NULL);
    187   1.8  christos #endif
    188   1.1  christos 
    189   1.1  christos 	  if (!ibfd)
    190   1.1  christos 	    {
    191   1.1  christos 	      fprintf (stderr,_("%s: Can't open input archive %s\n"),
    192   1.1  christos 		       program_name, name);
    193   1.1  christos 	      maybequit ();
    194   1.1  christos 	      return;
    195   1.1  christos 	    }
    196   1.1  christos 
    197   1.1  christos 	  if (!bfd_check_format(ibfd, bfd_archive))
    198   1.1  christos 	    {
    199   1.1  christos 	      fprintf (stderr,
    200   1.1  christos 		       _("%s: file %s is not an archive\n"),
    201   1.1  christos 		       program_name, name);
    202   1.1  christos 	      maybequit ();
    203   1.1  christos 	      return;
    204   1.1  christos 	    }
    205   1.1  christos 
    206   1.1  christos 	  ptr = &(obfd->archive_head);
    207   1.1  christos 	  element = bfd_openr_next_archived_file (ibfd, NULL);
    208   1.1  christos 
    209   1.1  christos 	  while (element)
    210   1.1  christos 	    {
    211   1.1  christos 	      *ptr = element;
    212   1.1  christos 	      ptr = &element->archive_next;
    213   1.1  christos 	      element = bfd_openr_next_archived_file (ibfd, element);
    214   1.1  christos 	    }
    215   1.1  christos 	}
    216   1.1  christos 
    217   1.1  christos       bfd_set_format (obfd, bfd_archive);
    218   1.1  christos 
    219   1.1  christos       obfd->has_armap = 1;
    220   1.1  christos       obfd->is_thin_archive = 0;
    221   1.1  christos     }
    222   1.1  christos }
    223   1.1  christos 
    224   1.1  christos static void
    225   1.1  christos ar_addlib_doer (bfd *abfd, bfd *prev)
    226   1.1  christos {
    227   1.1  christos   /* Add this module to the output bfd.  */
    228   1.1  christos   if (prev != NULL)
    229   1.1  christos     prev->archive_next = abfd->archive_next;
    230   1.1  christos 
    231   1.1  christos   abfd->archive_next = obfd->archive_head;
    232   1.1  christos   obfd->archive_head = abfd;
    233   1.1  christos }
    234   1.1  christos 
    235   1.1  christos void
    236   1.1  christos ar_addlib (char *name, struct list *list)
    237   1.1  christos {
    238   1.1  christos   if (obfd == NULL)
    239   1.1  christos     {
    240   1.1  christos       fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
    241   1.1  christos       maybequit ();
    242   1.1  christos     }
    243   1.1  christos   else
    244   1.1  christos     {
    245   1.1  christos       bfd *arch;
    246   1.1  christos 
    247   1.1  christos       arch = open_inarch (name, (char *) NULL);
    248   1.1  christos       if (arch != NULL)
    249   1.1  christos 	map_over_list (arch, ar_addlib_doer, list);
    250   1.1  christos 
    251   1.1  christos       /* Don't close the bfd, since it will make the elements disappear.  */
    252   1.1  christos     }
    253   1.1  christos }
    254   1.1  christos 
    255   1.1  christos void
    256   1.1  christos ar_addmod (struct list *list)
    257   1.1  christos {
    258   1.1  christos   if (!obfd)
    259   1.1  christos     {
    260   1.1  christos       fprintf (stderr, _("%s: no open output archive\n"), program_name);
    261   1.1  christos       maybequit ();
    262   1.1  christos     }
    263   1.1  christos   else
    264   1.1  christos     {
    265   1.1  christos       while (list)
    266   1.1  christos 	{
    267   1.6  christos 	  bfd *abfd;
    268   1.1  christos 
    269   1.6  christos #if BFD_SUPPORTS_PLUGINS
    270   1.6  christos 	  abfd = bfd_openr (list->name, "plugin");
    271   1.6  christos #else
    272   1.6  christos 	  abfd = bfd_openr (list->name, NULL);
    273   1.6  christos #endif
    274   1.1  christos 	  if (!abfd)
    275   1.1  christos 	    {
    276   1.1  christos 	      fprintf (stderr, _("%s: can't open file %s\n"),
    277   1.1  christos 		       program_name, list->name);
    278   1.1  christos 	      maybequit ();
    279   1.1  christos 	    }
    280   1.1  christos 	  else
    281   1.1  christos 	    {
    282   1.1  christos 	      abfd->archive_next = obfd->archive_head;
    283   1.1  christos 	      obfd->archive_head = abfd;
    284   1.1  christos 	    }
    285   1.1  christos 	  list = list->next;
    286   1.1  christos 	}
    287   1.1  christos     }
    288   1.1  christos }
    289   1.1  christos 
    290   1.1  christos 
    291   1.1  christos void
    292   1.1  christos ar_clear (void)
    293   1.1  christos {
    294   1.1  christos   if (obfd)
    295   1.1  christos     obfd->archive_head = 0;
    296   1.1  christos }
    297   1.1  christos 
    298   1.1  christos void
    299   1.1  christos ar_delete (struct list *list)
    300   1.1  christos {
    301   1.1  christos   if (!obfd)
    302   1.1  christos     {
    303   1.1  christos       fprintf (stderr, _("%s: no open output archive\n"), program_name);
    304   1.1  christos       maybequit ();
    305   1.1  christos     }
    306   1.1  christos   else
    307   1.1  christos     {
    308   1.1  christos       while (list)
    309   1.1  christos 	{
    310   1.1  christos 	  /* Find this name in the archive.  */
    311   1.1  christos 	  bfd *member = obfd->archive_head;
    312   1.1  christos 	  bfd **prev = &(obfd->archive_head);
    313   1.1  christos 	  int found = 0;
    314   1.1  christos 
    315   1.1  christos 	  while (member)
    316   1.1  christos 	    {
    317   1.8  christos 	      if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
    318   1.1  christos 		{
    319   1.1  christos 		  *prev = member->archive_next;
    320   1.1  christos 		  found = 1;
    321   1.1  christos 		}
    322   1.1  christos 	      else
    323   1.1  christos 		prev = &(member->archive_next);
    324   1.1  christos 
    325   1.1  christos 	      member = member->archive_next;
    326   1.1  christos 	    }
    327   1.1  christos 
    328   1.1  christos 	  if (!found)
    329   1.1  christos 	    {
    330   1.1  christos 	      fprintf (stderr, _("%s: can't find module file %s\n"),
    331   1.1  christos 		       program_name, list->name);
    332   1.1  christos 	      maybequit ();
    333   1.1  christos 	    }
    334   1.1  christos 
    335   1.1  christos 	  list = list->next;
    336   1.1  christos 	}
    337   1.1  christos     }
    338   1.1  christos }
    339   1.1  christos 
    340   1.1  christos void
    341   1.1  christos ar_save (void)
    342   1.1  christos {
    343   1.1  christos   if (!obfd)
    344   1.1  christos     {
    345   1.1  christos       fprintf (stderr, _("%s: no open output archive\n"), program_name);
    346   1.1  christos       maybequit ();
    347   1.1  christos     }
    348   1.1  christos   else
    349   1.1  christos     {
    350   1.8  christos       struct stat target_stat;
    351   1.1  christos 
    352   1.3  christos       if (deterministic > 0)
    353   1.3  christos         obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
    354   1.3  christos 
    355   1.8  christos       temp_fd = dup (temp_fd);
    356   1.1  christos       bfd_close (obfd);
    357   1.1  christos 
    358   1.8  christos       if (stat (real_name, &target_stat) != 0)
    359   1.8  christos 	{
    360   1.8  christos 	  /* The temp file created in ar_open has mode 0600 as per mkstemp.
    361   1.8  christos 	     Create the real empty output file here so smart_rename will
    362   1.8  christos 	     update the mode according to the process umask.  */
    363   1.8  christos 	  obfd = bfd_openw (real_name, NULL);
    364   1.8  christos 	  if (obfd != NULL)
    365   1.8  christos 	    {
    366   1.8  christos 	      bfd_set_format (obfd, bfd_archive);
    367   1.8  christos 	      bfd_close (obfd);
    368   1.8  christos 	    }
    369   1.8  christos 	}
    370   1.8  christos 
    371   1.8  christos       smart_rename (temp_name, real_name, temp_fd, NULL, false);
    372   1.1  christos       obfd = 0;
    373   1.8  christos       free (temp_name);
    374   1.8  christos       free (real_name);
    375   1.1  christos     }
    376   1.1  christos }
    377   1.1  christos 
    378   1.1  christos void
    379   1.1  christos ar_replace (struct list *list)
    380   1.1  christos {
    381   1.1  christos   if (!obfd)
    382   1.1  christos     {
    383   1.1  christos       fprintf (stderr, _("%s: no open output archive\n"), program_name);
    384   1.1  christos       maybequit ();
    385   1.1  christos     }
    386   1.1  christos   else
    387   1.1  christos     {
    388   1.1  christos       while (list)
    389   1.1  christos 	{
    390   1.1  christos 	  /* Find this name in the archive.  */
    391   1.1  christos 	  bfd *member = obfd->archive_head;
    392   1.1  christos 	  bfd **prev = &(obfd->archive_head);
    393   1.1  christos 	  int found = 0;
    394   1.1  christos 
    395   1.1  christos 	  while (member)
    396   1.1  christos 	    {
    397   1.8  christos 	      if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
    398   1.1  christos 		{
    399   1.1  christos 		  /* Found the one to replace.  */
    400   1.6  christos 		  bfd *abfd = bfd_openr (list->name, NULL);
    401   1.1  christos 
    402   1.1  christos 		  if (!abfd)
    403   1.1  christos 		    {
    404   1.1  christos 		      fprintf (stderr, _("%s: can't open file %s\n"),
    405   1.1  christos 			       program_name, list->name);
    406   1.1  christos 		      maybequit ();
    407   1.1  christos 		    }
    408   1.1  christos 		  else
    409   1.1  christos 		    {
    410   1.1  christos 		      *prev = abfd;
    411   1.1  christos 		      abfd->archive_next = member->archive_next;
    412   1.1  christos 		      found = 1;
    413   1.1  christos 		    }
    414   1.1  christos 		}
    415   1.1  christos 	      else
    416   1.1  christos 		{
    417   1.1  christos 		  prev = &(member->archive_next);
    418   1.1  christos 		}
    419   1.1  christos 	      member = member->archive_next;
    420   1.1  christos 	    }
    421   1.1  christos 
    422   1.1  christos 	  if (!found)
    423   1.1  christos 	    {
    424   1.6  christos 	      bfd *abfd = bfd_openr (list->name, NULL);
    425   1.1  christos 
    426   1.1  christos 	      fprintf (stderr,_("%s: can't find module file %s\n"),
    427   1.1  christos 		       program_name, list->name);
    428   1.1  christos 	      if (!abfd)
    429   1.1  christos 		{
    430   1.1  christos 		  fprintf (stderr, _("%s: can't open file %s\n"),
    431   1.1  christos 			   program_name, list->name);
    432   1.1  christos 		  maybequit ();
    433   1.1  christos 		}
    434   1.1  christos 	      else
    435   1.1  christos 		*prev = abfd;
    436   1.1  christos 	    }
    437   1.1  christos 
    438   1.1  christos 	  list = list->next;
    439   1.1  christos 	}
    440   1.1  christos     }
    441   1.1  christos }
    442   1.1  christos 
    443   1.1  christos /* And I added this one.  */
    444   1.1  christos void
    445   1.1  christos ar_list (void)
    446   1.1  christos {
    447   1.1  christos   if (!obfd)
    448   1.1  christos     {
    449   1.1  christos       fprintf (stderr, _("%s: no open output archive\n"), program_name);
    450   1.1  christos       maybequit ();
    451   1.1  christos     }
    452   1.1  christos   else
    453   1.1  christos     {
    454   1.1  christos       bfd *abfd;
    455   1.1  christos 
    456   1.1  christos       outfile = stdout;
    457   1.1  christos       verbose =1 ;
    458   1.1  christos       printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
    459   1.1  christos 
    460   1.1  christos       for (abfd = obfd->archive_head;
    461   1.1  christos 	   abfd != (bfd *)NULL;
    462   1.1  christos 	   abfd = abfd->archive_next)
    463   1.1  christos 	ar_directory_doer (abfd, (bfd *) NULL);
    464   1.1  christos     }
    465   1.1  christos }
    466   1.1  christos 
    467   1.1  christos void
    468   1.1  christos ar_end (void)
    469   1.1  christos {
    470   1.1  christos   if (obfd)
    471   1.1  christos     {
    472   1.9  christos       const char *filename = bfd_get_filename (obfd);
    473   1.9  christos       bfd_close_all_done (obfd);
    474   1.9  christos       unlink (filename);
    475   1.1  christos     }
    476   1.1  christos }
    477   1.1  christos 
    478   1.1  christos void
    479   1.1  christos ar_extract (struct list *list)
    480   1.1  christos {
    481   1.1  christos   if (!obfd)
    482   1.1  christos     {
    483   1.1  christos       fprintf (stderr, _("%s: no open archive\n"), program_name);
    484   1.1  christos       maybequit ();
    485   1.1  christos     }
    486   1.1  christos   else
    487   1.1  christos     {
    488   1.1  christos       while (list)
    489   1.1  christos 	{
    490   1.1  christos 	  /* Find this name in the archive.  */
    491   1.1  christos 	  bfd *member = obfd->archive_head;
    492   1.1  christos 	  int found = 0;
    493   1.1  christos 
    494   1.1  christos 	  while (member && !found)
    495   1.1  christos 	    {
    496   1.8  christos 	      if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
    497   1.1  christos 		{
    498   1.1  christos 		  extract_file (member);
    499   1.1  christos 		  found = 1;
    500   1.1  christos 		}
    501   1.1  christos 
    502   1.1  christos 	      member = member->archive_next;
    503   1.1  christos 	    }
    504   1.1  christos 
    505   1.1  christos 	  if (!found)
    506   1.1  christos 	    {
    507   1.6  christos 	      bfd_openr (list->name, NULL);
    508   1.1  christos 	      fprintf (stderr, _("%s: can't find module file %s\n"),
    509   1.1  christos 		       program_name, list->name);
    510   1.1  christos 	    }
    511   1.1  christos 
    512   1.1  christos 	  list = list->next;
    513   1.1  christos 	}
    514   1.1  christos     }
    515   1.1  christos }
    516