1 /* $OpenPackages$ */ 2 /* $OpenBSD: arch.c,v 1.50 2001/09/19 10:58:07 mpech Exp $ */ 3 /* $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $ */ 4 5 /* 6 * Copyright (c) 1999,2000 Marc Espie. 7 * 8 * Extensive code changes for the OpenBSD project. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 23 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 1988, 1989, 1990, 1993 33 * The Regents of the University of California. All rights reserved. 34 * Copyright (c) 1989 by Berkeley Softworks 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * Adam de Boor. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Berkeley and its contributors. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69 /* 70 * Once again, cacheing/hashing comes into play in the manipulation 71 * of archives. The first time an archive is referenced, all of its members' 72 * headers are read and hashed and the archive closed again. All hashed 73 * archives are kept in a hash (archives) which is searched each time 74 * an archive member is referenced. 75 * 76 */ 77 78 #include <sys/param.h> 79 #include <sys/types.h> 80 #include <ar.h> 81 #include <assert.h> 82 #include <ctype.h> 83 #include <fcntl.h> 84 #include <limits.h> 85 #include <stddef.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <unistd.h> 90 #include "ohash.h" 91 #include "config.h" 92 #include "defines.h" 93 #include "dir.h" 94 #include "arch.h" 95 #include "var.h" 96 #include "targ.h" 97 #include "memory.h" 98 #include "gnode.h" 99 #include "timestamp.h" 100 #include "lst.h" 101 102 #ifndef PATH_MAX 103 # ifdef MAXPATHLEN 104 # define PATH_MAX (MAXPATHLEN+1) 105 # else 106 # define PATH_MAX 1024 107 # endif 108 #endif 109 110 #ifdef TARGET_MACHINE 111 #undef MACHINE 112 #define MACHINE TARGET_MACHINE 113 #endif 114 #ifdef TARGET_MACHINE_ARCH 115 #undef MACHINE_ARCH 116 #define MACHINE_ARCH TARGET_MACHINE_ARCH 117 #endif 118 119 static struct ohash archives; /* Archives we've already examined. */ 120 121 typedef struct Arch_ { 122 struct ohash members; /* All the members of this archive, as 123 * struct arch_member entries. */ 124 char name[1]; /* Archive name. */ 125 } Arch; 126 127 /* Used to get to ar's field sizes. */ 128 static struct ar_hdr *dummy; 129 #define AR_NAME_SIZE (sizeof(dummy->ar_name)) 130 #define AR_DATE_SIZE (sizeof(dummy->ar_date)) 131 132 /* Each archive member is tied to an arch_member structure, 133 * suitable for hashing. */ 134 struct arch_member { 135 TIMESTAMP mtime; /* Member modification date. */ 136 char date[AR_DATE_SIZE+1]; 137 /* Same, before conversion to numeric value. */ 138 char name[1]; /* Member name. */ 139 }; 140 141 static struct ohash_info members_info = { 142 offsetof(struct arch_member, name), NULL, 143 hash_alloc, hash_free, element_alloc 144 }; 145 146 static struct ohash_info arch_info = { 147 offsetof(Arch, name), NULL, hash_alloc, hash_free, element_alloc 148 }; 149 150 151 152 static struct arch_member *new_arch_member(struct ar_hdr *, const char *); 153 static TIMESTAMP mtime_of_member(struct arch_member *); 154 static long field2long(const char *, size_t); 155 static Arch *read_archive(const char *, const char *); 156 157 #ifdef CLEANUP 158 static void ArchFree(Arch *); 159 #endif 160 static TIMESTAMP ArchMTimeMember(const char *, const char *, bool); 161 static FILE *ArchFindMember(const char *, const char *, struct ar_hdr *, const char *); 162 static void ArchTouch(const char *, const char *); 163 #if defined(__svr4__) || defined(__SVR4) || \ 164 (defined(__OpenBSD__) && defined(__mips__)) || \ 165 (defined(__OpenBSD__) && defined(__powerpc)) 166 #define SVR4ARCHIVES 167 #endif 168 169 #ifdef SVR4ARCHIVES 170 struct SVR4namelist { 171 char *fnametab; /* Extended name table strings */ 172 size_t fnamesize; /* Size of the string table */ 173 }; 174 175 static const char *svr4list = "Archive list"; 176 177 static char *ArchSVR4Entry(struct SVR4namelist *, char *, size_t, FILE *); 178 #endif 179 180 static struct arch_member * 181 new_arch_member(hdr, name) 182 struct ar_hdr *hdr; 183 const char *name; 184 { 185 const char *end = NULL; 186 struct arch_member *n; 187 188 n = ohash_create_entry(&members_info, name, &end); 189 /* XXX ar entries are NOT null terminated. */ 190 memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE); 191 n->date[AR_DATE_SIZE] = '\0'; 192 /* Don't compute mtime before it is needed. */ 193 ts_set_out_of_date(n->mtime); 194 return n; 195 } 196 197 static TIMESTAMP 198 mtime_of_member(m) 199 struct arch_member *m; 200 { 201 if (is_out_of_date(m->mtime)) 202 ts_set_from_time_t((time_t) strtol(m->date, NULL, 10), m->mtime); 203 return m->mtime; 204 } 205 206 #ifdef CLEANUP 207 /*- 208 *----------------------------------------------------------------------- 209 * ArchFree -- 210 * Free memory used by an archive 211 *----------------------------------------------------------------------- 212 */ 213 static void 214 ArchFree(a) 215 Arch *a; 216 { 217 struct arch_member *mem; 218 unsigned int i; 219 220 /* Free memory from hash entries */ 221 for (mem = ohash_first(&a->members, &i); mem != NULL; 222 mem = ohash_next(&a->members, &i)) 223 free(mem); 224 225 ohash_delete(&a->members); 226 free(a); 227 } 228 #endif 229 230 231 232 /* Side-effects: Some nodes may be created. */ 233 bool 234 Arch_ParseArchive(linePtr, nodeLst, ctxt) 235 char **linePtr; /* Pointer to start of specification */ 236 Lst nodeLst; /* Lst on which to place the nodes */ 237 SymTable *ctxt; /* Context in which to expand variables */ 238 { 239 char *cp; /* Pointer into line */ 240 GNode *gn; /* New node */ 241 char *libName; /* Library-part of specification */ 242 char *memName; /* Member-part of specification */ 243 char nameBuf[MAKE_BSIZE]; /* temporary place for node name */ 244 char saveChar; /* Ending delimiter of member-name */ 245 bool subLibName; /* true if libName should have/had 246 * variable substitution performed on it */ 247 248 libName = *linePtr; 249 250 subLibName = false; 251 252 for (cp = libName; *cp != '(' && *cp != '\0';) { 253 if (*cp == '$') { 254 bool ok; 255 256 cp += Var_ParseSkip(cp, ctxt, &ok); 257 if (ok == false) 258 return false; 259 subLibName = true; 260 } else 261 cp++; 262 } 263 264 *cp++ = '\0'; 265 if (subLibName) 266 libName = Var_Subst(libName, ctxt, true); 267 268 for (;;) { 269 /* First skip to the start of the member's name, mark that 270 * place and skip to the end of it (either white-space or 271 * a close paren). */ 272 bool doSubst = false; /* true if need to substitute in memName */ 273 274 while (*cp != '\0' && *cp != ')' && isspace(*cp)) 275 cp++; 276 memName = cp; 277 while (*cp != '\0' && *cp != ')' && !isspace(*cp)) { 278 if (*cp == '$') { 279 bool ok; 280 cp += Var_ParseSkip(cp, ctxt, &ok); 281 if (ok == false) 282 return false; 283 doSubst = true; 284 } else 285 cp++; 286 } 287 288 /* If the specification ends without a closing parenthesis, 289 * chances are there's something wrong (like a missing backslash), 290 * so it's better to return failure than allow such things to 291 * happen. */ 292 if (*cp == '\0') { 293 printf("No closing parenthesis in archive specification\n"); 294 return false; 295 } 296 297 /* If we didn't move anywhere, we must be done. */ 298 if (cp == memName) 299 break; 300 301 saveChar = *cp; 302 *cp = '\0'; 303 304 /* XXX: This should be taken care of intelligently by 305 * SuffExpandChildren, both for the archive and the member portions. */ 306 307 /* If member contains variables, try and substitute for them. 308 * This will slow down archive specs with dynamic sources, of course, 309 * since we'll be (non-)substituting them three times, but them's 310 * the breaks -- we need to do this since SuffExpandChildren calls 311 * us, otherwise we could assume the thing would be taken care of 312 * later. */ 313 if (doSubst) { 314 char *buf; 315 char *sacrifice; 316 char *oldMemName = memName; 317 318 memName = Var_Subst(memName, ctxt, true); 319 320 /* Now form an archive spec and recurse to deal with nested 321 * variables and multi-word variable values.... The results 322 * are just placed at the end of the nodeLst we're returning. */ 323 buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3); 324 325 sprintf(buf, "%s(%s)", libName, memName); 326 327 if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) { 328 /* Must contain dynamic sources, so we can't deal with it now. 329 * Just create an ARCHV node for the thing and let 330 * SuffExpandChildren handle it... */ 331 gn = Targ_FindNode(buf, TARG_CREATE); 332 333 if (gn == NULL) { 334 free(buf); 335 return false; 336 } else { 337 gn->type |= OP_ARCHV; 338 Lst_AtEnd(nodeLst, gn); 339 } 340 } else if (!Arch_ParseArchive(&sacrifice, nodeLst, ctxt)) { 341 /* Error in nested call -- free buffer and return false 342 * ourselves. */ 343 free(buf); 344 return false; 345 } 346 /* Free buffer and continue with our work. */ 347 free(buf); 348 } else if (Dir_HasWildcards(memName)) { 349 LIST members; 350 char *member; 351 352 Lst_Init(&members); 353 354 Dir_Expand(memName, dirSearchPath, &members); 355 while ((member = (char *)Lst_DeQueue(&members)) != NULL) { 356 snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, member); 357 free(member); 358 gn = Targ_FindNode(nameBuf, TARG_CREATE); 359 /* We've found the node, but have to make sure the rest of 360 * the world knows it's an archive member, without having 361 * to constantly check for parentheses, so we type the 362 * thing with the OP_ARCHV bit before we place it on the 363 * end of the provided list. */ 364 gn->type |= OP_ARCHV; 365 Lst_AtEnd(nodeLst, gn); 366 } 367 } else { 368 snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, memName); 369 gn = Targ_FindNode(nameBuf, TARG_CREATE); 370 /* We've found the node, but have to make sure the rest of the 371 * world knows it's an archive member, without having to 372 * constantly check for parentheses, so we type the thing with 373 * the OP_ARCHV bit before we place it on the end of the 374 * provided list. */ 375 gn->type |= OP_ARCHV; 376 Lst_AtEnd(nodeLst, gn); 377 } 378 if (doSubst) 379 free(memName); 380 381 *cp = saveChar; 382 } 383 384 /* If substituted libName, free it now, since we need it no longer. */ 385 if (subLibName) 386 free(libName); 387 388 /* We promised the pointer would be set up at the next non-space, so 389 * we must advance cp there before setting *linePtr... (note that on 390 * entrance to the loop, cp is guaranteed to point at a ')') */ 391 do { 392 cp++; 393 } while (*cp != '\0' && isspace(*cp)); 394 395 *linePtr = cp; 396 return true; 397 } 398 399 /* Helper function: ar fields are not null terminated. */ 400 static long 401 field2long(field, len) 402 const char *field; 403 size_t len; 404 { 405 static char enough[32]; 406 407 assert(len < sizeof(enough)); 408 memcpy(enough, field, len); 409 enough[len] = '\0'; 410 return strtol(enough, NULL, 10); 411 } 412 413 static Arch * 414 read_archive(archive, end) 415 const char *archive; 416 const char *end; 417 { 418 FILE * arch; /* Stream to archive */ 419 char magic[SARMAG]; 420 Arch *ar; 421 #ifdef SVR4ARCHIVES 422 struct SVR4namelist list; 423 424 list.fnametab = NULL; 425 #endif 426 427 /* When we encounter an archive for the first time, we read its 428 * whole contents, to place it in the cache. */ 429 arch = fopen(archive, "r"); 430 if (arch == NULL) 431 return NULL; 432 433 /* Make sure this is an archive we can handle. */ 434 if ((fread(magic, SARMAG, 1, arch) != 1) || 435 (strncmp(magic, ARMAG, SARMAG) != 0)) { 436 fclose(arch); 437 return NULL; 438 } 439 440 ar = ohash_create_entry(&arch_info, archive, &end); 441 ohash_init(&ar->members, 8, &members_info); 442 443 for (;;) { 444 size_t n; 445 struct ar_hdr arh; /* Archive-member header for reading archive */ 446 off_t size; /* Size of archive member */ 447 char buffer[PATH_MAX]; 448 char *memName; 449 /* Current member name while hashing. */ 450 char *cp; /* Useful character pointer */ 451 452 memName = buffer; 453 n = fread(&arh, 1, sizeof(struct ar_hdr), arch); 454 455 /* Whole archive read ok. */ 456 if (n == 0 && feof(arch)) { 457 #ifdef SVR4ARCHIVES 458 efree(list.fnametab); 459 #endif 460 fclose(arch); 461 return ar; 462 } 463 if (n < sizeof(struct ar_hdr)) 464 break; 465 466 if (memcmp(arh.ar_fmag, ARFMAG, sizeof(arh.ar_fmag)) != 0) { 467 /* The header is bogus. */ 468 break; 469 } else { 470 /* We need to advance the stream's pointer to the start of the 471 * next header. Records are padded with newlines to an even-byte 472 * boundary, so we need to extract the size of the record and 473 * round it up during the seek. */ 474 size = (off_t) field2long(arh.ar_size, sizeof(arh.ar_size)); 475 476 (void)memcpy(memName, arh.ar_name, AR_NAME_SIZE); 477 /* Find real end of name (strip extranous ' ') */ 478 for (cp = memName + AR_NAME_SIZE - 1; *cp == ' ';) 479 cp--; 480 cp[1] = '\0'; 481 482 #ifdef SVR4ARCHIVES 483 /* SVR4 names are slash terminated. Also svr4 extended AR format. 484 */ 485 if (memName[0] == '/') { 486 /* SVR4 magic mode. */ 487 memName = ArchSVR4Entry(&list, memName, size, arch); 488 if (memName == NULL) /* Invalid data */ 489 break; 490 else if (memName == svr4list) /* List of files entry */ 491 continue; 492 /* Got the entry. */ 493 /* XXX this assumes further processing, such as AR_EFMT1, 494 * also applies to SVR4ARCHIVES. */ 495 } 496 else { 497 if (cp[0] == '/') 498 cp[0] = '\0'; 499 } 500 #endif 501 502 #ifdef AR_EFMT1 503 /* BSD 4.4 extended AR format: #1/<namelen>, with name as the 504 * first <namelen> bytes of the file. */ 505 if (memcmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && 506 isdigit(memName[sizeof(AR_EFMT1) - 1])) { 507 508 int elen = atoi(memName + sizeof(AR_EFMT1)-1); 509 510 if (elen <= 0 || elen >= PATH_MAX) 511 break; 512 memName = buffer; 513 if (fread(memName, elen, 1, arch) != 1) 514 break; 515 memName[elen] = '\0'; 516 if (fseek(arch, -elen, SEEK_CUR) != 0) 517 break; 518 if (DEBUG(ARCH) || DEBUG(MAKE)) 519 printf("ArchStat: Extended format entry for %s\n", memName); 520 } 521 #endif 522 523 ohash_insert(&ar->members, 524 ohash_qlookup(&ar->members, memName), 525 new_arch_member(&arh, memName)); 526 } 527 if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) 528 break; 529 } 530 531 fclose(arch); 532 ohash_delete(&ar->members); 533 #ifdef SVR4ARCHIVES 534 efree(list.fnametab); 535 #endif 536 free(ar); 537 return NULL; 538 } 539 540 /*- 541 *----------------------------------------------------------------------- 542 * ArchMTimeMember -- 543 * Find the modification time of an archive's member, given the 544 * path to the archive and the path to the desired member. 545 * 546 * Results: 547 * The archive member's modification time, or OUT_OF_DATE if member 548 * was not found (convenient, so that missing members are always 549 * out of date). 550 * 551 * Side Effects: 552 * Cache the whole archive contents if hash is true. 553 *----------------------------------------------------------------------- 554 */ 555 static TIMESTAMP 556 ArchMTimeMember(archive, member, hash) 557 const char *archive; /* Path to the archive */ 558 const char *member; /* Name of member. If it is a path, only the 559 * last component is used. */ 560 bool hash; /* true if archive should be hashed if not 561 * already so. */ 562 { 563 FILE * arch; /* Stream to archive */ 564 Arch *ar; /* Archive descriptor */ 565 unsigned int slot; /* Place of archive in the archives hash */ 566 const char *end = NULL; 567 const char *cp; 568 TIMESTAMP result; 569 570 ts_set_out_of_date(result); 571 /* Because of space constraints and similar things, files are archived 572 * using their final path components, not the entire thing, so we need 573 * to point 'member' to the final component, if there is one, to make 574 * the comparisons easier... */ 575 cp = strrchr(member, '/'); 576 if (cp != NULL) 577 member = cp + 1; 578 579 /* Try to find archive in cache. */ 580 slot = ohash_qlookupi(&archives, archive, &end); 581 ar = ohash_find(&archives, slot); 582 583 /* If not found, get it now. */ 584 if (ar == NULL) { 585 if (!hash) { 586 /* Quick path: no need to hash the whole archive, just use 587 * ArchFindMember to get the member's header and close the stream 588 * again. */ 589 struct ar_hdr sarh; 590 591 arch = ArchFindMember(archive, member, &sarh, "r"); 592 593 if (arch != NULL) { 594 fclose(arch); 595 ts_set_from_time_t( (time_t)strtol(sarh.ar_date, NULL, 10), result); 596 } 597 return result; 598 } 599 ar = read_archive(archive, end); 600 if (ar != NULL) 601 ohash_insert(&archives, slot, ar); 602 } 603 604 /* If archive was found, get entry we seek. */ 605 if (ar != NULL) { 606 struct arch_member *he; 607 end = NULL; 608 609 he = ohash_find(&ar->members, ohash_qlookupi(&ar->members, member, &end)); 610 if (he != NULL) 611 return mtime_of_member(he); 612 else { 613 if ((size_t)(end - member) > AR_NAME_SIZE) { 614 /* Try truncated name. */ 615 end = member + AR_NAME_SIZE; 616 he = ohash_find(&ar->members, 617 ohash_qlookupi(&ar->members, member, &end)); 618 if (he != NULL) 619 return mtime_of_member(he); 620 } 621 } 622 } 623 return result; 624 } 625 626 #ifdef SVR4ARCHIVES 627 /*- 628 *----------------------------------------------------------------------- 629 * ArchSVR4Entry -- 630 * Parse an SVR4 style entry that begins with a slash. 631 * If it is "//", then load the table of filenames 632 * If it is "/<offset>", then try to substitute the long file name 633 * from offset of a table previously read. 634 * 635 * Results: 636 * svr4list: just read a list of names 637 * NULL: error occurred 638 * extended name 639 * 640 * Side-effect: 641 * For a list of names, store the list in l. 642 *----------------------------------------------------------------------- 643 */ 644 645 static char * 646 ArchSVR4Entry(l, name, size, arch) 647 struct SVR4namelist *l; 648 char *name; 649 size_t size; 650 FILE *arch; 651 { 652 #define ARLONGNAMES1 "/" 653 #define ARLONGNAMES2 "ARFILENAMES" 654 size_t entry; 655 char *ptr, *eptr; 656 657 assert(name[0] == '/'); 658 name++; 659 /* First comes a table of archive names, to be used by subsequent calls. */ 660 if (memcmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || 661 memcmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { 662 663 if (l->fnametab != NULL) { 664 if (DEBUG(ARCH)) 665 printf("Attempted to redefine an SVR4 name table\n"); 666 return NULL; 667 } 668 669 l->fnametab = emalloc(size); 670 l->fnamesize = size; 671 672 if (fread(l->fnametab, size, 1, arch) != 1) { 673 if (DEBUG(ARCH)) 674 printf("Reading an SVR4 name table failed\n"); 675 return NULL; 676 } 677 678 eptr = l->fnametab + size; 679 for (entry = 0, ptr = l->fnametab; ptr < eptr; ptr++) 680 switch (*ptr) { 681 case '/': 682 entry++; 683 *ptr = '\0'; 684 break; 685 686 case '\n': 687 break; 688 689 default: 690 break; 691 } 692 if (DEBUG(ARCH)) 693 printf("Found svr4 archive name table with %lu entries\n", 694 (u_long)entry); 695 return (char *)svr4list; 696 } 697 /* Then the names themselves are given as offsets in this table. */ 698 if (*name == ' ' || *name == '\0') 699 return NULL; 700 701 entry = (size_t) strtol(name, &eptr, 0); 702 if ((*eptr != ' ' && *eptr != '\0') || eptr == name) { 703 if (DEBUG(ARCH)) 704 printf("Could not parse SVR4 name /%s\n", name); 705 return NULL; 706 } 707 if (entry >= l->fnamesize) { 708 if (DEBUG(ARCH)) 709 printf("SVR4 entry offset /%s is greater than %lu\n", 710 name, (u_long)l->fnamesize); 711 return NULL; 712 } 713 714 if (DEBUG(ARCH)) 715 printf("Replaced /%s with %s\n", name, l->fnametab + entry); 716 717 return l->fnametab + entry; 718 } 719 #endif 720 721 722 /*- 723 *----------------------------------------------------------------------- 724 * ArchFindMember -- 725 * Locate a member of an archive, given the path of the archive and 726 * the path of the desired member. If the archive is to be modified, 727 * the mode should be "r+", if not, it should be "r". 728 * 729 * Results: 730 * A FILE *, opened for reading and writing, positioned right after 731 * the member's header, or NULL if the member was nonexistent. 732 * 733 * Side Effects: 734 * Fill the struct ar_hdr pointed by arhPtr. 735 *----------------------------------------------------------------------- 736 */ 737 static FILE * 738 ArchFindMember(archive, member, arhPtr, mode) 739 const char *archive; /* Path to the archive */ 740 const char *member; /* Name of member. If it is a path, only the 741 * last component is used. */ 742 struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */ 743 const char *mode; /* The mode for opening the stream */ 744 { 745 FILE * arch; /* Stream to archive */ 746 char *cp; /* Useful character pointer */ 747 char magic[SARMAG]; 748 size_t len; 749 #ifdef SVR4ARCHIVES 750 struct SVR4namelist list; 751 752 list.fnametab = NULL; 753 #endif 754 755 arch = fopen(archive, mode); 756 if (arch == NULL) 757 return NULL; 758 759 /* Make sure this is an archive we can handle. */ 760 if (fread(magic, SARMAG, 1, arch) != 1 || 761 strncmp(magic, ARMAG, SARMAG) != 0) { 762 fclose(arch); 763 return NULL; 764 } 765 766 /* Because of space constraints and similar things, files are archived 767 * using their final path components, not the entire thing, so we need 768 * to point 'member' to the final component, if there is one, to make 769 * the comparisons easier... */ 770 cp = strrchr(member, '/'); 771 if (cp != NULL) 772 member = cp + 1; 773 774 len = strlen(member); 775 if (len >= AR_NAME_SIZE) 776 len = AR_NAME_SIZE; 777 778 /* Error handling is simpler than for read_archive, since we just 779 * look for a given member. */ 780 while (fread(arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) { 781 off_t size; /* Size of archive member */ 782 char *memName; 783 784 if (memcmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0) 785 /* The header is bogus, so the archive is bad. */ 786 break; 787 788 memName = arhPtr->ar_name; 789 if (memcmp(member, memName, len) == 0) { 790 /* If the member's name doesn't take up the entire 'name' field, 791 * we have to be careful of matching prefixes. Names are space- 792 * padded to the right, so if the character in 'name' at the end 793 * of the matched string is anything but a space, this isn't the 794 * member we sought. */ 795 #ifdef SVR4ARCHIVES 796 if (len < sizeof(arhPtr->ar_name) && memName[len] == '/') 797 len++; 798 #endif 799 if (len == sizeof(arhPtr->ar_name) || 800 memName[len] == ' ') { 801 #ifdef SVR4ARCHIVES 802 efree(list.fnametab); 803 #endif 804 return arch; 805 } 806 } 807 808 size = (off_t) field2long(arhPtr->ar_size, sizeof(arhPtr->ar_size)); 809 810 #ifdef SVR4ARCHIVES 811 /* svr4 names are slash terminated. Also svr4 extended AR format. 812 */ 813 if (memName[0] == '/') { 814 /* svr4 magic mode. */ 815 memName = ArchSVR4Entry(&list, arhPtr->ar_name, size, arch); 816 if (memName == NULL) /* Invalid data */ 817 break; 818 else if (memName == svr4list) /* List of files entry */ 819 continue; 820 /* Got the entry. */ 821 if (strcmp(memName, member) == 0) { 822 efree(list.fnametab); 823 return arch; 824 } 825 } 826 #endif 827 828 #ifdef AR_EFMT1 829 /* BSD 4.4 extended AR format: #1/<namelen>, with name as the 830 * first <namelen> bytes of the file. */ 831 if (memcmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && 832 isdigit(memName[sizeof(AR_EFMT1) - 1])) { 833 char ename[PATH_MAX]; 834 835 int elen = atoi(memName + sizeof(AR_EFMT1)-1); 836 837 if (elen <= 0 || elen >= PATH_MAX) 838 break; 839 if (fread(ename, elen, 1, arch) != 1) 840 break; 841 if (fseek(arch, -elen, SEEK_CUR) != 0) 842 break; 843 ename[elen] = '\0'; 844 if (DEBUG(ARCH) || DEBUG(MAKE)) 845 printf("ArchFind: Extended format entry for %s\n", ename); 846 /* Found as extended name. */ 847 if (strcmp(ename, member) == 0) { 848 #ifdef SVR4ARCHIVES 849 efree(list.fnametab); 850 #endif 851 return arch; 852 } 853 } 854 #endif 855 /* This isn't the member we're after, so we need to advance the 856 * stream's pointer to the start of the next header. */ 857 if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) 858 break; 859 } 860 861 /* We did not find the member, or we ran into an error while reading 862 * the archive. */ 863 #ifdef SVRARCHIVES 864 efree(list.fnametab); 865 #endif 866 fclose(arch); 867 return NULL; 868 } 869 870 static void 871 ArchTouch(archive, member) 872 const char *archive; /* Path to the archive */ 873 const char *member; /* Name of member. */ 874 { 875 FILE *arch; 876 struct ar_hdr arh; 877 878 arch = ArchFindMember(archive, member, &arh, "r+"); 879 if (arch != NULL) { 880 snprintf(arh.ar_date, sizeof(arh.ar_date), "%-12ld", (long) 881 timestamp2time_t(now)); 882 if (fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR) == 0) 883 (void)fwrite(&arh, sizeof(struct ar_hdr), 1, arch); 884 fclose(arch); 885 } 886 } 887 888 /* 889 * Side Effects: 890 * The modification time of the entire archive is also changed. 891 * For a library, this could necessitate the re-ranlib'ing of the 892 * whole thing. 893 */ 894 void 895 Arch_Touch(gn) 896 GNode *gn; /* Node of member to touch */ 897 { 898 ArchTouch(Varq_Value(ARCHIVE_INDEX, gn), Varq_Value(MEMBER_INDEX, gn)); 899 } 900 901 /*ARGSUSED*/ 902 void 903 Arch_TouchLib(gn) 904 GNode *gn UNUSED; /* The node of the library to touch */ 905 /* ^ Non RANLIBMAG does nothing with it */ 906 { 907 #ifdef RANLIBMAG 908 if (gn->path != NULL) { 909 ArchTouch(gn->path, RANLIBMAG); 910 set_times(gn->path); 911 } 912 #endif 913 } 914 915 TIMESTAMP 916 Arch_MTime(gn) 917 GNode *gn; /* Node describing archive member */ 918 { 919 gn->mtime = ArchMTimeMember(Varq_Value(ARCHIVE_INDEX, gn), 920 Varq_Value(MEMBER_INDEX, gn), 921 true); 922 923 return gn->mtime; 924 } 925 926 TIMESTAMP 927 Arch_MemMTime(gn) 928 GNode *gn; 929 { 930 LstNode ln; 931 932 for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) { 933 GNode *pgn; 934 char *nameStart, 935 *nameEnd; 936 937 pgn = (GNode *)Lst_Datum(ln); 938 939 if (pgn->type & OP_ARCHV) { 940 /* If the parent is an archive specification and is being made 941 * and its member's name matches the name of the node we were 942 * given, record the modification time of the parent in the 943 * child. We keep searching its parents in case some other 944 * parent requires this child to exist... */ 945 if ((nameStart = strchr(pgn->name, '(') ) != NULL) { 946 nameStart++; 947 nameEnd = strchr(nameStart, ')'); 948 } else 949 nameEnd = NULL; 950 951 if (pgn->make && nameEnd != NULL && 952 strncmp(nameStart, gn->name, nameEnd - nameStart) == 0 && 953 gn->name[nameEnd-nameStart] == '\0') 954 gn->mtime = Arch_MTime(pgn); 955 } else if (pgn->make) { 956 /* Something which isn't a library depends on the existence of 957 * this target, so it needs to exist. */ 958 ts_set_out_of_date(gn->mtime); 959 break; 960 } 961 } 962 return gn->mtime; 963 } 964 965 /* If the system can handle the -L flag when linking (or we cannot find 966 * the library), we assume that the user has placed the .LIBRARIES variable 967 * in the final linking command (or the linker will know where to find it) 968 * and set the TARGET variable for this node to be the node's name. Otherwise, 969 * we set the TARGET variable to be the full path of the library, 970 * as returned by Dir_FindFile. 971 */ 972 void 973 Arch_FindLib(gn, path) 974 GNode *gn; /* Node of library to find */ 975 Lst path; /* Search path */ 976 { 977 char *libName; /* file name for archive */ 978 979 libName = emalloc(strlen(gn->name) + 6 - 2); 980 sprintf(libName, "lib%s.a", &gn->name[2]); 981 982 gn->path = Dir_FindFile(libName, path); 983 984 free(libName); 985 986 #ifdef LIBRARIES 987 Varq_Set(TARGET_INDEX, gn->name, gn); 988 #else 989 Varq_Set(TARGET_INDEX, gn->path == NULL ? gn->name : gn->path, gn); 990 #endif /* LIBRARIES */ 991 } 992 993 /*- 994 *----------------------------------------------------------------------- 995 * Arch_LibOODate -- 996 * Decide if a node with the OP_LIB attribute is out-of-date. Called 997 * from Make_OODate to make its life easier. 998 * 999 * There are several ways for a library to be out-of-date that are 1000 * not available to ordinary files. In addition, there are ways 1001 * that are open to regular files that are not available to 1002 * libraries. A library that is only used as a source is never 1003 * considered out-of-date by itself. This does not preclude the 1004 * library's modification time from making its parent be out-of-date. 1005 * A library will be considered out-of-date for any of these reasons, 1006 * given that it is a target on a dependency line somewhere: 1007 * Its modification time is less than that of one of its 1008 * sources (gn->mtime < gn->cmtime). 1009 * Its modification time is greater than the time at which the 1010 * make began (i.e. it's been modified in the course 1011 * of the make, probably by archiving). 1012 * The modification time of one of its sources is greater than 1013 * the one of its RANLIBMAG member (i.e. its table of contents 1014 * is out-of-date). We don't compare of the archive time 1015 * vs. TOC time because they can be too close. In my 1016 * opinion we should not bother with the TOC at all since 1017 * this is used by 'ar' rules that affect the data contents 1018 * of the archive, not by ranlib rules, which affect the 1019 * TOC. 1020 * 1021 * Results: 1022 * true if the library is out-of-date. false otherwise. 1023 * 1024 * Side Effects: 1025 * The library will be hashed if it hasn't been already. 1026 *----------------------------------------------------------------------- 1027 */ 1028 bool 1029 Arch_LibOODate(gn) 1030 GNode *gn; /* The library's graph node */ 1031 { 1032 #ifdef RANLIBMAG 1033 TIMESTAMP modTimeTOC; /* mod time of __.SYMDEF */ 1034 #endif 1035 1036 if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) 1037 return false; 1038 if (is_strictly_before(now, gn->mtime) || is_strictly_before(gn->mtime, gn->cmtime) || 1039 is_out_of_date(gn->mtime)) 1040 return true; 1041 #ifdef RANLIBMAG 1042 /* non existent libraries are always out-of-date. */ 1043 if (gn->path == NULL) 1044 return true; 1045 modTimeTOC = ArchMTimeMember(gn->path, RANLIBMAG, false); 1046 1047 if (!is_out_of_date(modTimeTOC)) { 1048 if (DEBUG(ARCH) || DEBUG(MAKE)) 1049 printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); 1050 return is_strictly_before(modTimeTOC, gn->cmtime); 1051 } 1052 /* A library w/o a table of contents is out-of-date. */ 1053 if (DEBUG(ARCH) || DEBUG(MAKE)) 1054 printf("No t.o.c...."); 1055 return true; 1056 #else 1057 return false; 1058 #endif 1059 } 1060 1061 void 1062 Arch_Init() 1063 { 1064 ohash_init(&archives, 4, &arch_info); 1065 } 1066 1067 #ifdef CLEANUP 1068 void 1069 Arch_End() 1070 { 1071 Arch *e; 1072 unsigned int i; 1073 1074 for (e = ohash_first(&archives, &i); e != NULL; 1075 e = ohash_next(&archives, &i)) 1076 ArchFree(e); 1077 ohash_delete(&archives); 1078 } 1079 #endif 1080 1081 bool 1082 Arch_IsLib(gn) 1083 GNode *gn; 1084 { 1085 char buf[SARMAG]; 1086 int fd; 1087 1088 if (gn->path == NULL || (fd = open(gn->path, O_RDONLY)) == -1) 1089 return false; 1090 1091 if (read(fd, buf, SARMAG) != SARMAG) { 1092 (void)close(fd); 1093 return false; 1094 } 1095 1096 (void)close(fd); 1097 1098 return memcmp(buf, ARMAG, SARMAG) == 0; 1099 } 1100