scc-ranlib.c (6276B)
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 char *argv0; 32 33 static void 34 error(char *fmt, ...) 35 { 36 va_list va; 37 38 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); 45 46 status = EXIT_FAILURE; 47 } 48 49 Symdef * 50 lookup(char *name) 51 { 52 unsigned h; 53 Symdef *dp; 54 char *s; 55 size_t len; 56 57 h = genhash(name) % NR_SYMDEF; 58 59 for (dp = htab[h]; dp; dp = dp->next) { 60 if (!strcmp(dp->name, name)) 61 return dp; 62 } 63 64 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 } 72 73 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; 82 83 return dp; 84 } 85 86 static int 87 newsymbol(Symbol *sym, long off) 88 { 89 Symdef *np; 90 91 if (!isupper(sym->type) || sym->type == 'N' || sym->type == 'U') 92 return 1; 93 94 if ((np = lookup(sym->name)) == NULL) { 95 error(strerror(errno)); 96 return 0; 97 } 98 99 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 } 113 114 return 1; 115 } 116 117 static void 118 freehash(void) 119 { 120 Symdef **npp, *next, *np; 121 122 for (npp = htab; npp < &htab[NR_SYMDEF]; npp++) 123 *npp = NULL; 124 125 for (np = head; np; np = next) { 126 next = np->next; 127 free(np->name); 128 free(np); 129 } 130 131 head = NULL; 132 } 133 134 static int 135 newmember(FILE *fp, long off) 136 { 137 int i,t, ret = 0; 138 Obj *obj; 139 Symbol sym; 140 141 t = objprobe(fp, NULL); 142 if (t == -1 || artype != -1 && artype != t) { 143 nolib = 1; 144 return 0; 145 } 146 artype = t; 147 148 if ((obj = newobj(t)) == NULL) { 149 error(strerror(errno)); 150 return 0; 151 } 152 namidx = obj->index; 153 154 if (readobj(obj, fp) < 0) { 155 error(strerror(errno)); 156 goto error; 157 } 158 159 for (i = 0; getsym(obj, &i, &sym); i++) { 160 if (!newsymbol(&sym, off)) 161 goto error; 162 } 163 164 ret = 1; 165 166 error: 167 delobj(obj); 168 return ret; 169 } 170 171 static int 172 readsyms(FILE *fp) 173 { 174 long idxsiz, cur, off; 175 char memb[SARNAM+1]; 176 177 nolib = 0; 178 artype = -1; 179 nsymbols = 0; 180 idxsiz = 0; 181 182 if (!archive(fp)) { 183 error("file format not recognized"); 184 return 0; 185 } 186 187 cur = ftell(fp); 188 if ((off = armember(fp, memb, NULL)) < 0) 189 goto corrupted; 190 191 if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) { 192 idxsiz = off; 193 cur += off; 194 } 195 196 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 } 215 216 corrupted: 217 error(strerror(errno)); 218 error("library corrupted"); 219 return 0; 220 } 221 222 static void 223 merge(FILE *to, struct fprop *prop, FILE *lib, FILE *idx) 224 { 225 int c; 226 struct ar_hdr first; 227 228 rewind(lib); 229 rewind(idx); 230 fseek(lib, SARMAG, SEEK_SET); 231 232 if (fread(&first, sizeof(first), 1, lib) != 1) 233 return; 234 235 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 } 241 242 fwrite(ARMAG, SARMAG, 1, to); 243 244 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); 252 253 while ((c = getc(idx)) != EOF) 254 putc(c, to); 255 if (prop->size & 1) 256 putc('\n', to); 257 258 while ((c = getc(lib)) != EOF) 259 putc(c, to); 260 261 fflush(to); 262 } 263 264 static void 265 ranlib(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]; 274 275 filename = fname; 276 if ((fp = fopen(fname, "rb")) == NULL) { 277 error(strerror(errno)); 278 return; 279 } 280 281 if (readsyms(fp) <0) 282 goto err2; 283 284 if ((idx = tmpfile()) == NULL) { 285 error(strerror(errno)); 286 goto err2; 287 } 288 289 offs = malloc(sizeof(long) * nsymbols); 290 names = malloc(sizeof(*names) * nsymbols); 291 if (!offs || !names) { 292 error(strerror(errno)); 293 goto err3; 294 } 295 296 for (dp = head, i = 0; i < nsymbols; dp = dp->next, i++) { 297 offs[i] = dp->offset; 298 names[i] = dp->name; 299 } 300 301 /* 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 } 306 307 if (getstat(fname, &prop) < 0) { 308 error(strerror(errno)); 309 goto err3; 310 } 311 prop.time = time(NULL); 312 prop.size = ftell(idx); 313 314 size = sizeof(struct ar_hdr) + prop.size + (prop.size & 1); 315 for (i = 0; i < nsymbols; i++) 316 offs[i] += size; 317 318 /* 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 } 324 325 r = snprintf(tmpname, sizeof(tmpname), "%s.tmp", fname); 326 if (r >= sizeof(tmpname)) { 327 error("too long temporary name"); 328 goto err3; 329 } 330 331 if ((out = fopen(tmpname, "wb")) == NULL) { 332 error(strerror(errno)); 333 goto err3; 334 } 335 336 merge(out, &prop, fp, idx); 337 if (ferror(out) || ferror(fp) || ferror(idx)) { 338 error(strerror(errno)); 339 fclose(out); 340 goto err4; 341 } 342 343 fclose(out); 344 if (rename(tmpname, fname) == EOF) { 345 error(strerror(errno)); 346 goto err4; 347 } 348 349 err4: 350 remove(tmpname); 351 err3: 352 free(offs); 353 free(names); 354 fclose(idx); 355 err2: 356 freehash(); 357 err1: 358 fclose(fp); 359 } 360 361 static void 362 usage(void) 363 { 364 fputs("usage: scc-ranlib [-t] file...\n", stderr); 365 exit(EXIT_FAILURE); 366 } 367 368 int 369 main(int argc, char *argv[]) 370 { 371 ARGBEGIN { 372 case 't': 373 break; 374 default: 375 usage(); 376 } ARGEND 377 378 if (argc == 0) 379 usage(); 380 381 for (; *argv; ++argv) 382 ranlib(*argv); 383 384 return status; 385 }