146012Sbostic /*-
2*62197Sbostic * Copyright (c) 1990, 1993
3*62197Sbostic * The Regents of the University of California. 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*62197Sbostic static char sccsid[] = "@(#)build.c 8.1 (Berkeley) 06/06/93";
1346012Sbostic #endif /* not lint */
1446012Sbostic
1546012Sbostic #include <sys/types.h>
1646012Sbostic #include <sys/errno.h>
1746012Sbostic #include <sys/stat.h>
1860139Sbostic
1946012Sbostic #include <a.out.h>
2060139Sbostic #include <ar.h>
2146012Sbostic #include <dirent.h>
2260139Sbostic #include <fcntl.h>
2346012Sbostic #include <ranlib.h>
2446012Sbostic #include <stdio.h>
2560139Sbostic #include <unistd.h>
2646012Sbostic
2760139Sbostic #include "archive.h"
2860139Sbostic
2946012Sbostic extern CHDR chdr; /* converted header */
3046012Sbostic extern char *archive; /* archive name */
3146012Sbostic extern char *tname; /* temporary file "name" */
3246012Sbostic
3346012Sbostic typedef struct _rlib {
3446012Sbostic struct _rlib *next; /* next structure */
3546012Sbostic off_t pos; /* offset of defining archive file */
3646012Sbostic char *sym; /* symbol */
3746012Sbostic int symlen; /* strlen(sym) */
3846012Sbostic } RLIB;
3946012Sbostic RLIB *rhead, **pnext;
4046012Sbostic
4146012Sbostic FILE *fp;
4246012Sbostic
4360139Sbostic long symcnt; /* symbol count */
4460139Sbostic long tsymlen; /* total string length */
4560139Sbostic
4660139Sbostic static void rexec __P((int, int));
4760139Sbostic static void symobj __P((void));
4860139Sbostic
build()4946012Sbostic build()
5046012Sbostic {
5146012Sbostic CF cf;
5246012Sbostic int afd, tfd;
5346012Sbostic off_t size;
5446012Sbostic
5546012Sbostic afd = open_archive(O_RDWR);
5646012Sbostic fp = fdopen(afd, "r+");
5746012Sbostic tfd = tmp();
5846012Sbostic
5946012Sbostic SETCF(afd, archive, tfd, tname, RPAD|WPAD);
6046012Sbostic
6146012Sbostic /* Read through the archive, creating list of symbols. */
6246012Sbostic pnext = &rhead;
6360139Sbostic symcnt = tsymlen = 0;
6447241Sbostic while(get_arobj(afd)) {
6546012Sbostic if (!strcmp(chdr.name, RANLIBMAG)) {
6647241Sbostic skip_arobj(afd);
6746012Sbostic continue;
6846012Sbostic }
6946012Sbostic rexec(afd, tfd);
7047241Sbostic put_arobj(&cf, (struct stat *)NULL);
7146012Sbostic }
7246012Sbostic *pnext = NULL;
7346012Sbostic
7446012Sbostic /* Create the symbol table. */
7546012Sbostic symobj();
7646012Sbostic
7746012Sbostic /* Copy the saved objects into the archive. */
7846012Sbostic size = lseek(tfd, (off_t)0, SEEK_CUR);
7946012Sbostic (void)lseek(tfd, (off_t)0, SEEK_SET);
8046012Sbostic SETCF(tfd, tname, afd, archive, RPAD|WPAD);
8147241Sbostic copy_ar(&cf, size);
8246012Sbostic (void)ftruncate(afd, lseek(afd, (off_t)0, SEEK_CUR));
8346012Sbostic (void)close(tfd);
8446012Sbostic
8546012Sbostic /* Set the time. */
8646012Sbostic settime(afd);
8746012Sbostic close_archive(afd);
8846012Sbostic return(0);
8946012Sbostic }
9046012Sbostic
9146012Sbostic /*
9246012Sbostic * rexec
9346012Sbostic * Read the exec structure; ignore any files that don't look
9446012Sbostic * exactly right.
9546012Sbostic */
9646698Sbostic static void
rexec(rfd,wfd)9746012Sbostic rexec(rfd, wfd)
9846012Sbostic register int rfd;
9946012Sbostic int wfd;
10046012Sbostic {
10146012Sbostic register RLIB *rp;
10246012Sbostic register long nsyms;
10346012Sbostic register int nr, symlen;
10446012Sbostic register char *strtab, *sym;
10546012Sbostic struct exec ebuf;
10646012Sbostic struct nlist nl;
10746012Sbostic off_t r_off, w_off;
10846012Sbostic long strsize;
10946012Sbostic void *emalloc();
11046012Sbostic
11146012Sbostic /* Get current offsets for original and tmp files. */
11246012Sbostic r_off = lseek(rfd, (off_t)0, SEEK_CUR);
11346012Sbostic w_off = lseek(wfd, (off_t)0, SEEK_CUR);
11446012Sbostic
11546012Sbostic /* Read in exec structure. */
11654078Sbostic nr = read(rfd, &ebuf, sizeof(struct exec));
11746012Sbostic if (nr != sizeof(struct exec))
11846012Sbostic goto badread;
11946012Sbostic
12046012Sbostic /* Check magic number and symbol count. */
12146012Sbostic if (N_BADMAG(ebuf) || ebuf.a_syms == 0)
12246012Sbostic goto bad1;
12346012Sbostic
12446012Sbostic /* Seek to string table. */
12554078Sbostic if (lseek(rfd, r_off + N_STROFF(ebuf), SEEK_SET) == (off_t)-1)
12646012Sbostic error(archive);
12746012Sbostic
12846012Sbostic /* Read in size of the string table. */
12954078Sbostic nr = read(rfd, &strsize, sizeof(strsize));
13046012Sbostic if (nr != sizeof(strsize))
13146012Sbostic goto badread;
13246012Sbostic
13346012Sbostic /* Read in the string table. */
13446012Sbostic strsize -= sizeof(strsize);
13554078Sbostic strtab = emalloc(strsize);
13646012Sbostic nr = read(rfd, strtab, strsize);
13746012Sbostic if (nr != strsize) {
13846012Sbostic badread: if (nr < 0)
13946012Sbostic error(archive);
14046012Sbostic goto bad2;
14146012Sbostic }
14246012Sbostic
14346012Sbostic /* Seek to symbol table. */
14459716Storek if (fseek(fp, (long)r_off + N_SYMOFF(ebuf), SEEK_SET))
14546012Sbostic goto bad2;
14646012Sbostic
14746012Sbostic /* For each symbol read the nlist entry and save it as necessary. */
14846012Sbostic nsyms = ebuf.a_syms / sizeof(struct nlist);
14946012Sbostic while (nsyms--) {
15054078Sbostic if (!fread(&nl, sizeof(struct nlist), 1, fp)) {
15146012Sbostic if (feof(fp))
15246012Sbostic badfmt();
15346012Sbostic error(archive);
15446012Sbostic }
15546012Sbostic
15646012Sbostic /* Ignore if no name or local. */
15746012Sbostic if (!nl.n_un.n_strx || !(nl.n_type & N_EXT))
15846012Sbostic continue;
15946012Sbostic
16046012Sbostic /*
16146012Sbostic * If the symbol is an undefined external and the n_value
16246012Sbostic * field is non-zero, keep it.
16346012Sbostic */
16446012Sbostic if ((nl.n_type & N_TYPE) == N_UNDF && !nl.n_value)
16546012Sbostic continue;
16646012Sbostic
16746012Sbostic /* First four bytes are the table size. */
16846012Sbostic sym = strtab + nl.n_un.n_strx - sizeof(long);
16946012Sbostic symlen = strlen(sym) + 1;
17046012Sbostic
17146012Sbostic rp = (RLIB *)emalloc(sizeof(RLIB));
17246012Sbostic rp->sym = (char *)emalloc(symlen);
17346012Sbostic bcopy(sym, rp->sym, symlen);
17446012Sbostic rp->symlen = symlen;
17546012Sbostic rp->pos = w_off;
17646012Sbostic
17746012Sbostic /* Build in forward order for "ar -m" command. */
17846012Sbostic *pnext = rp;
17946012Sbostic pnext = &rp->next;
18046012Sbostic
18146012Sbostic ++symcnt;
18246012Sbostic tsymlen += symlen;
18346012Sbostic }
18446012Sbostic
18546012Sbostic bad2: free(strtab);
18654078Sbostic bad1: (void)lseek(rfd, r_off, SEEK_SET);
18746012Sbostic }
18846012Sbostic
18946012Sbostic /*
19046012Sbostic * symobj --
19146012Sbostic * Write the symbol table into the archive, computing offsets as
19246012Sbostic * writing.
19346012Sbostic */
19446698Sbostic static void
symobj()19546012Sbostic symobj()
19646012Sbostic {
19746012Sbostic register RLIB *rp;
19846012Sbostic struct ranlib rn;
19954078Sbostic off_t ransize;
20054078Sbostic long size, stroff;
20146012Sbostic char hb[sizeof(struct ar_hdr) + 1], pad;
20246012Sbostic
20346012Sbostic /* Rewind the archive, leaving the magic number. */
20459716Storek if (fseek(fp, (long)SARMAG, SEEK_SET))
20546012Sbostic error(archive);
20646012Sbostic
20746012Sbostic /* Size of the ranlib archive file, pad if necessary. */
20846012Sbostic ransize = sizeof(long) +
20946012Sbostic symcnt * sizeof(struct ranlib) + sizeof(long) + tsymlen;
21046012Sbostic if (ransize & 01) {
21146012Sbostic ++ransize;
21246012Sbostic pad = '\n';
21346012Sbostic } else
21446012Sbostic pad = '\0';
21546012Sbostic
21646012Sbostic /* Put out the ranlib archive file header. */
21746012Sbostic #define DEFMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
21846012Sbostic (void)sprintf(hb, HDR2, RANLIBMAG, 0L, getuid(), getgid(),
21946698Sbostic DEFMODE & ~umask(0), ransize, ARFMAG);
22046012Sbostic if (!fwrite(hb, sizeof(struct ar_hdr), 1, fp))
22146012Sbostic error(tname);
22246012Sbostic
22346012Sbostic /* First long is the size of the ranlib structure section. */
22446012Sbostic size = symcnt * sizeof(struct ranlib);
22554078Sbostic if (!fwrite(&size, sizeof(size), 1, fp))
22646012Sbostic error(tname);
22746012Sbostic
22846012Sbostic /* Offset of the first archive file. */
22946012Sbostic size = SARMAG + sizeof(struct ar_hdr) + ransize;
23046012Sbostic
23146012Sbostic /*
23246012Sbostic * Write out the ranlib structures. The offset into the string
23346012Sbostic * table is cumulative, the offset into the archive is the value
23446012Sbostic * set in rexec() plus the offset to the first archive file.
23546012Sbostic */
23646012Sbostic for (rp = rhead, stroff = 0; rp; rp = rp->next) {
23746012Sbostic rn.ran_un.ran_strx = stroff;
23846012Sbostic stroff += rp->symlen;
23946012Sbostic rn.ran_off = size + rp->pos;
24054078Sbostic if (!fwrite(&rn, sizeof(struct ranlib), 1, fp))
24146012Sbostic error(archive);
24246012Sbostic }
24346012Sbostic
24446012Sbostic /* Second long is the size of the string table. */
24554078Sbostic if (!fwrite(&tsymlen, sizeof(tsymlen), 1, fp))
24646012Sbostic error(tname);
24746012Sbostic
24846012Sbostic /* Write out the string table. */
24946012Sbostic for (rp = rhead; rp; rp = rp->next)
25046012Sbostic if (!fwrite(rp->sym, rp->symlen, 1, fp))
25146012Sbostic error(tname);
25246012Sbostic
25346012Sbostic if (pad && !fwrite(&pad, sizeof(pad), 1, fp))
25446012Sbostic error(tname);
25546012Sbostic
25646012Sbostic (void)fflush(fp);
25746012Sbostic }
258