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