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*60139Sbostic static char sccsid[] = "@(#)build.c 5.6 (Berkeley) 05/19/93"; 1346012Sbostic #endif /* not lint */ 1446012Sbostic 1546012Sbostic #include <sys/types.h> 1646012Sbostic #include <sys/errno.h> 1746012Sbostic #include <sys/stat.h> 18*60139Sbostic 1946012Sbostic #include <a.out.h> 20*60139Sbostic #include <ar.h> 2146012Sbostic #include <dirent.h> 22*60139Sbostic #include <fcntl.h> 2346012Sbostic #include <ranlib.h> 2446012Sbostic #include <stdio.h> 25*60139Sbostic #include <unistd.h> 2646012Sbostic 27*60139Sbostic #include "archive.h" 28*60139Sbostic 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 43*60139Sbostic long symcnt; /* symbol count */ 44*60139Sbostic long tsymlen; /* total string length */ 45*60139Sbostic 46*60139Sbostic static void rexec __P((int, int)); 47*60139Sbostic static void symobj __P((void)); 48*60139Sbostic 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; 63*60139Sbostic 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 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 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