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