ref: cb1b6c86fe82527f4c3c5f8f11ea4f5e4ae6a350
dir: /src/cmd/ranlib.c/
#include <ctype.h> #include <errno.h> #include <limits.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <scc/ar.h> #include <scc/arg.h> #include <scc/mach.h> #include <scc/scc.h> #include "sys.h" #define NR_SYMDEF 32 typedef struct symdef Symdef; struct symdef { char *name; int type; long offset; Symdef *hash, *next; }; static char *namidx; static long nsymbols; static int status, artype, nolib; static char *filename, *membname; static Symdef *htab[NR_SYMDEF], *head; static long offset; char *argv0; static void error(char *fmt, ...) { va_list va; va_start(va, fmt); fprintf(stderr, "ranlib: %s: ", filename); if (membname) fprintf(stderr, "%s: ", membname); vfprintf(stderr, fmt, va); putc('\n', stderr); va_end(va); status = EXIT_FAILURE; } Symdef * lookup(char *name) { unsigned h; Symdef *dp; char *s; size_t len; h = genhash(name) % NR_SYMDEF; for (dp = htab[h]; dp; dp = dp->next) { if (!strcmp(dp->name, name)) return dp; } len = strlen(name) + 1; dp = malloc(sizeof(*dp)); s = malloc(len); if (!dp || !s) { free(s); free(dp); return NULL; } nsymbols++; dp->name = s; memcpy(dp->name, name, len); dp->type = 'U'; dp->offset = -1; dp->hash = htab[h]; htab[h] = dp; dp->next = head; head = dp; return dp; } static int newsymbol(Symbol *sym) { Symdef *np; if (!isupper(sym->type) || sym->type == 'N') return 1; if ((np = lookup(sym->name)) == NULL) { error(strerror(errno)); return 0; } switch (np->type) { case 'C': if (sym->type == 'C') break; case 'U': np->type = sym->type; np->offset = offset; break; default: if (sym->type != 'C') { error("multiple definitions of '%s'", sym->name); return 0; } } return 1; } static void freehash(void) { Symdef **npp, *next, *np; for (npp = htab; npp < &htab[NR_SYMDEF]; npp++) *npp = NULL; for (np = head; np; np = next) { next = np->next; free(np->name); free(np); } head = NULL; } static int newmember(FILE *fp) { int i,t, ret = 0; Obj *obj; Symbol sym; offset = ftell(fp); if (offset == EOF) { error(strerror(errno)); return 0; } t = objtype(fp, NULL); if (t == -1 || artype != -1 && artype != t) { nolib = 1; return 0; } artype = t; if ((obj = newobj(t)) == NULL) { error(strerror(errno)); return 0; } namidx = obj->index; if (readobj(obj, fp) < 0) { error(strerror(errno)); goto error; } for (i = 0; getsym(obj, &i, &sym); i++) { if (!newsymbol(&sym)) goto error; } ret = 1; error: delobj(obj); return ret; } static int readsyms(FILE *fp) { long cur, off; char memb[SARNAM+1]; nolib = 0; artype = -1; nsymbols = 0; if (!archive(fp)) { error("file format not recognized"); return 0; } cur = ftell(fp); if ((off = armember(fp, memb)) < 0) goto corrupted; if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) cur = ftell(fp) + off; fseek(fp, cur, SEEK_SET); for (;;) { cur = ftell(fp); off = armember(fp, memb); switch (off) { case -1: goto corrupted; case 0: return (nolib || nsymbols == 0) ? -1 : 0; default: membname = memb; if (objtype(fp, NULL) != -1) newmember(fp); membname = NULL; fseek(fp, cur, SEEK_SET); fseek(fp, off, SEEK_CUR); break; } } corrupted: error(strerror(errno)); error("library corrupted"); return 0; } static void merge(FILE *to, struct fprop *prop, FILE *lib, FILE *idx) { int c; char mtime[13]; struct ar_hdr first; rewind(lib); rewind(idx); fseek(lib, SARMAG, SEEK_SET); if (fread(&first, sizeof(first), 1, lib) != 1) return; if (!strncmp(first.ar_name, namidx, SARNAM)) fseek(lib, atol(first.ar_size), SEEK_CUR); else fseek(lib, SARMAG, SEEK_SET); fwrite(ARMAG, SARMAG, 1, to); strftime(mtime, sizeof(mtime), "%s", gmtime(&prop->time)); fprintf(to, "%-16.16s%-12s%-6u%-6u%-8lo%-10ld`\n", namidx, mtime, prop->uid, prop->gid, prop->mode, prop->size); while ((c = getc(idx)) != EOF) putc(c, to); if (prop->size & 1) putc('\n', to); while ((c = getc(lib)) != EOF) putc(c, to); fflush(to); } static void ranlib(char *fname) { size_t r; long *offs, i; char **names; FILE *fp, *idx, *out; Symdef *dp; struct fprop prop; char tmpname[FILENAME_MAX]; filename = fname; if ((fp = fopen(fname, "rb")) == NULL) { error(strerror(errno)); return; } if (readsyms(fp) <0) goto err2; if ((idx = tmpfile()) == NULL) { error(strerror(errno)); goto err2; } offs = malloc(sizeof(long) * nsymbols); names = malloc(sizeof(*names) * nsymbols); if (!offs || !names) { error(strerror(errno)); goto err3; } for (dp = head, i = 0; i < nsymbols; dp = dp->next, i++) { offs[i] = dp->offset; names[i] = dp->name; } if (setindex(artype, nsymbols, names, offs, idx) < 0) { error(strerror(errno)); goto err3; } if (getstat(fname, &prop) < 0) { error(strerror(errno)); goto err3; } prop.size = ftell(idx); prop.time = time(NULL); r = snprintf(tmpname, sizeof(tmpname), "%s.tmp", fname); if (r >= sizeof(tmpname)) { error("too long temporary name"); goto err3; } if ((out = fopen(tmpname, "wb")) == NULL) { error(strerror(errno)); goto err3; } merge(out, &prop, fp, idx); if (ferror(out) || ferror(fp) || ferror(idx)) { error(strerror(errno)); fclose(out); goto err4; } fclose(out); if (rename(tmpname, fname) == EOF) { error(strerror(errno)); goto err4; } err4: remove(tmpname); err3: free(offs); free(names); fclose(idx); err2: freehash(); err1: fclose(fp); } static void usage(void) { fputs("usage: ranlib [-t] file...\n", stderr); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { ARGBEGIN { case 't': break; default: usage(); } ARGEND if (argc == 0) usage(); for (; *argv; ++argv) ranlib(*argv); return status; }