arch.c revision 1.168
1/* $NetBSD: arch.c,v 1.168 2020/11/07 13:34:46 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 cashed and the archive closed again. All cashed 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_MTime Find the modification time of a member of 97 * an archive *in the archive*. The time is also 98 * placed in the member's GNode. Returns the 99 * modification time. 100 * 101 * Arch_MemberMTime 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.168 2020/11/07 13:34:46 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 nodeLst. Nodes are created as 173 * necessary. 174 * 175 * Input: 176 * pp The start of the specification. 177 * nodeLst 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 * *nodeLst Nodes for the members have been added. 184 */ 185Boolean 186Arch_ParseArchive(char **pp, GNodeList *nodeLst, GNode *ctxt) 187{ 188 char *cp; /* Pointer into line */ 189 GNode *gn; /* New node */ 190 char *libName; /* Library-part of specification */ 191 char *libName_freeIt = NULL; 192 char *memName; /* Member-part of specification */ 193 char saveChar; /* Ending delimiter of member-name */ 194 Boolean expandLibName; /* Whether the parsed libName contains 195 * variable expressions that need to be 196 * expanded */ 197 198 libName = *pp; 199 expandLibName = FALSE; 200 201 for (cp = libName; *cp != '(' && *cp != '\0';) { 202 if (*cp == '$') { 203 /* 204 * Variable spec, so call the Var module to parse the puppy 205 * so we can safely advance beyond it... 206 */ 207 const char *nested_p = cp; 208 void *result_freeIt; 209 const char *result; 210 Boolean isError; 211 212 /* XXX: is expanded twice: once here and once below */ 213 (void)Var_Parse(&nested_p, ctxt, VARE_UNDEFERR|VARE_WANTRES, 214 &result, &result_freeIt); 215 /* TODO: handle errors */ 216 isError = result == var_Error; 217 free(result_freeIt); 218 if (isError) 219 return FALSE; 220 221 expandLibName = TRUE; 222 cp += nested_p - cp; 223 } else 224 cp++; 225 } 226 227 *cp++ = '\0'; 228 if (expandLibName) { 229 (void)Var_Subst(libName, ctxt, VARE_UNDEFERR|VARE_WANTRES, &libName); 230 /* TODO: handle errors */ 231 libName_freeIt = libName; 232 } 233 234 235 for (;;) { 236 /* 237 * First skip to the start of the member's name, mark that 238 * place and skip to the end of it (either white-space or 239 * a close paren). 240 */ 241 Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */ 242 243 pp_skip_whitespace(&cp); 244 245 memName = cp; 246 while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) { 247 if (*cp == '$') { 248 /* 249 * Variable spec, so call the Var module to parse the puppy 250 * so we can safely advance beyond it... 251 */ 252 void *freeIt; 253 const char *result; 254 Boolean isError; 255 const char *nested_p = cp; 256 257 (void)Var_Parse(&nested_p, ctxt, VARE_UNDEFERR|VARE_WANTRES, 258 &result, &freeIt); 259 /* TODO: handle errors */ 260 isError = result == var_Error; 261 free(freeIt); 262 263 if (isError) 264 return FALSE; 265 266 doSubst = TRUE; 267 cp += nested_p - cp; 268 } else { 269 cp++; 270 } 271 } 272 273 /* 274 * If the specification ends without a closing parenthesis, 275 * chances are there's something wrong (like a missing backslash), 276 * so it's better to return failure than allow such things to happen 277 */ 278 if (*cp == '\0') { 279 Parse_Error(PARSE_FATAL, "No closing parenthesis in archive specification"); 280 return FALSE; 281 } 282 283 /* 284 * If we didn't move anywhere, we must be done 285 */ 286 if (cp == memName) { 287 break; 288 } 289 290 saveChar = *cp; 291 *cp = '\0'; 292 293 /* 294 * XXX: This should be taken care of intelligently by 295 * SuffExpandChildren, both for the archive and the member portions. 296 */ 297 /* 298 * If member contains variables, try and substitute for them. 299 * This will slow down archive specs with dynamic sources, of course, 300 * since we'll be (non-)substituting them three times, but them's 301 * the breaks -- we need to do this since SuffExpandChildren calls 302 * us, otherwise we could assume the thing would be taken care of 303 * later. 304 */ 305 if (doSubst) { 306 char *buf; 307 char *sacrifice; 308 char *oldMemName = memName; 309 310 (void)Var_Subst(memName, ctxt, VARE_UNDEFERR|VARE_WANTRES, 311 &memName); 312 /* TODO: handle errors */ 313 314 /* 315 * Now form an archive spec and recurse to deal with nested 316 * variables and multi-word variable values.... The results 317 * are just placed at the end of the nodeLst we're returning. 318 */ 319 buf = sacrifice = str_concat4(libName, "(", memName, ")"); 320 321 if (strchr(memName, '$') != NULL && 322 strcmp(memName, oldMemName) == 0) { 323 /* 324 * Must contain dynamic sources, so we can't deal with it now. 325 * Just create an ARCHV node for the thing and let 326 * SuffExpandChildren handle it... 327 */ 328 gn = Targ_GetNode(buf); 329 gn->type |= OP_ARCHV; 330 Lst_Append(nodeLst, gn); 331 332 } else if (!Arch_ParseArchive(&sacrifice, nodeLst, ctxt)) { 333 /* Error in nested call. */ 334 free(buf); 335 return FALSE; 336 } 337 free(buf); 338 339 } else if (Dir_HasWildcards(memName)) { 340 StringList *members = Lst_New(); 341 Dir_Expand(memName, dirSearchPath, members); 342 343 while (!Lst_IsEmpty(members)) { 344 char *member = Lst_Dequeue(members); 345 char *fullname = str_concat4(libName, "(", member, ")"); 346 free(member); 347 348 gn = Targ_GetNode(fullname); 349 free(fullname); 350 351 gn->type |= OP_ARCHV; 352 Lst_Append(nodeLst, gn); 353 } 354 Lst_Free(members); 355 356 } else { 357 char *fullname = str_concat4(libName, "(", memName, ")"); 358 gn = Targ_GetNode(fullname); 359 free(fullname); 360 361 /* 362 * We've found the node, but have to make sure the rest of the 363 * world knows it's an archive member, without having to 364 * constantly check for parentheses, so we type the thing with 365 * the OP_ARCHV bit before we place it on the end of the 366 * provided list. 367 */ 368 gn->type |= OP_ARCHV; 369 Lst_Append(nodeLst, gn); 370 } 371 if (doSubst) { 372 free(memName); 373 } 374 375 *cp = saveChar; 376 } 377 378 free(libName_freeIt); 379 380 cp++; /* skip the ')' */ 381 /* We promised that pp would be set up at the next non-space. */ 382 pp_skip_whitespace(&cp); 383 *pp = cp; 384 return TRUE; 385} 386 387/* Locate a member of an archive, given the path of the archive and the path 388 * of the desired member. 389 * 390 * Input: 391 * archive Path to the archive 392 * member Name of member; only its basename is used. 393 * addToCache TRUE if archive should be cached if not already so. 394 * 395 * Results: 396 * The ar_hdr for the member, or NULL. 397 */ 398static struct ar_hdr * 399ArchStatMember(const char *archive, const char *member, Boolean addToCache) 400{ 401#define AR_MAX_NAME_LEN (sizeof arh.ar_name - 1) 402 FILE *arch; /* Stream to archive */ 403 size_t size; /* Size of archive member */ 404 char magic[SARMAG]; 405 ArchListNode *ln; 406 Arch *ar; /* Archive descriptor */ 407 struct ar_hdr arh; /* archive-member header for reading archive */ 408 char memName[MAXPATHLEN + 1]; 409 /* Current member name while hashing. */ 410 411 /* 412 * Because of space constraints and similar things, files are archived 413 * using their basename, not the entire path. 414 */ 415 const char *lastSlash = strrchr(member, '/'); 416 if (lastSlash != NULL) 417 member = lastSlash + 1; 418 419 for (ln = archives->first; ln != NULL; ln = ln->next) { 420 const Arch *a = ln->datum; 421 if (strcmp(a->name, archive) == 0) 422 break; 423 } 424 425 if (ln != NULL) { 426 struct ar_hdr *hdr; 427 428 ar = ln->datum; 429 hdr = HashTable_FindValue(&ar->members, member); 430 if (hdr != NULL) 431 return hdr; 432 433 { 434 /* Try truncated name */ 435 char copy[AR_MAX_NAME_LEN + 1]; 436 size_t len = strlen(member); 437 438 if (len > AR_MAX_NAME_LEN) { 439 len = AR_MAX_NAME_LEN; 440 snprintf(copy, sizeof copy, "%s", member); 441 hdr = HashTable_FindValue(&ar->members, copy); 442 } 443 return hdr; 444 } 445 } 446 447 if (!addToCache) { 448 /* 449 * Caller doesn't want the thing cached, just use ArchFindMember 450 * to read the header for the member out and close down the stream 451 * again. Since the archive is not to be cached, we assume there's 452 * no need to allocate extra room for the header we're returning, 453 * so just declare it static. 454 */ 455 static struct ar_hdr sarh; 456 457 arch = ArchFindMember(archive, member, &sarh, "r"); 458 if (arch == NULL) 459 return NULL; 460 461 fclose(arch); 462 return &sarh; 463 } 464 465 /* 466 * We don't have this archive on the list yet, so we want to find out 467 * everything that's in it and cache it so we can get at it quickly. 468 */ 469 arch = fopen(archive, "r"); 470 if (arch == NULL) 471 return NULL; 472 473 /* 474 * We use the ARMAG string to make sure this is an archive we 475 * can handle... 476 */ 477 if (fread(magic, SARMAG, 1, arch) != 1 || 478 strncmp(magic, ARMAG, SARMAG) != 0) { 479 (void)fclose(arch); 480 return NULL; 481 } 482 483 ar = bmake_malloc(sizeof *ar); 484 ar->name = bmake_strdup(archive); 485 ar->fnametab = NULL; 486 ar->fnamesize = 0; 487 HashTable_Init(&ar->members); 488 memName[AR_MAX_NAME_LEN] = '\0'; 489 490 while (fread(&arh, sizeof arh, 1, arch) == 1) { 491 char *nameend; 492 493 /* If the header is bogus, there's no way we can recover. */ 494 if (strncmp(arh.ar_fmag, ARFMAG, sizeof arh.ar_fmag) != 0) 495 goto badarch; 496 497 /* 498 * We need to advance the stream's pointer to the start of the 499 * next header. Files are padded with newlines to an even-byte 500 * boundary, so we need to extract the size of the file from the 501 * 'size' field of the header and round it up during the seek. 502 */ 503 arh.ar_size[sizeof arh.ar_size - 1] = '\0'; 504 size = (size_t)strtol(arh.ar_size, NULL, 10); 505 506 memcpy(memName, arh.ar_name, sizeof arh.ar_name); 507 nameend = memName + AR_MAX_NAME_LEN; 508 while (nameend > memName && *nameend == ' ') 509 nameend--; 510 nameend[1] = '\0'; 511 512#ifdef SVR4ARCHIVES 513 /* 514 * svr4 names are slash terminated. Also svr4 extended AR format. 515 */ 516 if (memName[0] == '/') { 517 /* 518 * svr4 magic mode; handle it 519 */ 520 switch (ArchSVR4Entry(ar, memName, size, arch)) { 521 case -1: /* Invalid data */ 522 goto badarch; 523 case 0: /* List of files entry */ 524 continue; 525 default: /* Got the entry */ 526 break; 527 } 528 } else { 529 if (nameend[0] == '/') 530 nameend[0] = '\0'; 531 } 532#endif 533 534#ifdef AR_EFMT1 535 /* 536 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 537 * first <namelen> bytes of the file 538 */ 539 if (strncmp(memName, AR_EFMT1, sizeof AR_EFMT1 - 1) == 0 && 540 ch_isdigit(memName[sizeof AR_EFMT1 - 1])) { 541 542 int elen = atoi(memName + sizeof AR_EFMT1 - 1); 543 544 if ((unsigned int)elen > MAXPATHLEN) 545 goto badarch; 546 if (fread(memName, (size_t)elen, 1, arch) != 1) 547 goto badarch; 548 memName[elen] = '\0'; 549 if (fseek(arch, -elen, SEEK_CUR) != 0) 550 goto badarch; 551 if (DEBUG(ARCH) || DEBUG(MAKE)) { 552 debug_printf("ArchStat: Extended format entry for %s\n", 553 memName); 554 } 555 } 556#endif 557 558 { 559 HashEntry *he; 560 he = HashTable_CreateEntry(&ar->members, memName, NULL); 561 HashEntry_Set(he, bmake_malloc(sizeof arh)); 562 memcpy(HashEntry_Get(he), &arh, sizeof arh); 563 } 564 565 if (fseek(arch, ((long)size + 1) & ~1, SEEK_CUR) != 0) 566 goto badarch; 567 } 568 569 fclose(arch); 570 571 Lst_Append(archives, ar); 572 573 /* 574 * Now that the archive has been read and cached, we can look into 575 * the addToCache table to find the desired member's header. 576 */ 577 return HashTable_FindValue(&ar->members, member); 578 579badarch: 580 fclose(arch); 581 HashTable_Done(&ar->members); 582 free(ar->fnametab); 583 free(ar); 584 return NULL; 585} 586 587#ifdef SVR4ARCHIVES 588/*- 589 *----------------------------------------------------------------------- 590 * ArchSVR4Entry -- 591 * Parse an SVR4 style entry that begins with a slash. 592 * If it is "//", then load the table of filenames 593 * If it is "/<offset>", then try to substitute the long file name 594 * from offset of a table previously read. 595 * If a table is read, the file pointer is moved to the next archive 596 * 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 *----------------------------------------------------------------------- 604 */ 605static int 606ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch) 607{ 608#define ARLONGNAMES1 "//" 609#define ARLONGNAMES2 "/ARFILENAMES" 610 size_t entry; 611 char *ptr, *eptr; 612 613 if (strncmp(inout_name, ARLONGNAMES1, sizeof ARLONGNAMES1 - 1) == 0 || 614 strncmp(inout_name, ARLONGNAMES2, sizeof ARLONGNAMES2 - 1) == 0) { 615 616 if (ar->fnametab != NULL) { 617 DEBUG0(ARCH, "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 */ 707static FILE * 708ArchFindMember(const char *archive, const char *member, struct ar_hdr *out_arh, 709 const char *mode) 710{ 711 FILE *arch; /* Stream to archive */ 712 int size; /* Size of archive member */ 713 char magic[SARMAG]; 714 size_t len, tlen; 715 const char *lastSlash; 716 717 arch = fopen(archive, mode); 718 if (arch == NULL) 719 return NULL; 720 721 /* 722 * We use the ARMAG string to make sure this is an archive we 723 * can handle... 724 */ 725 if (fread(magic, SARMAG, 1, arch) != 1 || 726 strncmp(magic, ARMAG, SARMAG) != 0) { 727 fclose(arch); 728 return NULL; 729 } 730 731 /* 732 * Because of space constraints and similar things, files are archived 733 * using their basename, not the entire path. 734 */ 735 lastSlash = strrchr(member, '/'); 736 if (lastSlash != NULL) 737 member = lastSlash + 1; 738 739 len = tlen = strlen(member); 740 if (len > sizeof out_arh->ar_name) { 741 tlen = sizeof out_arh->ar_name; 742 } 743 744 while (fread(out_arh, sizeof *out_arh, 1, arch) == 1) { 745 746 if (strncmp(out_arh->ar_fmag, ARFMAG, sizeof out_arh->ar_fmag) != 0) { 747 /* 748 * The header is bogus, so the archive is bad 749 * and there's no way we can recover... 750 */ 751 fclose(arch); 752 return NULL; 753 } 754 755 DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n", 756 archive, 757 (int)sizeof out_arh->ar_name, out_arh->ar_name, 758 (int)sizeof out_arh->ar_date, out_arh->ar_date); 759 760 if (ArchiveMember_HasName(out_arh, member, len)) { 761 /* 762 * To make life easier for callers that want to update the 763 * archive, we reposition the file at the start 764 * of the header we just read before we return the stream. 765 * In a more general situation, it might be better to leave 766 * the file at the actual member, rather than its header, but 767 * not here. 768 */ 769 if (fseek(arch, -(long)sizeof *out_arh, SEEK_CUR) != 0) { 770 fclose(arch); 771 return NULL; 772 } 773 return arch; 774 } 775 776#ifdef AR_EFMT1 777 /* 778 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 779 * first <namelen> bytes of the file 780 */ 781 if (strncmp(out_arh->ar_name, AR_EFMT1, sizeof AR_EFMT1 - 1) == 0 && 782 ch_isdigit(out_arh->ar_name[sizeof AR_EFMT1 - 1])) 783 { 784 int elen = atoi(&out_arh->ar_name[sizeof AR_EFMT1 - 1]); 785 char ename[MAXPATHLEN + 1]; 786 787 if ((unsigned int)elen > MAXPATHLEN) { 788 fclose(arch); 789 return NULL; 790 } 791 if (fread(ename, (size_t)elen, 1, arch) != 1) { 792 fclose(arch); 793 return NULL; 794 } 795 ename[elen] = '\0'; 796 if (DEBUG(ARCH) || DEBUG(MAKE)) { 797 debug_printf("ArchFind: Extended format entry for %s\n", ename); 798 } 799 if (strncmp(ename, member, len) == 0) { 800 /* Found as extended name */ 801 if (fseek(arch, -(long)sizeof(struct ar_hdr) - elen, 802 SEEK_CUR) != 0) { 803 fclose(arch); 804 return NULL; 805 } 806 return arch; 807 } 808 if (fseek(arch, -elen, SEEK_CUR) != 0) { 809 fclose(arch); 810 return NULL; 811 } 812 } 813#endif 814 815 /* 816 * This isn't the member we're after, so we need to advance the 817 * stream's pointer to the start of the next header. Files are 818 * padded with newlines to an even-byte boundary, so we need to 819 * extract the size of the file from the 'size' field of the 820 * header and round it up during the seek. 821 */ 822 out_arh->ar_size[sizeof out_arh->ar_size - 1] = '\0'; 823 size = (int)strtol(out_arh->ar_size, NULL, 10); 824 if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) { 825 fclose(arch); 826 return NULL; 827 } 828 } 829 830 fclose(arch); 831 return NULL; 832} 833 834/* Touch a member of an archive, on disk. 835 * The GNode's modification time is left as-is. 836 * 837 * The st_mtime of the entire archive is also changed. 838 * For a library, it may be required to run ranlib after this. 839 * 840 * Input: 841 * gn Node of member to touch 842 * 843 * Results: 844 * The 'time' field of the member's header is updated. 845 */ 846void 847Arch_Touch(GNode *gn) 848{ 849 FILE *f; 850 struct ar_hdr arh; 851 852 f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh, "r+"); 853 if (f == NULL) 854 return; 855 856 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 857 (void)fwrite(&arh, sizeof arh, 1, f); 858 fclose(f); /* TODO: handle errors */ 859} 860 861/* Given a node which represents a library, touch the thing, making sure that 862 * the table of contents is also touched. 863 * 864 * Both the modification time of the library and of the RANLIBMAG member are 865 * set to 'now'. */ 866void 867Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED) 868{ 869#ifdef RANLIBMAG 870 FILE *f; 871 struct ar_hdr arh; /* Header describing table of contents */ 872 struct utimbuf times; 873 874 f = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); 875 if (f == NULL) 876 return; 877 878 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 879 (void)fwrite(&arh, sizeof arh, 1, f); 880 fclose(f); /* TODO: handle errors */ 881 882 times.actime = times.modtime = now; 883 utime(gn->path, ×); /* TODO: handle errors */ 884#endif 885} 886 887/* Update the mtime of the GNode with the mtime from the archive member on 888 * disk (or in the cache). */ 889time_t 890Arch_MTime(GNode *gn) 891{ 892 struct ar_hdr *arh; 893 time_t modTime; 894 895 arh = ArchStatMember(GNode_VarArchive(gn), GNode_VarMember(gn), TRUE); 896 if (arh != NULL) { 897 modTime = (time_t)strtol(arh->ar_date, NULL, 10); 898 } else { 899 modTime = 0; 900 } 901 902 gn->mtime = modTime; 903 return modTime; 904} 905 906/* Given a non-existent archive member's node, get its modification time from 907 * its archived form, if it exists. gn->mtime is filled in as well. */ 908time_t 909Arch_MemberMTime(GNode *gn) 910{ 911 GNodeListNode *ln; 912 913 for (ln = gn->parents->first; ln != NULL; ln = ln->next) { 914 GNode *pgn = ln->datum; 915 916 if (pgn->type & OP_ARCHV) { 917 /* 918 * If the parent is an archive specification and is being made 919 * and its member's name matches the name of the node we were 920 * given, record the modification time of the parent in the 921 * child. We keep searching its parents in case some other 922 * parent requires this child to exist... 923 */ 924 const char *nameStart = strchr(pgn->name, '(') + 1; 925 const char *nameEnd = strchr(nameStart, ')'); 926 size_t nameLen = (size_t)(nameEnd - nameStart); 927 928 if ((pgn->flags & REMAKE) && 929 strncmp(nameStart, gn->name, nameLen) == 0) { 930 gn->mtime = Arch_MTime(pgn); 931 } 932 } else if (pgn->flags & REMAKE) { 933 /* 934 * Something which isn't a library depends on the existence of 935 * this target, so it needs to exist. 936 */ 937 gn->mtime = 0; 938 break; 939 } 940 } 941 942 return gn->mtime; 943} 944 945/* Search for a library along the given search path. 946 * 947 * The node's 'path' field is set to the found path (including the 948 * actual file name, not -l...). If the system can handle the -L 949 * flag when linking (or we cannot find the library), we assume that 950 * the user has placed the .LIBS variable in the final linking 951 * command (or the linker will know where to find it) and set the 952 * TARGET variable for this node to be the node's name. Otherwise, 953 * we set the TARGET variable to be the full path of the library, 954 * as returned by Dir_FindFile. 955 * 956 * Input: 957 * gn Node of library to find 958 */ 959void 960Arch_FindLib(GNode *gn, SearchPath *path) 961{ 962 char *libName = str_concat3("lib", gn->name + 2, ".a"); 963 gn->path = Dir_FindFile(libName, path); 964 free(libName); 965 966#ifdef LIBRARIES 967 Var_Set(TARGET, gn->name, gn); 968#else 969 Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn); 970#endif 971} 972 973/* Decide if a node with the OP_LIB attribute is out-of-date. Called from 974 * Make_OODate to make its life easier. 975 * The library is cached if it hasn't been already. 976 * 977 * There are several ways for a library to be out-of-date that are 978 * not available to ordinary files. In addition, there are ways 979 * that are open to regular files that are not available to 980 * libraries. A library that is only used as a source is never 981 * considered out-of-date by itself. This does not preclude the 982 * library's modification time from making its parent be out-of-date. 983 * A library will be considered out-of-date for any of these reasons, 984 * given that it is a target on a dependency line somewhere: 985 * 986 * Its modification time is less than that of one of its sources 987 * (gn->mtime < gn->youngestChild->mtime). 988 * 989 * Its modification time is greater than the time at which the make 990 * began (i.e. it's been modified in the course of the make, probably 991 * by archiving). 992 * 993 * The modification time of one of its sources is greater than the one 994 * of its RANLIBMAG member (i.e. its table of contents is out-of-date). 995 * We don't compare of the archive time vs. TOC time because they can be 996 * too close. In my opinion we should not bother with the TOC at all 997 * since this is used by 'ar' rules that affect the data contents of the 998 * archive, not by ranlib rules, which affect the TOC. 999 * 1000 * Input: 1001 * gn The library's graph node 1002 * 1003 * Results: 1004 * TRUE if the library is out-of-date. FALSE otherwise. 1005 */ 1006Boolean 1007Arch_LibOODate(GNode *gn) 1008{ 1009 Boolean oodate; 1010 1011 if (gn->type & OP_PHONY) { 1012 oodate = TRUE; 1013 } else if (!GNode_IsTarget(gn) && Lst_IsEmpty(gn->children)) { 1014 oodate = FALSE; 1015 } else if ((!Lst_IsEmpty(gn->children) && gn->youngestChild == NULL) || 1016 (gn->mtime > now) || 1017 (gn->youngestChild != NULL && 1018 gn->mtime < gn->youngestChild->mtime)) { 1019 oodate = TRUE; 1020 } else { 1021#ifdef RANLIBMAG 1022 struct ar_hdr *arh; /* Header for __.SYMDEF */ 1023 int modTimeTOC; /* The table-of-contents's mod time */ 1024 1025 arh = ArchStatMember(gn->path, RANLIBMAG, FALSE); 1026 1027 if (arh != NULL) { 1028 modTimeTOC = (int)strtol(arh->ar_date, NULL, 10); 1029 1030 if (DEBUG(ARCH) || DEBUG(MAKE)) { 1031 debug_printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); 1032 } 1033 oodate = (gn->youngestChild == NULL || gn->youngestChild->mtime > modTimeTOC); 1034 } else { 1035 /* 1036 * A library w/o a table of contents is out-of-date 1037 */ 1038 if (DEBUG(ARCH) || DEBUG(MAKE)) { 1039 debug_printf("No t.o.c...."); 1040 } 1041 oodate = TRUE; 1042 } 1043#else 1044 oodate = FALSE; 1045#endif 1046 } 1047 return oodate; 1048} 1049 1050/* Initialize the archives module. */ 1051void 1052Arch_Init(void) 1053{ 1054 archives = Lst_New(); 1055} 1056 1057/* Clean up the archives module. */ 1058void 1059Arch_End(void) 1060{ 1061#ifdef CLEANUP 1062 Lst_Destroy(archives, ArchFree); 1063#endif 1064} 1065 1066Boolean 1067Arch_IsLib(GNode *gn) 1068{ 1069 static const char armag[] = "!<arch>\n"; 1070 char buf[sizeof armag - 1]; 1071 int fd; 1072 1073 if ((fd = open(gn->path, O_RDONLY)) == -1) 1074 return FALSE; 1075 1076 if (read(fd, buf, sizeof buf) != sizeof buf) { 1077 (void)close(fd); 1078 return FALSE; 1079 } 1080 1081 (void)close(fd); 1082 1083 return memcmp(buf, armag, sizeof buf) == 0; 1084} 1085