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