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@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 35static void map_over_list 36 (bfd *, void (*function) (bfd *, bfd *), struct list *); 37static void ar_directory_doer (bfd *, bfd *); 38static void ar_addlib_doer (bfd *, bfd *); 39 40extern int verbose; 41extern int deterministic; 42 43static bfd *obfd; 44static char *real_name; 45static char *temp_name; 46static int temp_fd; 47static FILE *outfile; 48 49static void 50map_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 98static void 99ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED) 100{ 101 print_arelt_descr(outfile, abfd, verbose, false); 102} 103 104void 105ar_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 131void 132prompt (void) 133{ 134 extern int interactive; 135 136 if (interactive) 137 { 138 printf ("AR >"); 139 fflush (stdout); 140 } 141} 142 143void 144maybequit (void) 145{ 146 if (! interactive) 147 xexit (9); 148} 149 150 151void 152ar_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 224static void 225ar_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 235void 236ar_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 255void 256ar_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 291void 292ar_clear (void) 293{ 294 if (obfd) 295 obfd->archive_head = 0; 296} 297 298void 299ar_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 340void 341ar_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 378void 379ar_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. */ 444void 445ar_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 467void 468ar_end (void) 469{ 470 if (obfd) 471 { 472 bfd_cache_close (obfd); 473 unlink (bfd_get_filename (obfd)); 474 } 475} 476 477void 478ar_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