arch.c revision 1.190
1/* $NetBSD: arch.c,v 1.190 2020/12/20 13:38:43 rillig Exp $ */ 2 3/* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35/* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71/* Manipulate libraries, archives and their members. 72 * 73 * The first time an archive is referenced, all of its members' headers are 74 * read and cached and the archive closed again. All cached archives are kept 75 * on a list which is searched each time an archive member is referenced. 76 * 77 * The interface to this module is: 78 * 79 * Arch_Init Initialize this module. 80 * 81 * Arch_End Clean up this module. 82 * 83 * Arch_ParseArchive 84 * Parse an archive specification such as 85 * "archive.a(member1 member2)". 86 * 87 * Arch_Touch Alter the modification time of the archive 88 * member described by the given node to be 89 * the time when make was started. 90 * 91 * Arch_TouchLib Update the modification time of the library 92 * described by the given node. This is special 93 * because it also updates the modification time 94 * of the library's table of contents. 95 * 96 * Arch_UpdateMTime 97 * Find the modification time of a member of 98 * an archive *in the archive* and place it in the 99 * member's GNode. 100 * 101 * Arch_UpdateMemberMTime 102 * Find the modification time of a member of 103 * an archive. Called when the member doesn't 104 * already exist. Looks in the archive for the 105 * modification time. Returns the modification 106 * time. 107 * 108 * Arch_FindLib Search for a library along a path. The 109 * library name in the GNode should be in 110 * -l<name> format. 111 * 112 * Arch_LibOODate Decide if a library node is out-of-date. 113 */ 114 115#include <sys/types.h> 116#include <sys/stat.h> 117#include <sys/time.h> 118#include <sys/param.h> 119 120#include <ar.h> 121#include <utime.h> 122 123#include "make.h" 124#include "dir.h" 125#include "config.h" 126 127/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */ 128MAKE_RCSID("$NetBSD: arch.c,v 1.190 2020/12/20 13:38:43 rillig Exp $"); 129 130typedef struct List ArchList; 131typedef struct ListNode ArchListNode; 132 133static ArchList archives; /* The archives we've already examined */ 134 135typedef struct Arch { 136 char *name; /* Name of archive */ 137 HashTable members; /* All the members of the archive described 138 * by <name, struct ar_hdr *> key/value pairs */ 139 char *fnametab; /* Extended name table strings */ 140 size_t fnamesize; /* Size of the string table */ 141} Arch; 142 143static FILE *ArchFindMember(const char *, const char *, 144 struct ar_hdr *, const char *); 145#if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) 146#define SVR4ARCHIVES 147static int ArchSVR4Entry(Arch *, char *, size_t, FILE *); 148#endif 149 150#ifdef CLEANUP 151static void 152ArchFree(void *ap) 153{ 154 Arch *a = ap; 155 HashIter hi; 156 157 /* Free memory from hash entries */ 158 HashIter_Init(&hi, &a->members); 159 while (HashIter_Next(&hi) != NULL) 160 free(hi.entry->value); 161 162 free(a->name); 163 free(a->fnametab); 164 HashTable_Done(&a->members); 165 free(a); 166} 167#endif 168 169 170/* 171 * Parse an archive specification such as "archive.a(member1 member2.${EXT})", 172 * adding nodes for the expanded members to gns. Nodes are created as 173 * necessary. 174 * 175 * Input: 176 * pp The start of the specification. 177 * gns The list on which to place the nodes. 178 * ctxt The context in which to expand variables. 179 * 180 * Output: 181 * return TRUE if it was a valid specification. 182 * *pp Points to the first non-space after the archive spec. 183 */ 184Boolean 185Arch_ParseArchive(char **pp, GNodeList *gns, GNode *ctxt) 186{ 187 char *cp; /* Pointer into line */ 188 GNode *gn; /* New node */ 189 char *libName; /* Library-part of specification */ 190 char *libName_freeIt = NULL; 191 char *memName; /* Member-part of specification */ 192 char saveChar; /* Ending delimiter of member-name */ 193 Boolean expandLibName; /* Whether the parsed libName contains 194 * variable expressions that need to be 195 * expanded */ 196 197 libName = *pp; 198 expandLibName = FALSE; 199 200 for (cp = libName; *cp != '(' && *cp != '\0';) { 201 if (*cp == '$') { 202 /* Expand nested variable expressions. */ 203 /* XXX: This code can probably be shortened. */ 204 const char *nested_p = cp; 205 FStr result; 206 Boolean isError; 207 208 /* XXX: is expanded twice: once here and once below */ 209 (void)Var_Parse(&nested_p, ctxt, 210 VARE_WANTRES | VARE_UNDEFERR, &result); 211 /* TODO: handle errors */ 212 isError = result.str == var_Error; 213 FStr_Done(&result); 214 if (isError) 215 return FALSE; 216 217 expandLibName = TRUE; 218 cp += nested_p - cp; 219 } else 220 cp++; 221 } 222 223 *cp++ = '\0'; 224 if (expandLibName) { 225 (void)Var_Subst(libName, ctxt, VARE_WANTRES | VARE_UNDEFERR, 226 &libName); 227 /* TODO: handle errors */ 228 libName_freeIt = libName; 229 } 230 231 232 for (;;) { 233 /* 234 * First skip to the start of the member's name, mark that 235 * place and skip to the end of it (either white-space or 236 * a close paren). 237 */ 238 Boolean doSubst = FALSE; 239 240 pp_skip_whitespace(&cp); 241 242 memName = cp; 243 while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) { 244 if (*cp == '$') { 245 /* Expand nested variable expressions. */ 246 /* XXX: This code can probably be shortened. */ 247 FStr result; 248 Boolean isError; 249 const char *nested_p = cp; 250 251 (void)Var_Parse(&nested_p, ctxt, 252 VARE_WANTRES | VARE_UNDEFERR, 253 &result); 254 /* TODO: handle errors */ 255 isError = result.str == var_Error; 256 FStr_Done(&result); 257 258 if (isError) 259 return FALSE; 260 261 doSubst = TRUE; 262 cp += nested_p - cp; 263 } else { 264 cp++; 265 } 266 } 267 268 /* 269 * If the specification ends without a closing parenthesis, 270 * chances are there's something wrong (like a missing 271 * backslash), so it's better to return failure than allow 272 * such things to happen 273 */ 274 if (*cp == '\0') { 275 Parse_Error(PARSE_FATAL, 276 "No closing parenthesis " 277 "in archive specification"); 278 return FALSE; 279 } 280 281 /* 282 * If we didn't move anywhere, we must be done 283 */ 284 if (cp == memName) 285 break; 286 287 saveChar = *cp; 288 *cp = '\0'; 289 290 /* 291 * XXX: This should be taken care of intelligently by 292 * SuffExpandChildren, both for the archive and the member 293 * portions. 294 */ 295 /* 296 * If member contains variables, try and substitute for them. 297 * This will slow down archive specs with dynamic sources, of 298 * course, since we'll be (non-)substituting them three 299 * times, but them's the breaks -- we need to do this since 300 * SuffExpandChildren calls us, otherwise we could assume the 301 * thing would be taken care of later. 302 */ 303 if (doSubst) { 304 char *fullName; 305 char *p; 306 char *unexpandedMemName = memName; 307 308 (void)Var_Subst(memName, ctxt, 309 VARE_WANTRES | VARE_UNDEFERR, 310 &memName); 311 /* TODO: handle errors */ 312 313 /* 314 * Now form an archive spec and recurse to deal with 315 * nested variables and multi-word variable values. 316 */ 317 fullName = str_concat4(libName, "(", memName, ")"); 318 p = fullName; 319 320 if (strchr(memName, '$') != NULL && 321 strcmp(memName, unexpandedMemName) == 0) { 322 /* 323 * Must contain dynamic sources, so we can't 324 * deal with it now. Just create an ARCHV node 325 * for the thing and let SuffExpandChildren 326 * handle it. 327 */ 328 gn = Targ_GetNode(fullName); 329 gn->type |= OP_ARCHV; 330 Lst_Append(gns, gn); 331 332 } else if (!Arch_ParseArchive(&p, gns, ctxt)) { 333 /* Error in nested call. */ 334 free(fullName); 335 /* XXX: does unexpandedMemName leak? */ 336 return FALSE; 337 } 338 free(fullName); 339 /* XXX: does unexpandedMemName leak? */ 340 341 } else if (Dir_HasWildcards(memName)) { 342 StringList members = LST_INIT; 343 Dir_Expand(memName, &dirSearchPath, &members); 344 345 while (!Lst_IsEmpty(&members)) { 346 char *member = Lst_Dequeue(&members); 347 char *fullname = str_concat4(libName, "(", 348 member, ")"); 349 free(member); 350 351 gn = Targ_GetNode(fullname); 352 free(fullname); 353 354 gn->type |= OP_ARCHV; 355 Lst_Append(gns, gn); 356 } 357 Lst_Done(&members); 358 359 } else { 360 char *fullname = str_concat4(libName, "(", memName, 361 ")"); 362 gn = Targ_GetNode(fullname); 363 free(fullname); 364 365 /* 366 * We've found the node, but have to make sure the 367 * rest of the world knows it's an archive member, 368 * without having to constantly check for parentheses, 369 * so we type the thing with the OP_ARCHV bit before 370 * we place it on the end of the provided list. 371 */ 372 gn->type |= OP_ARCHV; 373 Lst_Append(gns, gn); 374 } 375 if (doSubst) 376 free(memName); 377 378 *cp = saveChar; 379 } 380 381 free(libName_freeIt); 382 383 cp++; /* skip the ')' */ 384 /* We promised that pp would be set up at the next non-space. */ 385 pp_skip_whitespace(&cp); 386 *pp = cp; 387 return TRUE; 388} 389 390/* Locate a member of an archive, given the path of the archive and the path 391 * of the desired member. 392 * 393 * Input: 394 * archive Path to the archive 395 * member Name of member; only its basename is used. 396 * addToCache TRUE if archive should be cached if not already so. 397 * 398 * Results: 399 * The ar_hdr for the member, or NULL. 400 * 401 * See ArchFindMember for an almost identical copy of this code. 402 */ 403static struct ar_hdr * 404ArchStatMember(const char *archive, const char *member, Boolean addToCache) 405{ 406#define AR_MAX_NAME_LEN (sizeof arh.ar_name - 1) 407 FILE *arch; 408 size_t size; /* Size of archive member */ 409 char magic[SARMAG]; 410 ArchListNode *ln; 411 Arch *ar; /* Archive descriptor */ 412 struct ar_hdr arh; /* archive-member header for reading archive */ 413 char memName[MAXPATHLEN + 1]; 414 /* Current member name while hashing. */ 415 416 /* 417 * Because of space constraints and similar things, files are archived 418 * using their basename, not the entire path. 419 */ 420 member = str_basename(member); 421 422 for (ln = archives.first; ln != NULL; ln = ln->next) { 423 const Arch *a = ln->datum; 424 if (strcmp(a->name, archive) == 0) 425 break; 426 } 427 428 if (ln != NULL) { 429 struct ar_hdr *hdr; 430 431 ar = ln->datum; 432 hdr = HashTable_FindValue(&ar->members, member); 433 if (hdr != NULL) 434 return hdr; 435 436 { 437 /* Try truncated name */ 438 char copy[AR_MAX_NAME_LEN + 1]; 439 size_t len = strlen(member); 440 441 if (len > AR_MAX_NAME_LEN) { 442 snprintf(copy, sizeof copy, "%s", member); 443 hdr = HashTable_FindValue(&ar->members, copy); 444 } 445 return hdr; 446 } 447 } 448 449 if (!addToCache) { 450 /* 451 * Caller doesn't want the thing cached, just use 452 * ArchFindMember to read the header for the member out and 453 * close down the stream again. Since the archive is not to be 454 * cached, we assume there's no need to allocate extra room 455 * for the header we're returning, so just declare it static. 456 */ 457 static struct ar_hdr sarh; 458 459 arch = ArchFindMember(archive, member, &sarh, "r"); 460 if (arch == NULL) 461 return NULL; 462 463 fclose(arch); 464 return &sarh; 465 } 466 467 /* 468 * We don't have this archive on the list yet, so we want to find out 469 * everything that's in it and cache it so we can get at it quickly. 470 */ 471 arch = fopen(archive, "r"); 472 if (arch == NULL) 473 return NULL; 474 475 /* 476 * We use the ARMAG string to make sure this is an archive we 477 * can handle... 478 */ 479 if (fread(magic, SARMAG, 1, arch) != 1 || 480 strncmp(magic, ARMAG, SARMAG) != 0) { 481 (void)fclose(arch); 482 return NULL; 483 } 484 485 ar = bmake_malloc(sizeof *ar); 486 ar->name = bmake_strdup(archive); 487 ar->fnametab = NULL; 488 ar->fnamesize = 0; 489 HashTable_Init(&ar->members); 490 memName[AR_MAX_NAME_LEN] = '\0'; 491 492 while (fread(&arh, sizeof arh, 1, arch) == 1) { 493 char *nameend; 494 495 /* If the header is bogus, there's no way we can recover. */ 496 if (strncmp(arh.ar_fmag, ARFMAG, sizeof arh.ar_fmag) != 0) 497 goto badarch; 498 499 /* 500 * We need to advance the stream's pointer to the start of the 501 * next header. Files are padded with newlines to an even-byte 502 * boundary, so we need to extract the size of the file from 503 * the 'size' field of the header and round it up during the 504 * seek. 505 */ 506 arh.ar_size[sizeof arh.ar_size - 1] = '\0'; 507 size = (size_t)strtol(arh.ar_size, NULL, 10); 508 509 memcpy(memName, arh.ar_name, sizeof arh.ar_name); 510 nameend = memName + AR_MAX_NAME_LEN; 511 while (nameend > memName && *nameend == ' ') 512 nameend--; 513 nameend[1] = '\0'; 514 515#ifdef SVR4ARCHIVES 516 /* 517 * svr4 names are slash-terminated. 518 * Also svr4 extended the AR format. 519 */ 520 if (memName[0] == '/') { 521 /* svr4 magic mode; handle it */ 522 switch (ArchSVR4Entry(ar, memName, size, arch)) { 523 case -1: /* Invalid data */ 524 goto badarch; 525 case 0: /* List of files entry */ 526 continue; 527 default: /* Got the entry */ 528 break; 529 } 530 } else { 531 if (nameend[0] == '/') 532 nameend[0] = '\0'; 533 } 534#endif 535 536#ifdef AR_EFMT1 537 /* 538 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 539 * first <namelen> bytes of the file 540 */ 541 if (strncmp(memName, AR_EFMT1, sizeof AR_EFMT1 - 1) == 0 && 542 ch_isdigit(memName[sizeof AR_EFMT1 - 1])) { 543 544 int elen = atoi(memName + sizeof AR_EFMT1 - 1); 545 546 if ((unsigned int)elen > MAXPATHLEN) 547 goto badarch; 548 if (fread(memName, (size_t)elen, 1, arch) != 1) 549 goto badarch; 550 memName[elen] = '\0'; 551 if (fseek(arch, -elen, SEEK_CUR) != 0) 552 goto badarch; 553 if (DEBUG(ARCH) || DEBUG(MAKE)) 554 debug_printf( 555 "ArchStatMember: " 556 "Extended format entry for %s\n", 557 memName); 558 } 559#endif 560 561 { 562 struct ar_hdr *cached_hdr = bmake_malloc( 563 sizeof *cached_hdr); 564 memcpy(cached_hdr, &arh, sizeof arh); 565 HashTable_Set(&ar->members, memName, cached_hdr); 566 } 567 568 if (fseek(arch, ((long)size + 1) & ~1, SEEK_CUR) != 0) 569 goto badarch; 570 } 571 572 fclose(arch); 573 574 Lst_Append(&archives, ar); 575 576 /* 577 * Now that the archive has been read and cached, we can look into 578 * the addToCache table to find the desired member's header. 579 */ 580 return HashTable_FindValue(&ar->members, member); 581 582badarch: 583 fclose(arch); 584 HashTable_Done(&ar->members); 585 free(ar->fnametab); 586 free(ar); 587 return NULL; 588} 589 590#ifdef SVR4ARCHIVES 591/* 592 * Parse an SVR4 style entry that begins with a slash. 593 * If it is "//", then load the table of filenames. 594 * If it is "/<offset>", then try to substitute the long file name 595 * from offset of a table previously read. 596 * If a table is read, the file pointer is moved to the next archive member. 597 * 598 * Results: 599 * -1: Bad data in archive 600 * 0: A table was loaded from the file 601 * 1: Name was successfully substituted from table 602 * 2: Name was not successfully substituted from table 603 */ 604static int 605ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch) 606{ 607#define ARLONGNAMES1 "//" 608#define ARLONGNAMES2 "/ARFILENAMES" 609 size_t entry; 610 char *ptr, *eptr; 611 612 if (strncmp(inout_name, ARLONGNAMES1, sizeof ARLONGNAMES1 - 1) == 0 || 613 strncmp(inout_name, ARLONGNAMES2, sizeof ARLONGNAMES2 - 1) == 0) { 614 615 if (ar->fnametab != NULL) { 616 DEBUG0(ARCH, 617 "Attempted to redefine an SVR4 name table\n"); 618 return -1; 619 } 620 621 /* 622 * This is a table of archive names, so we build one for 623 * ourselves 624 */ 625 ar->fnametab = bmake_malloc(size); 626 ar->fnamesize = size; 627 628 if (fread(ar->fnametab, size, 1, arch) != 1) { 629 DEBUG0(ARCH, "Reading an SVR4 name table failed\n"); 630 return -1; 631 } 632 eptr = ar->fnametab + size; 633 for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++) 634 if (*ptr == '/') { 635 entry++; 636 *ptr = '\0'; 637 } 638 DEBUG1(ARCH, "Found svr4 archive name table with %lu entries\n", 639 (unsigned long)entry); 640 return 0; 641 } 642 643 if (inout_name[1] == ' ' || inout_name[1] == '\0') 644 return 2; 645 646 entry = (size_t)strtol(&inout_name[1], &eptr, 0); 647 if ((*eptr != ' ' && *eptr != '\0') || eptr == &inout_name[1]) { 648 DEBUG1(ARCH, "Could not parse SVR4 name %s\n", inout_name); 649 return 2; 650 } 651 if (entry >= ar->fnamesize) { 652 DEBUG2(ARCH, "SVR4 entry offset %s is greater than %lu\n", 653 inout_name, (unsigned long)ar->fnamesize); 654 return 2; 655 } 656 657 DEBUG2(ARCH, "Replaced %s with %s\n", inout_name, &ar->fnametab[entry]); 658 659 snprintf(inout_name, MAXPATHLEN + 1, "%s", &ar->fnametab[entry]); 660 return 1; 661} 662#endif 663 664 665static Boolean 666ArchiveMember_HasName(const struct ar_hdr *hdr, 667 const char *name, size_t namelen) 668{ 669 const size_t ar_name_len = sizeof hdr->ar_name; 670 const char *ar_name = hdr->ar_name; 671 672 if (strncmp(ar_name, name, namelen) != 0) 673 return FALSE; 674 675 if (namelen >= ar_name_len) 676 return namelen == ar_name_len; 677 678 /* hdr->ar_name is space-padded to the right. */ 679 if (ar_name[namelen] == ' ') 680 return TRUE; 681 682 /* In archives created by GNU binutils 2.27, the member names end with 683 * a slash. */ 684 if (ar_name[namelen] == '/' && 685 (namelen == ar_name_len || ar_name[namelen + 1] == ' ')) 686 return TRUE; 687 688 return FALSE; 689} 690 691/* Locate a member of an archive, given the path of the archive and the path 692 * of the desired member. 693 * 694 * Input: 695 * archive Path to the archive 696 * member Name of member. If it is a path, only the last 697 * component is used. 698 * out_arh Archive header to be filled in 699 * mode "r" for read-only access, "r+" for read-write access 700 * 701 * Output: 702 * return The archive file, positioned at the start of the 703 * member's struct ar_hdr, or NULL if the member doesn't 704 * exist. 705 * *out_arh The current struct ar_hdr for member. 706 * 707 * See ArchStatMember for an almost identical copy of this code. 708 */ 709static FILE * 710ArchFindMember(const char *archive, const char *member, struct ar_hdr *out_arh, 711 const char *mode) 712{ 713 FILE *arch; /* Stream to archive */ 714 int size; /* Size of archive member */ 715 char magic[SARMAG]; 716 size_t len; 717 718 arch = fopen(archive, mode); 719 if (arch == NULL) 720 return NULL; 721 722 /* 723 * We use the ARMAG string to make sure this is an archive we 724 * can handle... 725 */ 726 if (fread(magic, SARMAG, 1, arch) != 1 || 727 strncmp(magic, ARMAG, SARMAG) != 0) { 728 fclose(arch); 729 return NULL; 730 } 731 732 /* 733 * Because of space constraints and similar things, files are archived 734 * using their basename, not the entire path. 735 */ 736 member = str_basename(member); 737 738 len = strlen(member); 739 740 while (fread(out_arh, sizeof *out_arh, 1, arch) == 1) { 741 742 if (strncmp(out_arh->ar_fmag, ARFMAG, 743 sizeof out_arh->ar_fmag) != 0) { 744 /* 745 * The header is bogus, so the archive is bad 746 * and there's no way we can recover... 747 */ 748 fclose(arch); 749 return NULL; 750 } 751 752 DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n", 753 archive, 754 (int)sizeof out_arh->ar_name, out_arh->ar_name, 755 (int)sizeof out_arh->ar_date, out_arh->ar_date); 756 757 if (ArchiveMember_HasName(out_arh, member, len)) { 758 /* 759 * To make life easier for callers that want to update 760 * the archive, we reposition the file at the start of 761 * the header we just read before we return the 762 * stream. In a more general situation, it might be 763 * better to leave the file at the actual member, 764 * rather than its header, but not here. 765 */ 766 if (fseek(arch, -(long)sizeof *out_arh, SEEK_CUR) != 767 0) { 768 fclose(arch); 769 return NULL; 770 } 771 return arch; 772 } 773 774#ifdef AR_EFMT1 775 /* 776 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 777 * first <namelen> bytes of the file 778 */ 779 if (strncmp(out_arh->ar_name, AR_EFMT1, sizeof AR_EFMT1 - 1) == 780 0 && 781 (ch_isdigit(out_arh->ar_name[sizeof AR_EFMT1 - 1]))) { 782 int elen = atoi(&out_arh->ar_name[sizeof AR_EFMT1 - 1]); 783 char ename[MAXPATHLEN + 1]; 784 785 if ((unsigned int)elen > MAXPATHLEN) { 786 fclose(arch); 787 return NULL; 788 } 789 if (fread(ename, (size_t)elen, 1, arch) != 1) { 790 fclose(arch); 791 return NULL; 792 } 793 ename[elen] = '\0'; 794 if (DEBUG(ARCH) || DEBUG(MAKE)) 795 debug_printf( 796 "ArchFindMember: " 797 "Extended format entry for %s\n", 798 ename); 799 if (strncmp(ename, member, len) == 0) { 800 /* Found as extended name */ 801 if (fseek(arch, 802 -(long)sizeof(struct ar_hdr) - elen, 803 SEEK_CUR) != 0) { 804 fclose(arch); 805 return NULL; 806 } 807 return arch; 808 } 809 if (fseek(arch, -elen, SEEK_CUR) != 0) { 810 fclose(arch); 811 return NULL; 812 } 813 } 814#endif 815 816 /* 817 * This isn't the member we're after, so we need to advance the 818 * stream's pointer to the start of the next header. Files are 819 * padded with newlines to an even-byte boundary, so we need to 820 * extract the size of the file from the 'size' field of the 821 * header and round it up during the seek. 822 */ 823 out_arh->ar_size[sizeof out_arh->ar_size - 1] = '\0'; 824 size = (int)strtol(out_arh->ar_size, NULL, 10); 825 if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) { 826 fclose(arch); 827 return NULL; 828 } 829 } 830 831 fclose(arch); 832 return NULL; 833} 834 835/* Touch a member of an archive, on disk. 836 * The GNode's modification time is left as-is. 837 * 838 * The st_mtime of the entire archive is also changed. 839 * For a library, it may be required to run ranlib after this. 840 * 841 * Input: 842 * gn Node of member to touch 843 * 844 * Results: 845 * The 'time' field of the member's header is updated. 846 */ 847void 848Arch_Touch(GNode *gn) 849{ 850 FILE *f; 851 struct ar_hdr arh; 852 853 f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh, 854 "r+"); 855 if (f == NULL) 856 return; 857 858 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 859 (void)fwrite(&arh, sizeof arh, 1, f); 860 fclose(f); /* TODO: handle errors */ 861} 862 863/* Given a node which represents a library, touch the thing, making sure that 864 * the table of contents is also touched. 865 * 866 * Both the modification time of the library and of the RANLIBMAG member are 867 * set to 'now'. */ 868void 869Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED) 870{ 871#ifdef RANLIBMAG 872 FILE *f; 873 struct ar_hdr arh; /* Header describing table of contents */ 874 struct utimbuf times; 875 876 f = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); 877 if (f == NULL) 878 return; 879 880 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 881 (void)fwrite(&arh, sizeof arh, 1, f); 882 fclose(f); /* TODO: handle errors */ 883 884 times.actime = times.modtime = now; 885 utime(gn->path, ×); /* TODO: handle errors */ 886#endif 887} 888 889/* Update the mtime of the GNode with the mtime from the archive member on 890 * disk (or in the cache). */ 891void 892Arch_UpdateMTime(GNode *gn) 893{ 894 struct ar_hdr *arh; 895 896 arh = ArchStatMember(GNode_VarArchive(gn), GNode_VarMember(gn), TRUE); 897 if (arh != NULL) 898 gn->mtime = (time_t)strtol(arh->ar_date, NULL, 10); 899 else 900 gn->mtime = 0; 901} 902 903/* Given a nonexistent archive member's node, update gn->mtime from its 904 * archived form, if it exists. */ 905void 906Arch_UpdateMemberMTime(GNode *gn) 907{ 908 GNodeListNode *ln; 909 910 for (ln = gn->parents.first; ln != NULL; ln = ln->next) { 911 GNode *pgn = ln->datum; 912 913 if (pgn->type & OP_ARCHV) { 914 /* 915 * If the parent is an archive specification and is 916 * being made and its member's name matches the name 917 * of the node we were given, record the modification 918 * time of the parent in the child. We keep searching 919 * its parents in case some other parent requires this 920 * child to exist. 921 */ 922 const char *nameStart = strchr(pgn->name, '(') + 1; 923 const char *nameEnd = strchr(nameStart, ')'); 924 size_t nameLen = (size_t)(nameEnd - nameStart); 925 926 if ((pgn->flags & REMAKE) && 927 strncmp(nameStart, gn->name, nameLen) == 0) { 928 Arch_UpdateMTime(pgn); 929 gn->mtime = pgn->mtime; 930 } 931 } else if (pgn->flags & REMAKE) { 932 /* 933 * Something which isn't a library depends on the 934 * existence of this target, so it needs to exist. 935 */ 936 gn->mtime = 0; 937 break; 938 } 939 } 940} 941 942/* Search for a library along the given search path. 943 * 944 * The node's 'path' field is set to the found path (including the 945 * actual file name, not -l...). If the system can handle the -L 946 * flag when linking (or we cannot find the library), we assume that 947 * the user has placed the .LIBS variable in the final linking 948 * command (or the linker will know where to find it) and set the 949 * TARGET variable for this node to be the node's name. Otherwise, 950 * we set the TARGET variable to be the full path of the library, 951 * as returned by Dir_FindFile. 952 * 953 * Input: 954 * gn Node of library to find 955 */ 956void 957Arch_FindLib(GNode *gn, SearchPath *path) 958{ 959 char *libName = str_concat3("lib", gn->name + 2, ".a"); 960 gn->path = Dir_FindFile(libName, path); 961 free(libName); 962 963#ifdef LIBRARIES 964 Var_Set(TARGET, gn->name, gn); 965#else 966 Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn); 967#endif 968} 969 970/* Decide if a node with the OP_LIB attribute is out-of-date. Called from 971 * GNode_IsOODate to make its life easier. 972 * The library is cached if it hasn't been already. 973 * 974 * There are several ways for a library to be out-of-date that are 975 * not available to ordinary files. In addition, there are ways 976 * that are open to regular files that are not available to 977 * libraries. 978 * 979 * A library that is only used as a source is never 980 * considered out-of-date by itself. This does not preclude the 981 * library's modification time from making its parent be out-of-date. 982 * A library will be considered out-of-date for any of these reasons, 983 * given that it is a target on a dependency line somewhere: 984 * 985 * Its modification time is less than that of one of its sources 986 * (gn->mtime < gn->youngestChild->mtime). 987 * 988 * Its modification time is greater than the time at which the make 989 * began (i.e. it's been modified in the course of the make, probably 990 * by archiving). 991 * 992 * The modification time of one of its sources is greater than the one 993 * of its RANLIBMAG member (i.e. its table of contents is out-of-date). 994 * We don't compare the archive time vs. TOC time because they can be 995 * too close. In my opinion we should not bother with the TOC at all 996 * since this is used by 'ar' rules that affect the data contents of the 997 * archive, not by ranlib rules, which affect the TOC. 998 */ 999Boolean 1000Arch_LibOODate(GNode *gn) 1001{ 1002 Boolean oodate; 1003 1004 if (gn->type & OP_PHONY) { 1005 oodate = TRUE; 1006 } else if (!GNode_IsTarget(gn) && Lst_IsEmpty(&gn->children)) { 1007 oodate = FALSE; 1008 } else if ((!Lst_IsEmpty(&gn->children) && gn->youngestChild == NULL) || 1009 (gn->mtime > now) || 1010 (gn->youngestChild != NULL && 1011 gn->mtime < gn->youngestChild->mtime)) { 1012 oodate = TRUE; 1013 } else { 1014#ifdef RANLIBMAG 1015 struct ar_hdr *arh; /* Header for __.SYMDEF */ 1016 int modTimeTOC; /* The table-of-contents' mod time */ 1017 1018 arh = ArchStatMember(gn->path, RANLIBMAG, FALSE); 1019 1020 if (arh != NULL) { 1021 modTimeTOC = (int)strtol(arh->ar_date, NULL, 10); 1022 1023 if (DEBUG(ARCH) || DEBUG(MAKE)) 1024 debug_printf("%s modified %s...", 1025 RANLIBMAG, 1026 Targ_FmtTime(modTimeTOC)); 1027 oodate = gn->youngestChild == NULL || 1028 gn->youngestChild->mtime > modTimeTOC; 1029 } else { 1030 /* 1031 * A library without a table of contents is out-of-date. 1032 */ 1033 if (DEBUG(ARCH) || DEBUG(MAKE)) 1034 debug_printf("no toc..."); 1035 oodate = TRUE; 1036 } 1037#else 1038 oodate = FALSE; 1039#endif 1040 } 1041 return oodate; 1042} 1043 1044/* Initialize the archives module. */ 1045void 1046Arch_Init(void) 1047{ 1048 Lst_Init(&archives); 1049} 1050 1051/* Clean up the archives module. */ 1052void 1053Arch_End(void) 1054{ 1055#ifdef CLEANUP 1056 Lst_DoneCall(&archives, ArchFree); 1057#endif 1058} 1059 1060Boolean 1061Arch_IsLib(GNode *gn) 1062{ 1063 static const char armag[] = "!<arch>\n"; 1064 char buf[sizeof armag - 1]; 1065 int fd; 1066 1067 if ((fd = open(gn->path, O_RDONLY)) == -1) 1068 return FALSE; 1069 1070 if (read(fd, buf, sizeof buf) != sizeof buf) { 1071 (void)close(fd); 1072 return FALSE; 1073 } 1074 1075 (void)close(fd); 1076 1077 return memcmp(buf, armag, sizeof buf) == 0; 1078} 1079