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