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