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