1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Hugh Smith at The University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)build.c 8.1 (Berkeley) 06/06/93"; 13 #endif /* not lint */ 14 15 #include <sys/types.h> 16 #include <sys/errno.h> 17 #include <sys/stat.h> 18 19 #include <a.out.h> 20 #include <ar.h> 21 #include <dirent.h> 22 #include <fcntl.h> 23 #include <ranlib.h> 24 #include <stdio.h> 25 #include <unistd.h> 26 27 #include "archive.h" 28 29 extern CHDR chdr; /* converted header */ 30 extern char *archive; /* archive name */ 31 extern char *tname; /* temporary file "name" */ 32 33 typedef struct _rlib { 34 struct _rlib *next; /* next structure */ 35 off_t pos; /* offset of defining archive file */ 36 char *sym; /* symbol */ 37 int symlen; /* strlen(sym) */ 38 } RLIB; 39 RLIB *rhead, **pnext; 40 41 FILE *fp; 42 43 long symcnt; /* symbol count */ 44 long tsymlen; /* total string length */ 45 46 static void rexec __P((int, int)); 47 static void symobj __P((void)); 48 49 build() 50 { 51 CF cf; 52 int afd, tfd; 53 off_t size; 54 55 afd = open_archive(O_RDWR); 56 fp = fdopen(afd, "r+"); 57 tfd = tmp(); 58 59 SETCF(afd, archive, tfd, tname, RPAD|WPAD); 60 61 /* Read through the archive, creating list of symbols. */ 62 pnext = &rhead; 63 symcnt = tsymlen = 0; 64 while(get_arobj(afd)) { 65 if (!strcmp(chdr.name, RANLIBMAG)) { 66 skip_arobj(afd); 67 continue; 68 } 69 rexec(afd, tfd); 70 put_arobj(&cf, (struct stat *)NULL); 71 } 72 *pnext = NULL; 73 74 /* Create the symbol table. */ 75 symobj(); 76 77 /* Copy the saved objects into the archive. */ 78 size = lseek(tfd, (off_t)0, SEEK_CUR); 79 (void)lseek(tfd, (off_t)0, SEEK_SET); 80 SETCF(tfd, tname, afd, archive, RPAD|WPAD); 81 copy_ar(&cf, size); 82 (void)ftruncate(afd, lseek(afd, (off_t)0, SEEK_CUR)); 83 (void)close(tfd); 84 85 /* Set the time. */ 86 settime(afd); 87 close_archive(afd); 88 return(0); 89 } 90 91 /* 92 * rexec 93 * Read the exec structure; ignore any files that don't look 94 * exactly right. 95 */ 96 static void 97 rexec(rfd, wfd) 98 register int rfd; 99 int wfd; 100 { 101 register RLIB *rp; 102 register long nsyms; 103 register int nr, symlen; 104 register char *strtab, *sym; 105 struct exec ebuf; 106 struct nlist nl; 107 off_t r_off, w_off; 108 long strsize; 109 void *emalloc(); 110 111 /* Get current offsets for original and tmp files. */ 112 r_off = lseek(rfd, (off_t)0, SEEK_CUR); 113 w_off = lseek(wfd, (off_t)0, SEEK_CUR); 114 115 /* Read in exec structure. */ 116 nr = read(rfd, &ebuf, sizeof(struct exec)); 117 if (nr != sizeof(struct exec)) 118 goto badread; 119 120 /* Check magic number and symbol count. */ 121 if (N_BADMAG(ebuf) || ebuf.a_syms == 0) 122 goto bad1; 123 124 /* Seek to string table. */ 125 if (lseek(rfd, r_off + N_STROFF(ebuf), SEEK_SET) == (off_t)-1) 126 error(archive); 127 128 /* Read in size of the string table. */ 129 nr = read(rfd, &strsize, sizeof(strsize)); 130 if (nr != sizeof(strsize)) 131 goto badread; 132 133 /* Read in the string table. */ 134 strsize -= sizeof(strsize); 135 strtab = emalloc(strsize); 136 nr = read(rfd, strtab, strsize); 137 if (nr != strsize) { 138 badread: if (nr < 0) 139 error(archive); 140 goto bad2; 141 } 142 143 /* Seek to symbol table. */ 144 if (fseek(fp, (long)r_off + N_SYMOFF(ebuf), SEEK_SET)) 145 goto bad2; 146 147 /* For each symbol read the nlist entry and save it as necessary. */ 148 nsyms = ebuf.a_syms / sizeof(struct nlist); 149 while (nsyms--) { 150 if (!fread(&nl, sizeof(struct nlist), 1, fp)) { 151 if (feof(fp)) 152 badfmt(); 153 error(archive); 154 } 155 156 /* Ignore if no name or local. */ 157 if (!nl.n_un.n_strx || !(nl.n_type & N_EXT)) 158 continue; 159 160 /* 161 * If the symbol is an undefined external and the n_value 162 * field is non-zero, keep it. 163 */ 164 if ((nl.n_type & N_TYPE) == N_UNDF && !nl.n_value) 165 continue; 166 167 /* First four bytes are the table size. */ 168 sym = strtab + nl.n_un.n_strx - sizeof(long); 169 symlen = strlen(sym) + 1; 170 171 rp = (RLIB *)emalloc(sizeof(RLIB)); 172 rp->sym = (char *)emalloc(symlen); 173 bcopy(sym, rp->sym, symlen); 174 rp->symlen = symlen; 175 rp->pos = w_off; 176 177 /* Build in forward order for "ar -m" command. */ 178 *pnext = rp; 179 pnext = &rp->next; 180 181 ++symcnt; 182 tsymlen += symlen; 183 } 184 185 bad2: free(strtab); 186 bad1: (void)lseek(rfd, r_off, SEEK_SET); 187 } 188 189 /* 190 * symobj -- 191 * Write the symbol table into the archive, computing offsets as 192 * writing. 193 */ 194 static void 195 symobj() 196 { 197 register RLIB *rp; 198 struct ranlib rn; 199 off_t ransize; 200 long size, stroff; 201 char hb[sizeof(struct ar_hdr) + 1], pad; 202 203 /* Rewind the archive, leaving the magic number. */ 204 if (fseek(fp, (long)SARMAG, SEEK_SET)) 205 error(archive); 206 207 /* Size of the ranlib archive file, pad if necessary. */ 208 ransize = sizeof(long) + 209 symcnt * sizeof(struct ranlib) + sizeof(long) + tsymlen; 210 if (ransize & 01) { 211 ++ransize; 212 pad = '\n'; 213 } else 214 pad = '\0'; 215 216 /* Put out the ranlib archive file header. */ 217 #define DEFMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) 218 (void)sprintf(hb, HDR2, RANLIBMAG, 0L, getuid(), getgid(), 219 DEFMODE & ~umask(0), ransize, ARFMAG); 220 if (!fwrite(hb, sizeof(struct ar_hdr), 1, fp)) 221 error(tname); 222 223 /* First long is the size of the ranlib structure section. */ 224 size = symcnt * sizeof(struct ranlib); 225 if (!fwrite(&size, sizeof(size), 1, fp)) 226 error(tname); 227 228 /* Offset of the first archive file. */ 229 size = SARMAG + sizeof(struct ar_hdr) + ransize; 230 231 /* 232 * Write out the ranlib structures. The offset into the string 233 * table is cumulative, the offset into the archive is the value 234 * set in rexec() plus the offset to the first archive file. 235 */ 236 for (rp = rhead, stroff = 0; rp; rp = rp->next) { 237 rn.ran_un.ran_strx = stroff; 238 stroff += rp->symlen; 239 rn.ran_off = size + rp->pos; 240 if (!fwrite(&rn, sizeof(struct ranlib), 1, fp)) 241 error(archive); 242 } 243 244 /* Second long is the size of the string table. */ 245 if (!fwrite(&tsymlen, sizeof(tsymlen), 1, fp)) 246 error(tname); 247 248 /* Write out the string table. */ 249 for (rp = rhead; rp; rp = rp->next) 250 if (!fwrite(rp->sym, rp->symlen, 1, fp)) 251 error(tname); 252 253 if (pad && !fwrite(&pad, sizeof(pad), 1, fp)) 254 error(tname); 255 256 (void)fflush(fp); 257 } 258