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