xref: /csrg-svn/usr.bin/ranlib/ranlib.c (revision 30827)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)ranlib.c	5.4 (Berkeley) 04/06/87";
15 #endif not lint
16 
17 /*
18  * ranlib - create table of contents for archive; string table version
19  */
20 #include <sys/types.h>
21 #include <ar.h>
22 #include <ranlib.h>
23 #include <a.out.h>
24 #include <stdio.h>
25 
26 struct	ar_hdr	archdr;
27 #define	OARMAG 0177545
28 long	arsize;
29 struct	exec	exp;
30 FILE	*fi, *fo;
31 long	off, oldoff;
32 long	atol(), ftell();
33 #define TABSZ	3000
34 int	tnum;
35 #define	STRTABSZ	30000
36 int	tssiz;
37 char	*strtab;
38 int	ssiz;
39 int	new;
40 char	tempnm[] = RANLIBMAG;
41 char	firstname[17];
42 void	stash();
43 char *malloc(), *calloc();
44 
45 /*
46  * table segment definitions
47  */
48 char	*segalloc();
49 void	segclean();
50 struct	tabsegment {
51 	struct tabsegment	*pnext;
52 	unsigned		nelem;
53 	struct ranlib		tab[TABSZ];
54 } tabbase, *ptabseg;
55 struct	strsegment {
56 	struct strsegment	*pnext;
57 	unsigned		nelem;
58 	char			stab[STRTABSZ];
59 } strbase, *pstrseg;
60 
61 main(argc, argv)
62 char **argv;
63 {
64 	char cmdbuf[BUFSIZ];
65 	/* magbuf must be an int array so it is aligned on an int-ish
66 	   boundary, so that we may access its first word as an int! */
67 	int magbuf[(SARMAG+sizeof(int))/sizeof(int)];
68 	register int just_touch = 0;
69 	register struct tabsegment *ptab;
70 	register struct strsegment *pstr;
71 
72 	/* check for the "-t" flag" */
73 	if (argc > 1 && strcmp(argv[1], "-t") == 0) {
74 		just_touch++;
75 		argc--;
76 		argv++;
77 	}
78 
79 	--argc;
80 	while(argc--) {
81 		fi = fopen(*++argv,"r");
82 		if (fi == NULL) {
83 			fprintf(stderr, "ranlib: cannot open %s\n", *argv);
84 			continue;
85 		}
86 		off = SARMAG;
87 		fread((char *)magbuf, 1, SARMAG, fi);
88 		if (strncmp((char *)magbuf, ARMAG, SARMAG)) {
89 			if (magbuf[0] == OARMAG)
90 				fprintf(stderr, "old format ");
91 			else
92 				fprintf(stderr, "not an ");
93 			fprintf(stderr, "archive: %s\n", *argv);
94 			continue;
95 		}
96 		if (just_touch) {
97 			register int	len;
98 
99 			fseek(fi, (long) SARMAG, 0);
100 			if (fread(cmdbuf, sizeof archdr.ar_name, 1, fi) != 1) {
101 				fprintf(stderr, "malformed archive: %s\n",
102 					*argv);
103 				continue;
104 			}
105 			len = strlen(tempnm);
106 			if (bcmp(cmdbuf, tempnm, len) != 0 ||
107 			    cmdbuf[len] != ' ') {
108 				fprintf(stderr, "no symbol table: %s\n", *argv);
109 				continue;
110 			}
111 			fclose(fi);
112 			fixdate(*argv);
113 			continue;
114 		}
115 		fseek(fi, 0L, 0);
116 		new = tssiz = tnum = 0;
117 		segclean();
118 		if (nextel(fi) == 0) {
119 			fclose(fi);
120 			continue;
121 		}
122 		do {
123 			long o;
124 			register n;
125 			struct nlist sym;
126 
127 			fread((char *)&exp, 1, sizeof(struct exec), fi);
128 			if (N_BADMAG(exp))
129 				continue;
130 			if (!strncmp(tempnm, archdr.ar_name, sizeof(archdr.ar_name)))
131 				continue;
132 			if (exp.a_syms == 0) {
133 				fprintf(stderr, "ranlib: warning: %s(%s): no symbol table\n", *argv, archdr.ar_name);
134 				continue;
135 			}
136 			o = N_STROFF(exp) - sizeof (struct exec);
137 			if (ftell(fi)+o+sizeof(ssiz) >= off) {
138 				fprintf(stderr, "ranlib: warning: %s(%s): old format .o file\n", *argv, archdr.ar_name);
139 				continue;
140 			}
141 			fseek(fi, o, 1);
142 			fread((char *)&ssiz, 1, sizeof (ssiz), fi);
143 			if (ssiz < sizeof ssiz){
144 				/* sanity check */
145 				fprintf(stderr, "ranlib: warning: %s(%s): mangled string table\n", *argv, archdr.ar_name);
146 				continue;
147 			}
148 			strtab = (char *)calloc(1, ssiz);
149 			if (strtab == 0) {
150 				fprintf(stderr, "ranlib: ran out of memory\n");
151 				exit(1);
152 			}
153 			fread(strtab+sizeof(ssiz), ssiz - sizeof(ssiz), 1, fi);
154 			fseek(fi, -(exp.a_syms+ssiz), 1);
155 			n = exp.a_syms / sizeof(struct nlist);
156 			while (--n >= 0) {
157 				fread((char *)&sym, 1, sizeof(sym), fi);
158 				if (sym.n_un.n_strx == 0)
159 					continue;
160 				sym.n_un.n_name = strtab + sym.n_un.n_strx;
161 				if ((sym.n_type&N_EXT)==0)
162 					continue;
163 				switch (sym.n_type&N_TYPE) {
164 
165 				case N_UNDF:
166 					if (sym.n_value!=0)
167 						stash(&sym);
168 					continue;
169 
170 				default:
171 					stash(&sym);
172 					continue;
173 				}
174 			}
175 			free(strtab);
176 		} while(nextel(fi));
177 		new = fixsize();
178 		fclose(fi);
179 		fo = fopen(tempnm, "w");
180 		if(fo == NULL) {
181 			fprintf(stderr, "can't create temporary\n");
182 			exit(1);
183 		}
184 		tnum *= sizeof (struct ranlib);
185 		fwrite(&tnum, 1, sizeof (tnum), fo);
186 		tnum /= sizeof (struct ranlib);
187 		ptab = &tabbase;
188 		do {
189 			fwrite((char *)ptab->tab, ptab->nelem,
190 			    sizeof(struct ranlib), fo);
191 		} while (ptab = ptab->pnext);
192 		fwrite(&tssiz, 1, sizeof (tssiz), fo);
193 		pstr = &strbase;
194 		do {
195 			fwrite(pstr->stab, pstr->nelem, 1, fo);
196 			tssiz -= pstr->nelem;
197 		} while (pstr = pstr->pnext);
198 		/* pad with nulls */
199 		while (tssiz--) putc('\0', fo);
200 		fclose(fo);
201 		if(new)
202 			sprintf(cmdbuf, "ar rlb %s %s %s\n", firstname, *argv, tempnm);
203 		else
204 			sprintf(cmdbuf, "ar rl %s %s\n", *argv, tempnm);
205 		if(system(cmdbuf))
206 			fprintf(stderr, "ranlib: ``%s'' failed\n", cmdbuf);
207 		else
208 			fixdate(*argv);
209 		unlink(tempnm);
210 	}
211 	exit(0);
212 }
213 
214 nextel(af)
215 FILE *af;
216 {
217 	register r;
218 	register char *cp;
219 
220 	oldoff = off;
221 	fseek(af, off, 0);
222 	r = fread((char *)&archdr, 1, sizeof(struct ar_hdr), af);
223 	if (r != sizeof(struct ar_hdr))
224 		return(0);
225 	for (cp=archdr.ar_name; cp < & archdr.ar_name[sizeof(archdr.ar_name)]; cp++)
226 		if (*cp == ' ')
227 			*cp = '\0';
228 	arsize = atol(archdr.ar_size);
229 	if (arsize & 1)
230 		arsize++;
231 	off = ftell(af) + arsize;
232 	return(1);
233 }
234 
235 void
236 stash(s)
237 	struct nlist *s;
238 {
239 	register char *cp;
240 	register char *strtab;
241 	register strsiz;
242 	register struct ranlib *tab;
243 	register tabsiz;
244 
245 	if (ptabseg->nelem >= TABSZ) {
246 		/* allocate a new symbol table segment */
247 		ptabseg = ptabseg->pnext =
248 		    (struct tabsegment *) segalloc(sizeof(struct tabsegment));
249 		ptabseg->pnext = NULL;
250 		ptabseg->nelem = 0;
251 	}
252 	tabsiz = ptabseg->nelem;
253 	tab = ptabseg->tab;
254 
255 	if (pstrseg->nelem >= STRTABSZ) {
256 		/* allocate a new string table segment */
257 		pstrseg = pstrseg->pnext =
258 		    (struct strsegment *) segalloc(sizeof(struct strsegment));
259 		pstrseg->pnext = NULL;
260 		pstrseg->nelem = 0;
261 	}
262 	strsiz = pstrseg->nelem;
263 	strtab = pstrseg->stab;
264 
265 	tab[tabsiz].ran_un.ran_strx = tssiz;
266 	tab[tabsiz].ran_off = oldoff;
267 redo:
268 	for (cp = s->n_un.n_name; strtab[strsiz++] = *cp++;)
269 		if (strsiz >= STRTABSZ) {
270 			/* allocate a new string table segment */
271 			pstrseg = pstrseg->pnext =
272 			    (struct strsegment *) segalloc(sizeof(struct strsegment));
273 			pstrseg->pnext = NULL;
274 			strsiz = pstrseg->nelem = 0;
275 			strtab = pstrseg->stab;
276 			goto redo;
277 		}
278 
279 	tssiz += strsiz - pstrseg->nelem; /* length of the string */
280 	pstrseg->nelem = strsiz;
281 	tnum++;
282 	ptabseg->nelem++;
283 }
284 
285 /* allocate a zero filled segment of size bytes */
286 char *
287 segalloc(size)
288 unsigned size;
289 {
290 	char *pseg = NULL;
291 
292 	pseg = malloc(size);
293 	if (pseg == NULL) {
294 		fprintf(stderr, "ranlib: ran out of memeory\n");
295 		exit(1);
296 	}
297 	return(pseg);
298 }
299 
300 /* free segments */
301 void
302 segclean()
303 {
304 	register struct tabsegment *ptab;
305 	register struct strsegment *pstr;
306 
307 	/*
308 	 * symbol table
309 	 *
310 	 * The first entry is static.
311 	 */
312 	ptabseg = &tabbase;
313 	ptab = ptabseg->pnext;
314 	while (ptabseg = ptab) {
315 		ptab = ptabseg->pnext;
316 		free((char *)ptabseg);
317 	}
318 	ptabseg = &tabbase;
319 	ptabseg->pnext = NULL;
320 	ptabseg->nelem = 0;
321 
322 	/*
323 	 * string table
324 	 *
325 	 * The first entry is static.
326 	 */
327 	pstrseg = &strbase;
328 	pstr = pstrseg->pnext;
329 	while (pstrseg = pstr) {
330 		pstr = pstrseg->pnext;
331 		free((char *)pstrseg);
332 	}
333 	pstrseg = &strbase;
334 	pstrseg->pnext = NULL;
335 	pstrseg->nelem = 0;
336 }
337 
338 fixsize()
339 {
340 	int i;
341 	off_t offdelta;
342 	register struct tabsegment *ptab;
343 
344 	if (tssiz&1)
345 		tssiz++;
346 	offdelta = sizeof(archdr) + sizeof (tnum) + tnum * sizeof(struct ranlib) +
347 	    sizeof (tssiz) + tssiz;
348 	off = SARMAG;
349 	nextel(fi);
350 	if(strncmp(archdr.ar_name, tempnm, sizeof (archdr.ar_name)) == 0) {
351 		new = 0;
352 		offdelta -= sizeof(archdr) + arsize;
353 	} else {
354 		new = 1;
355 		strncpy(firstname, archdr.ar_name, sizeof(archdr.ar_name));
356 	}
357 	ptab = &tabbase;
358 	do {
359 		for (i = 0; i < ptab->nelem; i++)
360 			ptab->tab[i].ran_off += offdelta;
361 	} while (ptab = ptab->pnext);
362 	return(new);
363 }
364 
365 /* patch time */
366 fixdate(s)
367 	char *s;
368 {
369 	long time();
370 	char buf[24];
371 	int fd;
372 
373 	fd = open(s, 1);
374 	if(fd < 0) {
375 		fprintf(stderr, "ranlib: can't reopen %s\n", s);
376 		return;
377 	}
378 	sprintf(buf, "%-*ld", sizeof(archdr.ar_date), time((long *)NULL)+5);
379 	lseek(fd, (long)SARMAG + ((char *)archdr.ar_date-(char *)&archdr), 0);
380 	write(fd, buf, sizeof(archdr.ar_date));
381 	close(fd);
382 }
383