Home | History | Annotate | Line # | Download | only in binutils
arsup.c revision 1.1.1.6
      1 /* arsup.c - Archive support for MRI compatibility
      2    Copyright (C) 1992-2022 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 (at) 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       bfd_cache_close (obfd);
    473       unlink (bfd_get_filename (obfd));
    474     }
    475 }
    476 
    477 void
    478 ar_extract (struct list *list)
    479 {
    480   if (!obfd)
    481     {
    482       fprintf (stderr, _("%s: no open archive\n"), program_name);
    483       maybequit ();
    484     }
    485   else
    486     {
    487       while (list)
    488 	{
    489 	  /* Find this name in the archive.  */
    490 	  bfd *member = obfd->archive_head;
    491 	  int found = 0;
    492 
    493 	  while (member && !found)
    494 	    {
    495 	      if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
    496 		{
    497 		  extract_file (member);
    498 		  found = 1;
    499 		}
    500 
    501 	      member = member->archive_next;
    502 	    }
    503 
    504 	  if (!found)
    505 	    {
    506 	      bfd_openr (list->name, NULL);
    507 	      fprintf (stderr, _("%s: can't find module file %s\n"),
    508 		       program_name, list->name);
    509 	    }
    510 
    511 	  list = list->next;
    512 	}
    513     }
    514 }
    515