1#include <ctype.h>2#include <errno.h>3#include <limits.h>4#include <stdarg.h>5#include <stdio.h>6#include <stdlib.h>7#include <string.h>8#include <time.h>910#include <scc/ar.h>11#include <scc/arg.h>12#include <scc/mach.h>13#include <scc/scc.h>1415#define NR_SYMDEF 321617typedef struct symdef Symdef;1819struct symdef {20 char *name;21 int type;22 long offset;23 Symdef *hash, *next;24};2526static char *namidx;27static long nsymbols;28static int status, artype, nolib;29static char *filename, *membname;30static Symdef *htab[NR_SYMDEF], *head;31char *argv0;3233static void34error(char *fmt, ...)35{36 va_list va;3738 va_start(va, fmt);39 fprintf(stderr, "scc-ranlib: %s: ", filename);40 if (membname)41 fprintf(stderr, "%s: ", membname);42 vfprintf(stderr, fmt, va);43 putc('\n', stderr);44 va_end(va);4546 status = EXIT_FAILURE;47}4849Symdef *50lookup(char *name)51{52 unsigned h;53 Symdef *dp;54 char *s;55 size_t len;5657 h = genhash(name) % NR_SYMDEF;5859 for (dp = htab[h]; dp; dp = dp->next) {60 if (!strcmp(dp->name, name))61 return dp;62 }6364 len = strlen(name) + 1;65 dp = malloc(sizeof(*dp));66 s = malloc(len);67 if (!dp || !s) {68 free(s);69 free(dp);70 return NULL;71 }7273 nsymbols++;74 dp->name = s;75 memcpy(dp->name, name, len);76 dp->type = 'U';77 dp->offset = -1;78 dp->hash = htab[h];79 htab[h] = dp;80 dp->next = head;81 head = dp;8283 return dp;84}8586static int87newsymbol(Symbol *sym, long off)88{89 Symdef *np;9091 if (!isupper(sym->type) || sym->type == 'N' || sym->type == 'U')92 return 1;9394 if ((np = lookup(sym->name)) == NULL) {95 error(strerror(errno));96 return 0;97 }9899 switch (np->type) {100 case 'C':101 if (sym->type == 'C')102 break;103 case 'U':104 np->type = sym->type;105 np->offset = off;106 break;107 default:108 if (sym->type != 'C') {109 error("multiple definitions of '%s'", sym->name);110 return 0;111 }112 }113114 return 1;115}116117static void118freehash(void)119{120 Symdef **npp, *next, *np;121122 for (npp = htab; npp < &htab[NR_SYMDEF]; npp++)123 *npp = NULL;124125 for (np = head; np; np = next) {126 next = np->next;127 free(np->name);128 free(np);129 }130131 head = NULL;132}133134static int135newmember(FILE *fp, long off)136{137 int i,t, ret = 0;138 Obj *obj;139 Symbol sym;140141 t = objprobe(fp, NULL);142 if (t == -1 || artype != -1 && artype != t) {143 nolib = 1;144 return 0;145 }146 artype = t;147148 if ((obj = newobj(t)) == NULL) {149 error(strerror(errno));150 return 0;151 }152 namidx = obj->index;153154 if (readobj(obj, fp) < 0) {155 error(strerror(errno));156 goto error;157 }158159 for (i = 0; getsym(obj, &i, &sym); i++) {160 if (!newsymbol(&sym, off))161 goto error;162 }163164 ret = 1;165166error:167 delobj(obj);168 return ret;169}170171static int172readsyms(FILE *fp)173{174 long idxsiz, cur, off;175 char memb[SARNAM+1];176177 nolib = 0;178 artype = -1;179 nsymbols = 0;180 idxsiz = 0;181182 if (!archive(fp)) {183 error("file format not recognized");184 return 0;185 }186187 cur = ftell(fp);188 if ((off = armember(fp, memb, NULL)) < 0)189 goto corrupted;190191 if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) {192 idxsiz = off;193 cur += off;194 }195196 fseek(fp, cur, SEEK_SET);197 for (;;) {198 cur = ftell(fp);199 off = armember(fp, memb, NULL);200 switch (off) {201 case -1:202 goto corrupted;203 case 0:204 return (nolib || nsymbols == 0) ? -1 : 0;205 default:206 membname = memb;207 if (objprobe(fp, NULL) != -1)208 newmember(fp, cur - idxsiz);209 membname = NULL;210 fseek(fp, cur, SEEK_SET);211 fseek(fp, off, SEEK_CUR);212 break;213 }214 }215216corrupted:217 error(strerror(errno));218 error("library corrupted");219 return 0;220}221222static void223merge(FILE *to, struct fprop *prop, FILE *lib, FILE *idx)224{225 int c;226 struct ar_hdr first;227228 rewind(lib);229 rewind(idx);230 fseek(lib, SARMAG, SEEK_SET);231232 if (fread(&first, sizeof(first), 1, lib) != 1)233 return;234235 if (!strncmp(first.ar_name, namidx, strlen(namidx))) {236 long siz = atol(first.ar_size);237 fseek(lib, siz + (siz & 1), SEEK_CUR);238 } else {239 fseek(lib, SARMAG, SEEK_SET);240 }241242 fwrite(ARMAG, SARMAG, 1, to);243244 fprintf(to,245 "%-16.16s%-12lld%-6u%-6u%-8lo%-10ld`\n",246 namidx,247 fromepoch(prop->time),248 prop->uid,249 prop->gid,250 prop->mode,251 prop->size);252253 while ((c = getc(idx)) != EOF)254 putc(c, to);255 if (prop->size & 1)256 putc('\n', to);257258 while ((c = getc(lib)) != EOF)259 putc(c, to);260261 fflush(to);262}263264static void265ranlib(char *fname)266{267 size_t r;268 long *offs, size, i;269 char **names;270 FILE *fp, *idx, *out;271 Symdef *dp;272 struct fprop prop;273 char tmpname[FILENAME_MAX];274275 filename = fname;276 if ((fp = fopen(fname, "rb")) == NULL) {277 error(strerror(errno));278 return;279 }280281 if (readsyms(fp) <0)282 goto err2;283284 if ((idx = tmpfile()) == NULL) {285 error(strerror(errno));286 goto err2;287 }288289 offs = malloc(sizeof(long) * nsymbols);290 names = malloc(sizeof(*names) * nsymbols);291 if (!offs || !names) {292 error(strerror(errno));293 goto err3;294 }295296 for (dp = head, i = 0; i < nsymbols; dp = dp->next, i++) {297 offs[i] = dp->offset;298 names[i] = dp->name;299 }300301 /* First pass: write index to determine its size */302 if (setindex(artype, nsymbols, names, offs, idx) < 0) {303 error(strerror(errno));304 goto err3;305 }306307 if (getstat(fname, &prop) < 0) {308 error(strerror(errno));309 goto err3;310 }311 prop.time = time(NULL);312 prop.size = ftell(idx);313314 size = sizeof(struct ar_hdr) + prop.size + (prop.size & 1);315 for (i = 0; i < nsymbols; i++)316 offs[i] += size;317318 /* Second pass: rewrite index with corrected offsets */319 rewind(idx);320 if (setindex(artype, nsymbols, names, offs, idx) < 0) {321 error(strerror(errno));322 goto err3;323 }324325 r = snprintf(tmpname, sizeof(tmpname), "%s.tmp", fname);326 if (r >= sizeof(tmpname)) {327 error("too long temporary name");328 goto err3;329 }330331 if ((out = fopen(tmpname, "wb")) == NULL) {332 error(strerror(errno));333 goto err3;334 }335336 merge(out, &prop, fp, idx);337 if (ferror(out) || ferror(fp) || ferror(idx)) {338 error(strerror(errno));339 fclose(out);340 goto err4;341 }342343 fclose(out);344 if (rename(tmpname, fname) == EOF) {345 error(strerror(errno));346 goto err4;347 }348349err4:350 remove(tmpname);351err3:352 free(offs);353 free(names);354 fclose(idx);355err2:356 freehash();357err1:358 fclose(fp);359}360361static void362usage(void)363{364 fputs("usage: scc-ranlib [-t] file...\n", stderr);365 exit(EXIT_FAILURE);366}367368int369main(int argc, char *argv[])370{371 ARGBEGIN {372 case 't':373 break;374 default:375 usage();376 } ARGEND377378 if (argc == 0)379 usage();380381 for (; *argv; ++argv)382 ranlib(*argv);383384 return status;385}