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