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