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