1 /* arsup.c - Archive support for MRI compatibility
2    Copyright (C) 1992-2021 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
map_over_list(bfd * arch,void (* function)(bfd *,bfd *),struct list * list)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
ar_directory_doer(bfd * abfd,bfd * ignore ATTRIBUTE_UNUSED)99 ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
100 {
101   print_arelt_descr(outfile, abfd, verbose, false);
102 }
103 
104 void
ar_directory(char * ar_name,struct list * list,char * output)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
prompt(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
maybequit(void)144 maybequit (void)
145 {
146   if (! interactive)
147     xexit (9);
148 }
149 
150 
151 void
ar_open(char * name,int t)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
ar_addlib_doer(bfd * abfd,bfd * prev)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
ar_addlib(char * name,struct list * list)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
ar_addmod(struct list * list)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
ar_clear(void)292 ar_clear (void)
293 {
294   if (obfd)
295     obfd->archive_head = 0;
296 }
297 
298 void
ar_delete(struct list * list)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
ar_save(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
ar_replace(struct list * list)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
ar_list(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
ar_end(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
ar_extract(struct list * list)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