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