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