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