scc-ranlib.c (5885B)
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> 9 10 #include <scc/ar.h> 11 #include <scc/arg.h> 12 #include <scc/mach.h> 13 #include <scc/scc.h> 14 15 #define NR_SYMDEF 32 16 17 typedef struct symdef Symdef; 18 19 struct symdef { 20 char *name; 21 int type; 22 long offset; 23 Symdef *hash, *next; 24 }; 25 26 static char *namidx; 27 static long nsymbols; 28 static int status, artype, nolib; 29 static char *filename, *membname; 30 static Symdef *htab[NR_SYMDEF], *head; 31 static long offset; 32 char *argv0; 33 34 static void 35 error(char *fmt, ...) 36 { 37 va_list va; 38 39 va_start(va, fmt); 40 fprintf(stderr, "ranlib: %s: ", filename); 41 if (membname) 42 fprintf(stderr, "%s: ", membname); 43 vfprintf(stderr, fmt, va); 44 putc('\n', stderr); 45 va_end(va); 46 47 status = EXIT_FAILURE; 48 } 49 50 Symdef * 51 lookup(char *name) 52 { 53 unsigned h; 54 Symdef *dp; 55 char *s; 56 size_t len; 57 58 h = genhash(name) % NR_SYMDEF; 59 60 for (dp = htab[h]; dp; dp = dp->next) { 61 if (!strcmp(dp->name, name)) 62 return dp; 63 } 64 65 len = strlen(name) + 1; 66 dp = malloc(sizeof(*dp)); 67 s = malloc(len); 68 if (!dp || !s) { 69 free(s); 70 free(dp); 71 return NULL; 72 } 73 74 nsymbols++; 75 dp->name = s; 76 memcpy(dp->name, name, len); 77 dp->type = 'U'; 78 dp->offset = -1; 79 dp->hash = htab[h]; 80 htab[h] = dp; 81 dp->next = head; 82 head = dp; 83 84 return dp; 85 } 86 87 static int 88 newsymbol(Symbol *sym) 89 { 90 Symdef *np; 91 92 if (!isupper(sym->type) || sym->type == 'N') 93 return 1; 94 95 if ((np = lookup(sym->name)) == NULL) { 96 error(strerror(errno)); 97 return 0; 98 } 99 100 switch (np->type) { 101 case 'C': 102 if (sym->type == 'C') 103 break; 104 case 'U': 105 np->type = sym->type; 106 np->offset = offset; 107 break; 108 default: 109 if (sym->type != 'C') { 110 error("multiple definitions of '%s'", sym->name); 111 return 0; 112 } 113 } 114 115 return 1; 116 } 117 118 static void 119 freehash(void) 120 { 121 Symdef **npp, *next, *np; 122 123 for (npp = htab; npp < &htab[NR_SYMDEF]; npp++) 124 *npp = NULL; 125 126 for (np = head; np; np = next) { 127 next = np->next; 128 free(np->name); 129 free(np); 130 } 131 132 head = NULL; 133 } 134 135 static int 136 newmember(FILE *fp) 137 { 138 int i,t, ret = 0; 139 Obj *obj; 140 Symbol sym; 141 142 offset = ftell(fp); 143 144 if (offset == EOF) { 145 error(strerror(errno)); 146 return 0; 147 } 148 149 t = objprobe(fp, NULL); 150 if (t == -1 || artype != -1 && artype != t) { 151 nolib = 1; 152 return 0; 153 } 154 artype = t; 155 156 if ((obj = newobj(t)) == NULL) { 157 error(strerror(errno)); 158 return 0; 159 } 160 namidx = obj->index; 161 162 if (readobj(obj, fp) < 0) { 163 error(strerror(errno)); 164 goto error; 165 } 166 167 for (i = 0; getsym(obj, &i, &sym); i++) { 168 if (!newsymbol(&sym)) 169 goto error; 170 } 171 172 ret = 1; 173 174 error: 175 delobj(obj); 176 return ret; 177 } 178 179 static int 180 readsyms(FILE *fp) 181 { 182 long cur, off; 183 char memb[SARNAM+1]; 184 185 nolib = 0; 186 artype = -1; 187 nsymbols = 0; 188 189 if (!archive(fp)) { 190 error("file format not recognized"); 191 return 0; 192 } 193 194 cur = ftell(fp); 195 if ((off = armember(fp, memb)) < 0) 196 goto corrupted; 197 198 if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) 199 cur = ftell(fp) + off; 200 201 fseek(fp, cur, SEEK_SET); 202 for (;;) { 203 cur = ftell(fp); 204 off = armember(fp, memb); 205 switch (off) { 206 case -1: 207 goto corrupted; 208 case 0: 209 return (nolib || nsymbols == 0) ? -1 : 0; 210 default: 211 membname = memb; 212 if (objprobe(fp, NULL) != -1) 213 newmember(fp); 214 membname = NULL; 215 fseek(fp, cur, SEEK_SET); 216 fseek(fp, off, SEEK_CUR); 217 break; 218 } 219 } 220 221 corrupted: 222 error(strerror(errno)); 223 error("library corrupted"); 224 return 0; 225 } 226 227 static void 228 merge(FILE *to, struct fprop *prop, FILE *lib, FILE *idx) 229 { 230 int c; 231 struct ar_hdr first; 232 233 rewind(lib); 234 rewind(idx); 235 fseek(lib, SARMAG, SEEK_SET); 236 237 if (fread(&first, sizeof(first), 1, lib) != 1) 238 return; 239 240 if (!strncmp(first.ar_name, namidx, SARNAM)) 241 fseek(lib, atol(first.ar_size), SEEK_CUR); 242 else 243 fseek(lib, SARMAG, SEEK_SET); 244 245 fwrite(ARMAG, SARMAG, 1, to); 246 247 fprintf(to, 248 "%-16.16s%-12lld%-6u%-6u%-8lo%-10ld`\n", 249 namidx, 250 fromepoch(prop->time), 251 prop->uid, 252 prop->gid, 253 prop->mode, 254 prop->size); 255 256 while ((c = getc(idx)) != EOF) 257 putc(c, to); 258 if (prop->size & 1) 259 putc('\n', to); 260 261 while ((c = getc(lib)) != EOF) 262 putc(c, to); 263 264 fflush(to); 265 } 266 267 static void 268 ranlib(char *fname) 269 { 270 size_t r; 271 long *offs, i; 272 char **names; 273 FILE *fp, *idx, *out; 274 Symdef *dp; 275 struct fprop prop; 276 char tmpname[FILENAME_MAX]; 277 278 filename = fname; 279 if ((fp = fopen(fname, "rb")) == NULL) { 280 error(strerror(errno)); 281 return; 282 } 283 284 if (readsyms(fp) <0) 285 goto err2; 286 287 if ((idx = tmpfile()) == NULL) { 288 error(strerror(errno)); 289 goto err2; 290 } 291 292 offs = malloc(sizeof(long) * nsymbols); 293 names = malloc(sizeof(*names) * nsymbols); 294 if (!offs || !names) { 295 error(strerror(errno)); 296 goto err3; 297 } 298 299 for (dp = head, i = 0; i < nsymbols; dp = dp->next, i++) { 300 offs[i] = dp->offset; 301 names[i] = dp->name; 302 } 303 304 if (setindex(artype, nsymbols, names, offs, idx) < 0) { 305 error(strerror(errno)); 306 goto err3; 307 } 308 309 if (getstat(fname, &prop) < 0) { 310 error(strerror(errno)); 311 goto err3; 312 } 313 prop.size = ftell(idx); 314 prop.time = time(NULL); 315 316 r = snprintf(tmpname, sizeof(tmpname), "%s.tmp", fname); 317 if (r >= sizeof(tmpname)) { 318 error("too long temporary name"); 319 goto err3; 320 } 321 322 if ((out = fopen(tmpname, "wb")) == NULL) { 323 error(strerror(errno)); 324 goto err3; 325 } 326 327 merge(out, &prop, fp, idx); 328 if (ferror(out) || ferror(fp) || ferror(idx)) { 329 error(strerror(errno)); 330 fclose(out); 331 goto err4; 332 } 333 334 fclose(out); 335 if (rename(tmpname, fname) == EOF) { 336 error(strerror(errno)); 337 goto err4; 338 } 339 340 err4: 341 remove(tmpname); 342 err3: 343 free(offs); 344 free(names); 345 fclose(idx); 346 err2: 347 freehash(); 348 err1: 349 fclose(fp); 350 } 351 352 static void 353 usage(void) 354 { 355 fputs("usage: ranlib [-t] file...\n", stderr); 356 exit(EXIT_FAILURE); 357 } 358 359 int 360 main(int argc, char *argv[]) 361 { 362 ARGBEGIN { 363 case 't': 364 break; 365 default: 366 usage(); 367 } ARGEND 368 369 if (argc == 0) 370 usage(); 371 372 for (; *argv; ++argv) 373 ranlib(*argv); 374 375 return status; 376 }