xref: /csrg-svn/usr.bin/ranlib/build.c (revision 47241)
146012Sbostic /*-
246012Sbostic  * Copyright (c) 1990 The Regents of the University of California.
346012Sbostic  * All rights reserved.
446012Sbostic  *
546012Sbostic  * This code is derived from software contributed to Berkeley by
646012Sbostic  * Hugh Smith at The University of Guelph.
746012Sbostic  *
846012Sbostic  * %sccs.include.redist.c%
946012Sbostic  */
1046012Sbostic 
1146012Sbostic #ifndef lint
12*47241Sbostic static char sccsid[] = "@(#)build.c	5.3 (Berkeley) 03/12/91";
1346012Sbostic #endif /* not lint */
1446012Sbostic 
1546012Sbostic #include <sys/types.h>
1646012Sbostic #include <sys/errno.h>
1746012Sbostic #include <sys/stat.h>
1846012Sbostic #include <fcntl.h>
1946012Sbostic #include <a.out.h>
2046012Sbostic #include <dirent.h>
2146012Sbostic #include <unistd.h>
2246012Sbostic #include <ar.h>
2346012Sbostic #include <ranlib.h>
2446012Sbostic #include <stdio.h>
2546012Sbostic #include <archive.h>
2646012Sbostic 
2746012Sbostic extern CHDR chdr;			/* converted header */
2846012Sbostic extern char *archive;			/* archive name */
2946012Sbostic extern char *tname;			/* temporary file "name" */
3046012Sbostic 
3146012Sbostic typedef struct _rlib {
3246012Sbostic 	struct _rlib *next;		/* next structure */
3346012Sbostic 	off_t pos;			/* offset of defining archive file */
3446012Sbostic 	char *sym;			/* symbol */
3546012Sbostic 	int symlen;			/* strlen(sym) */
3646012Sbostic } RLIB;
3746012Sbostic RLIB *rhead, **pnext;
3846012Sbostic 
3946012Sbostic FILE *fp;
4046698Sbostic static void rexec(), symobj();
4146012Sbostic 
4246012Sbostic build()
4346012Sbostic {
4446012Sbostic 	CF cf;
4546012Sbostic 	int afd, tfd;
4646012Sbostic 	off_t size;
4746012Sbostic 
4846012Sbostic 	afd = open_archive(O_RDWR);
4946012Sbostic 	fp = fdopen(afd, "r+");
5046012Sbostic 	tfd = tmp();
5146012Sbostic 
5246012Sbostic 	SETCF(afd, archive, tfd, tname, RPAD|WPAD);
5346012Sbostic 
5446012Sbostic 	/* Read through the archive, creating list of symbols. */
5546012Sbostic 	pnext = &rhead;
56*47241Sbostic 	while(get_arobj(afd)) {
5746012Sbostic 		if (!strcmp(chdr.name, RANLIBMAG)) {
58*47241Sbostic 			skip_arobj(afd);
5946012Sbostic 			continue;
6046012Sbostic 		}
6146012Sbostic 		rexec(afd, tfd);
62*47241Sbostic 		put_arobj(&cf, (struct stat *)NULL);
6346012Sbostic 	}
6446012Sbostic 	*pnext = NULL;
6546012Sbostic 
6646012Sbostic 	/* Create the symbol table. */
6746012Sbostic 	symobj();
6846012Sbostic 
6946012Sbostic 	/* Copy the saved objects into the archive. */
7046012Sbostic 	size = lseek(tfd, (off_t)0, SEEK_CUR);
7146012Sbostic 	(void)lseek(tfd, (off_t)0, SEEK_SET);
7246012Sbostic 	SETCF(tfd, tname, afd, archive, RPAD|WPAD);
73*47241Sbostic 	copy_ar(&cf, size);
7446012Sbostic 	(void)ftruncate(afd, lseek(afd, (off_t)0, SEEK_CUR));
7546012Sbostic 	(void)close(tfd);
7646012Sbostic 
7746012Sbostic 	/* Set the time. */
7846012Sbostic 	settime(afd);
7946012Sbostic 	close_archive(afd);
8046012Sbostic 	return(0);
8146012Sbostic }
8246012Sbostic 
8346012Sbostic long symcnt;				/* symbol count */
8446012Sbostic long tsymlen;				/* total string length */
8546012Sbostic 
8646012Sbostic /*
8746012Sbostic  * rexec
8846012Sbostic  *	Read the exec structure; ignore any files that don't look
8946012Sbostic  *	exactly right.
9046012Sbostic  */
9146698Sbostic static void
9246012Sbostic rexec(rfd, wfd)
9346012Sbostic 	register int rfd;
9446012Sbostic 	int wfd;
9546012Sbostic {
9646012Sbostic 	register RLIB *rp;
9746012Sbostic 	register long nsyms;
9846012Sbostic 	register int nr, symlen;
9946012Sbostic 	register char *strtab, *sym;
10046012Sbostic 	struct exec ebuf;
10146012Sbostic 	struct nlist nl;
10246012Sbostic 	off_t r_off, w_off;
10346012Sbostic 	long strsize;
10446012Sbostic 	void *emalloc();
10546012Sbostic 
10646012Sbostic 	/* Get current offsets for original and tmp files. */
10746012Sbostic 	r_off = lseek(rfd, (off_t)0, SEEK_CUR);
10846012Sbostic 	w_off = lseek(wfd, (off_t)0, SEEK_CUR);
10946012Sbostic 
11046012Sbostic 	/* Read in exec structure. */
11146012Sbostic 	nr = read(rfd, (char *)&ebuf, sizeof(struct exec));
11246012Sbostic 	if (nr != sizeof(struct exec))
11346012Sbostic 		goto badread;
11446012Sbostic 
11546012Sbostic 	/* Check magic number and symbol count. */
11646012Sbostic 	if (N_BADMAG(ebuf) || ebuf.a_syms == 0)
11746012Sbostic 		goto bad1;
11846012Sbostic 
11946012Sbostic 	/* Seek to string table. */
12046012Sbostic 	if (lseek(rfd, N_STROFF(ebuf) + r_off, SEEK_SET) == (off_t)-1)
12146012Sbostic 		error(archive);
12246012Sbostic 
12346012Sbostic 	/* Read in size of the string table. */
12446012Sbostic 	nr = read(rfd, (char *)&strsize, sizeof(strsize));
12546012Sbostic 	if (nr != sizeof(strsize))
12646012Sbostic 		goto badread;
12746012Sbostic 
12846012Sbostic 	/* Read in the string table. */
12946012Sbostic 	strsize -= sizeof(strsize);
13046012Sbostic 	strtab = (char *)emalloc(strsize);
13146012Sbostic 	nr = read(rfd, strtab, strsize);
13246012Sbostic 	if (nr != strsize) {
13346012Sbostic badread:	if (nr < 0)
13446012Sbostic 			error(archive);
13546012Sbostic 		goto bad2;
13646012Sbostic 	}
13746012Sbostic 
13846012Sbostic 	/* Seek to symbol table. */
13946012Sbostic 	if (fseek(fp, N_SYMOFF(ebuf) + r_off, SEEK_SET) == (off_t)-1)
14046012Sbostic 		goto bad2;
14146012Sbostic 
14246012Sbostic 	/* For each symbol read the nlist entry and save it as necessary. */
14346012Sbostic 	nsyms = ebuf.a_syms / sizeof(struct nlist);
14446012Sbostic 	while (nsyms--) {
14546012Sbostic 		if (!fread((char *)&nl, sizeof(struct nlist), 1, fp)) {
14646012Sbostic 			if (feof(fp))
14746012Sbostic 				badfmt();
14846012Sbostic 			error(archive);
14946012Sbostic 		}
15046012Sbostic 
15146012Sbostic 		/* Ignore if no name or local. */
15246012Sbostic 		if (!nl.n_un.n_strx || !(nl.n_type & N_EXT))
15346012Sbostic 			continue;
15446012Sbostic 
15546012Sbostic 		/*
15646012Sbostic 		 * If the symbol is an undefined external and the n_value
15746012Sbostic 		 * field is non-zero, keep it.
15846012Sbostic 		 */
15946012Sbostic 		if ((nl.n_type & N_TYPE) == N_UNDF && !nl.n_value)
16046012Sbostic 			continue;
16146012Sbostic 
16246012Sbostic 		/* First four bytes are the table size. */
16346012Sbostic 		sym = strtab + nl.n_un.n_strx - sizeof(long);
16446012Sbostic 		symlen = strlen(sym) + 1;
16546012Sbostic 
16646012Sbostic 		rp = (RLIB *)emalloc(sizeof(RLIB));
16746012Sbostic 		rp->sym = (char *)emalloc(symlen);
16846012Sbostic 		bcopy(sym, rp->sym, symlen);
16946012Sbostic 		rp->symlen = symlen;
17046012Sbostic 		rp->pos = w_off;
17146012Sbostic 
17246012Sbostic 		/* Build in forward order for "ar -m" command. */
17346012Sbostic 		*pnext = rp;
17446012Sbostic 		pnext = &rp->next;
17546012Sbostic 
17646012Sbostic 		++symcnt;
17746012Sbostic 		tsymlen += symlen;
17846012Sbostic 	}
17946012Sbostic 
18046012Sbostic bad2:	free(strtab);
18146012Sbostic bad1:	(void)lseek(rfd, (off_t)r_off, SEEK_SET);
18246012Sbostic }
18346012Sbostic 
18446012Sbostic /*
18546012Sbostic  * symobj --
18646012Sbostic  *	Write the symbol table into the archive, computing offsets as
18746012Sbostic  *	writing.
18846012Sbostic  */
18946698Sbostic static void
19046012Sbostic symobj()
19146012Sbostic {
19246012Sbostic 	register RLIB *rp;
19346012Sbostic 	struct ranlib rn;
19446012Sbostic 	char hb[sizeof(struct ar_hdr) + 1], pad;
19546012Sbostic 	long ransize, size, stroff;
19646012Sbostic 	gid_t getgid();
19746012Sbostic 	uid_t getuid();
19846012Sbostic 
19946012Sbostic 	/* Rewind the archive, leaving the magic number. */
20046012Sbostic 	if (fseek(fp, (off_t)SARMAG, SEEK_SET) == (off_t)-1)
20146012Sbostic 		error(archive);
20246012Sbostic 
20346012Sbostic 	/* Size of the ranlib archive file, pad if necessary. */
20446012Sbostic 	ransize = sizeof(long) +
20546012Sbostic 	    symcnt * sizeof(struct ranlib) + sizeof(long) + tsymlen;
20646012Sbostic 	if (ransize & 01) {
20746012Sbostic 		++ransize;
20846012Sbostic 		pad = '\n';
20946012Sbostic 	} else
21046012Sbostic 		pad = '\0';
21146012Sbostic 
21246012Sbostic 	/* Put out the ranlib archive file header. */
21346012Sbostic #define	DEFMODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
21446012Sbostic 	(void)sprintf(hb, HDR2, RANLIBMAG, 0L, getuid(), getgid(),
21546698Sbostic 	    DEFMODE & ~umask(0), ransize, ARFMAG);
21646012Sbostic 	if (!fwrite(hb, sizeof(struct ar_hdr), 1, fp))
21746012Sbostic 		error(tname);
21846012Sbostic 
21946012Sbostic 	/* First long is the size of the ranlib structure section. */
22046012Sbostic 	size = symcnt * sizeof(struct ranlib);
22146012Sbostic 	if (!fwrite((char *)&size, sizeof(size), 1, fp))
22246012Sbostic 		error(tname);
22346012Sbostic 
22446012Sbostic 	/* Offset of the first archive file. */
22546012Sbostic 	size = SARMAG + sizeof(struct ar_hdr) + ransize;
22646012Sbostic 
22746012Sbostic 	/*
22846012Sbostic 	 * Write out the ranlib structures.  The offset into the string
22946012Sbostic 	 * table is cumulative, the offset into the archive is the value
23046012Sbostic 	 * set in rexec() plus the offset to the first archive file.
23146012Sbostic 	 */
23246012Sbostic 	for (rp = rhead, stroff = 0; rp; rp = rp->next) {
23346012Sbostic 		rn.ran_un.ran_strx = stroff;
23446012Sbostic 		stroff += rp->symlen;
23546012Sbostic 		rn.ran_off = size + rp->pos;
23646012Sbostic 		if (!fwrite((char *)&rn, sizeof(struct ranlib), 1, fp))
23746012Sbostic 			error(archive);
23846012Sbostic 	}
23946012Sbostic 
24046012Sbostic 	/* Second long is the size of the string table. */
24146012Sbostic 	if (!fwrite((char *)&tsymlen, sizeof(tsymlen), 1, fp))
24246012Sbostic 		error(tname);
24346012Sbostic 
24446012Sbostic 	/* Write out the string table. */
24546012Sbostic 	for (rp = rhead; rp; rp = rp->next)
24646012Sbostic 		if (!fwrite(rp->sym, rp->symlen, 1, fp))
24746012Sbostic 			error(tname);
24846012Sbostic 
24946012Sbostic 	if (pad && !fwrite(&pad, sizeof(pad), 1, fp))
25046012Sbostic 		error(tname);
25146012Sbostic 
25246012Sbostic 	(void)fflush(fp);
25346012Sbostic }
254