xref: /plan9/sys/src/cmd/ar.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * ar - portable (ascii) format version
33e12c5d1SDavid du Colombier  */
43e12c5d1SDavid du Colombier #include <u.h>
53e12c5d1SDavid du Colombier #include <libc.h>
63e12c5d1SDavid du Colombier #include <bio.h>
7*219b2ee8SDavid du Colombier #include <mach.h>
83e12c5d1SDavid du Colombier #include <ar.h>
93e12c5d1SDavid du Colombier 
10bd389b36SDavid du Colombier /*
11bd389b36SDavid du Colombier  *	The algorithm uses up to 3 temp files.  The "pivot member" is the
12*219b2ee8SDavid du Colombier  *	archive member specified by and a, b, or i option.  The temp files are
13*219b2ee8SDavid du Colombier  *	astart - contains existing members up to and including the pivot member.
14*219b2ee8SDavid du Colombier  *	amiddle - contains new files moved or inserted behind the pivot.
15*219b2ee8SDavid du Colombier  *	aend - contains the existing members that follow the pivot member.
16*219b2ee8SDavid du Colombier  *	When all members have been processed, function 'install' streams the
17*219b2ee8SDavid du Colombier  * 	temp files, in order, back into the archive.
18bd389b36SDavid du Colombier  */
19bd389b36SDavid du Colombier 
20*219b2ee8SDavid du Colombier typedef struct	Arsymref
21*219b2ee8SDavid du Colombier {
22*219b2ee8SDavid du Colombier 	char	*name;
23*219b2ee8SDavid du Colombier 	int	type;
24*219b2ee8SDavid du Colombier 	int	len;
25*219b2ee8SDavid du Colombier 	long	offset;
26*219b2ee8SDavid du Colombier 	struct	Arsymref *next;
27*219b2ee8SDavid du Colombier } Arsymref;
28*219b2ee8SDavid du Colombier 
29bd389b36SDavid du Colombier typedef struct	Armember	/* Temp file entry - one per archive member */
303e12c5d1SDavid du Colombier {
31bd389b36SDavid du Colombier 	struct Armember	*next;
32bd389b36SDavid du Colombier 	struct ar_hdr	hdr;
33bd389b36SDavid du Colombier 	long		size;
34bd389b36SDavid du Colombier 	long		date;
35bd389b36SDavid du Colombier 	void		*member;
36bd389b36SDavid du Colombier } Armember;
373e12c5d1SDavid du Colombier 
38bd389b36SDavid du Colombier typedef	struct Arfile		/* Temp file control block - one per tempfile */
39bd389b36SDavid du Colombier {
40bd389b36SDavid du Colombier 	int	paged;		/* set when some data paged to disk */
41bd389b36SDavid du Colombier 	char	*fname;		/* paging file name */
42bd389b36SDavid du Colombier 	int	fd;		/* paging file descriptor */
43*219b2ee8SDavid du Colombier 	long	size;
44bd389b36SDavid du Colombier 	Armember *head;		/* head of member chain */
45bd389b36SDavid du Colombier 	Armember *tail;		/* tail of member chain */
46*219b2ee8SDavid du Colombier 	Arsymref *sym;		/* head of defined symbol chain */
47bd389b36SDavid du Colombier } Arfile;
48*219b2ee8SDavid du Colombier 
49*219b2ee8SDavid du Colombier /*
50*219b2ee8SDavid du Colombier  *	macro to portably read/write archive header.
51*219b2ee8SDavid du Colombier  *	'cmd' is read/write/Bread/Bwrite, etc.
52*219b2ee8SDavid du Colombier  */
53*219b2ee8SDavid du Colombier #define	HEADER_IO(cmd, f, h)	cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
54*219b2ee8SDavid du Colombier 				|| cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
55*219b2ee8SDavid du Colombier 				|| cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
56*219b2ee8SDavid du Colombier 				|| cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
57*219b2ee8SDavid du Colombier 				|| cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
58*219b2ee8SDavid du Colombier 				|| cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
59*219b2ee8SDavid du Colombier 				|| cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
60*219b2ee8SDavid du Colombier 
61bd389b36SDavid du Colombier 		/* constants and flags */
62bd389b36SDavid du Colombier char	*man =		"mrxtdpq";
63bd389b36SDavid du Colombier char	*opt =		"uvnbailo";
64bd389b36SDavid du Colombier char	artemp[] =	"/tmp/vXXXXX";
65bd389b36SDavid du Colombier char	movtemp[] =	"/tmp/v1XXXXX";
66bd389b36SDavid du Colombier char	tailtemp[] =	"/tmp/v2XXXXX";
67*219b2ee8SDavid du Colombier char	symdef[] =	"__.SYMDEF";
683e12c5d1SDavid du Colombier 
69bd389b36SDavid du Colombier int	aflag;				/* command line flags */
70bd389b36SDavid du Colombier int	bflag;
71bd389b36SDavid du Colombier int	cflag;
72bd389b36SDavid du Colombier int	oflag;
73bd389b36SDavid du Colombier int	uflag;
74bd389b36SDavid du Colombier int	vflag;
753e12c5d1SDavid du Colombier 
76bd389b36SDavid du Colombier Arfile *astart, *amiddle, *aend;	/* Temp file control block pointers */
77*219b2ee8SDavid du Colombier int	allobj = 1;			/* set when all members are object files of the same type */
78*219b2ee8SDavid du Colombier int	symdefsize;			/* size of symdef file */
79bd389b36SDavid du Colombier 
80bd389b36SDavid du Colombier #define	ARNAMESIZE	sizeof(astart->tail->hdr.name)
81bd389b36SDavid du Colombier 
82bd389b36SDavid du Colombier char	poname[ARNAMESIZE+1];		/* name of pivot member */
83bd389b36SDavid du Colombier char	*file;				/* current file or member being worked on */
843e12c5d1SDavid du Colombier Biobuf	bout;
85*219b2ee8SDavid du Colombier Biobuf bar;
863e12c5d1SDavid du Colombier 
87*219b2ee8SDavid du Colombier void	arcopy(Biobuf*, Arfile*, Armember*);
88bd389b36SDavid du Colombier int	arcreate(char*);
89bd389b36SDavid du Colombier void	arfree(Arfile*);
90bd389b36SDavid du Colombier void	arinsert(Arfile*, Armember*);
91bd389b36SDavid du Colombier char	*armalloc(int);
92*219b2ee8SDavid du Colombier void	armove(Biobuf*, Arfile*, Armember*);
93*219b2ee8SDavid du Colombier void	arread(Biobuf*, Armember*, int);
94bd389b36SDavid du Colombier void	arstream(int, Arfile*);
95bd389b36SDavid du Colombier int	arwrite(int, Armember*);
96bd389b36SDavid du Colombier int	bamatch(char*, char*);
97*219b2ee8SDavid du Colombier Armember *getdir(Biobuf*);
98bd389b36SDavid du Colombier int	getspace(void);
99bd389b36SDavid du Colombier void	install(char*, Arfile*, Arfile*, Arfile*);
100bd389b36SDavid du Colombier void	longt(Armember*);
101bd389b36SDavid du Colombier int	match(int, char**);
102bd389b36SDavid du Colombier void	mesg(int, char*);
103bd389b36SDavid du Colombier Arfile	*newtempfile(char*);
104bd389b36SDavid du Colombier Armember *newmember(void);
105*219b2ee8SDavid du Colombier void	objsym(Sym*, void*);
106bd389b36SDavid du Colombier int	openar(char*, int, int);
107bd389b36SDavid du Colombier int	page(Arfile*);
108bd389b36SDavid du Colombier void	pmode(long);
109*219b2ee8SDavid du Colombier void	rl(int);
110*219b2ee8SDavid du Colombier void	scanobj(Biobuf*, Arfile*, int);
111bd389b36SDavid du Colombier void	select(int*, long);
112bd389b36SDavid du Colombier void	setcom(void(*)(char*, int, char**));
113*219b2ee8SDavid du Colombier void	skip(Biobuf*, long);
114bd389b36SDavid du Colombier void	trim(char*, char*, int);
1153e12c5d1SDavid du Colombier void	usage(void);
1163e12c5d1SDavid du Colombier void	wrerr(void);
117*219b2ee8SDavid du Colombier void	wrsym(Biobuf*, int, Arsymref*);
1183e12c5d1SDavid du Colombier 
119bd389b36SDavid du Colombier void	rcmd(char*, int, char**);		/* command processing */
120bd389b36SDavid du Colombier void	dcmd(char*, int, char**);
121bd389b36SDavid du Colombier void	xcmd(char*, int, char**);
122bd389b36SDavid du Colombier void	tcmd(char*, int, char**);
123bd389b36SDavid du Colombier void	pcmd(char*, int, char**);
124bd389b36SDavid du Colombier void	mcmd(char*, int, char**);
125bd389b36SDavid du Colombier void	qcmd(char*, int, char**);
126bd389b36SDavid du Colombier void	(*comfun)(char*, int, char**);
127bd389b36SDavid du Colombier 
1283e12c5d1SDavid du Colombier void
1293e12c5d1SDavid du Colombier main(int argc, char *argv[])
1303e12c5d1SDavid du Colombier {
1313e12c5d1SDavid du Colombier 	char *cp;
1323e12c5d1SDavid du Colombier 
133*219b2ee8SDavid du Colombier 
1343e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
1353e12c5d1SDavid du Colombier 	if(argc < 3)
1363e12c5d1SDavid du Colombier 		usage();
137bd389b36SDavid du Colombier 	for (cp = argv[1]; *cp; cp++) {
1383e12c5d1SDavid du Colombier 		switch(*cp) {
139bd389b36SDavid du Colombier 		case 'a':	aflag = 1;	break;
140bd389b36SDavid du Colombier 		case 'b':	bflag = 1;	break;
141bd389b36SDavid du Colombier 		case 'c':	cflag = 1;	break;
142bd389b36SDavid du Colombier 		case 'd':	setcom(dcmd);	break;
143bd389b36SDavid du Colombier 		case 'i':	bflag = 1;	break;
1443e12c5d1SDavid du Colombier 		case 'l':
145bd389b36SDavid du Colombier 				strcpy(artemp, "vXXXXX");
146bd389b36SDavid du Colombier 				strcpy(movtemp, "v1XXXXX");
147bd389b36SDavid du Colombier 				strcpy(tailtemp, "v2XXXXX");
148bd389b36SDavid du Colombier 				break;
149bd389b36SDavid du Colombier 		case 'm':	setcom(mcmd);	break;
150bd389b36SDavid du Colombier 		case 'o':	oflag = 1;	break;
151bd389b36SDavid du Colombier 		case 'p':	setcom(pcmd);	break;
152bd389b36SDavid du Colombier 		case 'q':	setcom(qcmd);	break;
153bd389b36SDavid du Colombier 		case 'r':	setcom(rcmd);	break;
154bd389b36SDavid du Colombier 		case 't':	setcom(tcmd);	break;
155bd389b36SDavid du Colombier 		case 'u':	uflag = 1;	break;
156bd389b36SDavid du Colombier 		case 'v':	vflag = 1;	break;
157bd389b36SDavid du Colombier 		case 'x':	setcom(xcmd);	break;
1583e12c5d1SDavid du Colombier 		default:
1593e12c5d1SDavid du Colombier 			fprint(2, "ar: bad option `%c'\n", *cp);
160bd389b36SDavid du Colombier 			exits("error");
1613e12c5d1SDavid du Colombier 		}
1623e12c5d1SDavid du Colombier 	}
163bd389b36SDavid du Colombier 	if (aflag && bflag) {
164bd389b36SDavid du Colombier 		fprint(2, "ar: only one of 'a' and 'b' can be specified\n");
165bd389b36SDavid du Colombier 		usage();
166bd389b36SDavid du Colombier 	}
167bd389b36SDavid du Colombier 	if(aflag || bflag) {
168bd389b36SDavid du Colombier 		trim(argv[2], poname, sizeof(poname));
1693e12c5d1SDavid du Colombier 		argv++;
1703e12c5d1SDavid du Colombier 		argc--;
1713e12c5d1SDavid du Colombier 		if(argc < 3)
1723e12c5d1SDavid du Colombier 			usage();
1733e12c5d1SDavid du Colombier 	}
1743e12c5d1SDavid du Colombier 	if(comfun == 0) {
175bd389b36SDavid du Colombier 		if(uflag == 0) {
1763e12c5d1SDavid du Colombier 			fprint(2, "ar: one of [%s] must be specified\n", man);
177bd389b36SDavid du Colombier 			usage();
1783e12c5d1SDavid du Colombier 		}
1793e12c5d1SDavid du Colombier 		setcom(rcmd);
1803e12c5d1SDavid du Colombier 	}
181bd389b36SDavid du Colombier 	cp = argv[2];
182bd389b36SDavid du Colombier 	argc -= 3;
183bd389b36SDavid du Colombier 	argv += 3;
184bd389b36SDavid du Colombier 	(*comfun)(cp, argc, argv);	/* do the command */
185bd389b36SDavid du Colombier 	cp = 0;
186bd389b36SDavid du Colombier 	while (argc--) {
187bd389b36SDavid du Colombier 		if (*argv) {
188bd389b36SDavid du Colombier 			fprint(2, "ar: %s not found\n", *argv);
189bd389b36SDavid du Colombier 			cp = "error";
1903e12c5d1SDavid du Colombier 		}
191bd389b36SDavid du Colombier 		argv++;
192bd389b36SDavid du Colombier 	}
193bd389b36SDavid du Colombier 	exits(cp);
194bd389b36SDavid du Colombier }
195bd389b36SDavid du Colombier /*
196bd389b36SDavid du Colombier  *	select a command
197bd389b36SDavid du Colombier  */
1983e12c5d1SDavid du Colombier void
199bd389b36SDavid du Colombier setcom(void (*fun)(char *, int, char**))
2003e12c5d1SDavid du Colombier {
2013e12c5d1SDavid du Colombier 
2023e12c5d1SDavid du Colombier 	if(comfun != 0) {
2033e12c5d1SDavid du Colombier 		fprint(2, "ar: only one of [%s] allowed\n", man);
204bd389b36SDavid du Colombier 		usage();
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier 	comfun = fun;
2073e12c5d1SDavid du Colombier }
208bd389b36SDavid du Colombier /*
209bd389b36SDavid du Colombier  *	perform the 'r' and 'u' commands
210bd389b36SDavid du Colombier  */
2113e12c5d1SDavid du Colombier void
212bd389b36SDavid du Colombier rcmd(char *arname, int count, char **files)
2133e12c5d1SDavid du Colombier {
214*219b2ee8SDavid du Colombier 	int fd;
215*219b2ee8SDavid du Colombier 	int i, ret;
216bd389b36SDavid du Colombier 	Arfile *ap;
217bd389b36SDavid du Colombier 	Armember *bp;
218bd389b36SDavid du Colombier 	Dir d;
219*219b2ee8SDavid du Colombier 	Biobuf *bfile;
2203e12c5d1SDavid du Colombier 
221bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 1);
222*219b2ee8SDavid du Colombier 	if (fd >= 0) {
223*219b2ee8SDavid du Colombier 		Binit(&bar, fd, OREAD);
224*219b2ee8SDavid du Colombier 		Bseek(&bar,seek(fd,0,1), 1);
225*219b2ee8SDavid du Colombier 	}
226bd389b36SDavid du Colombier 	astart = newtempfile(artemp);
227bd389b36SDavid du Colombier 	ap = astart;
228bd389b36SDavid du Colombier 	aend = 0;
229*219b2ee8SDavid du Colombier 	for(i = 0; fd >= 0; i++) {
230*219b2ee8SDavid du Colombier 		bp = getdir(&bar);
231bd389b36SDavid du Colombier 		if (!bp)
232bd389b36SDavid du Colombier 			break;
233bd389b36SDavid du Colombier 		if (bamatch(file, poname)) {		/* check for pivot */
234bd389b36SDavid du Colombier 			aend = newtempfile(tailtemp);
235bd389b36SDavid du Colombier 			ap = aend;
236bd389b36SDavid du Colombier 		}
237*219b2ee8SDavid du Colombier 			/* pitch symdef file */
238*219b2ee8SDavid du Colombier 		if (i == 0 && strcmp(file, symdef) == 0) {
239*219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
240*219b2ee8SDavid du Colombier 			continue;
241*219b2ee8SDavid du Colombier 		}
242*219b2ee8SDavid du Colombier 		if (count && !match(count, files)) {
243*219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
244*219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
245*219b2ee8SDavid du Colombier 			continue;
246*219b2ee8SDavid du Colombier 		}
247*219b2ee8SDavid du Colombier 		bfile = Bopen(file, OREAD);
248*219b2ee8SDavid du Colombier 		if (!bfile) {
249bd389b36SDavid du Colombier 			if (count != 0)
2503e12c5d1SDavid du Colombier 				fprint(2, "ar: cannot open %s\n", file);
251*219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
252*219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
253*219b2ee8SDavid du Colombier 			continue;
254*219b2ee8SDavid du Colombier 		}
255*219b2ee8SDavid du Colombier 		ret = dirfstat(Bfildes(bfile), &d);
256*219b2ee8SDavid du Colombier 		if (ret < 0)
257bd389b36SDavid du Colombier 			fprint(2, "ar: cannot stat %s\n", file);
258*219b2ee8SDavid du Colombier 		if (uflag && (ret < 0 || d.mtime <= bp->date)) {
259*219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
260*219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
261*219b2ee8SDavid du Colombier 			Bterm(bfile);
262*219b2ee8SDavid du Colombier 			continue;
2633e12c5d1SDavid du Colombier 		}
264bd389b36SDavid du Colombier 		mesg('r', file);
265*219b2ee8SDavid du Colombier 		skip(&bar, bp->size);
266*219b2ee8SDavid du Colombier 		scanobj(bfile, ap, d.length);
267*219b2ee8SDavid du Colombier 		armove(bfile, ap, bp);
268*219b2ee8SDavid du Colombier 		Bterm(bfile);
2693e12c5d1SDavid du Colombier 	}
270bd389b36SDavid du Colombier 	if(fd < 0) {
271bd389b36SDavid du Colombier 		if(!cflag)
272bd389b36SDavid du Colombier 			fprint(2, "ar: creating %s\n", arname);
273bd389b36SDavid du Colombier 	} else
274bd389b36SDavid du Colombier 		close(fd);
275bd389b36SDavid du Colombier 		/* copy in remaining files named on command line */
276bd389b36SDavid du Colombier 	for (i = 0; i < count; i++) {
277bd389b36SDavid du Colombier 		file = files[i];
2783e12c5d1SDavid du Colombier 		if(file == 0)
2793e12c5d1SDavid du Colombier 			continue;
280bd389b36SDavid du Colombier 		files[i] = 0;
281*219b2ee8SDavid du Colombier 		bfile = Bopen(file, OREAD);
282*219b2ee8SDavid du Colombier 		if (!bfile)
2833e12c5d1SDavid du Colombier 			fprint(2, "ar: %s cannot open\n", file);
284bd389b36SDavid du Colombier 		else {
285bd389b36SDavid du Colombier 			mesg('a', file);
286*219b2ee8SDavid du Colombier 			i = dirfstat(Bfildes(bfile), &d);
287*219b2ee8SDavid du Colombier 			if (i < 0)
288*219b2ee8SDavid du Colombier 				fprint(2, "can't stat %s\n", file);
289*219b2ee8SDavid du Colombier 			else {
290*219b2ee8SDavid du Colombier 				scanobj(bfile, astart, d.length);
291*219b2ee8SDavid du Colombier 				armove(bfile, astart, newmember());
292*219b2ee8SDavid du Colombier 			}
293*219b2ee8SDavid du Colombier 			Bterm(bfile);
2943e12c5d1SDavid du Colombier 		}
2953e12c5d1SDavid du Colombier 	}
296bd389b36SDavid du Colombier 	install(arname, astart, 0, aend);
297bd389b36SDavid du Colombier }
298*219b2ee8SDavid du Colombier 
299bd389b36SDavid du Colombier void
300bd389b36SDavid du Colombier dcmd(char *arname, int count, char **files)
301bd389b36SDavid du Colombier {
302bd389b36SDavid du Colombier 	Armember *bp;
303*219b2ee8SDavid du Colombier 	int fd, i;
304bd389b36SDavid du Colombier 
305bd389b36SDavid du Colombier 
306bd389b36SDavid du Colombier 	if (!count)
307bd389b36SDavid du Colombier 		return;
308bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 0);
309*219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
310*219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
311bd389b36SDavid du Colombier 	astart = newtempfile(artemp);
312*219b2ee8SDavid du Colombier 	for (i = 0; bp = getdir(&bar); i++) {
313bd389b36SDavid du Colombier 		if(match(count, files)) {
314bd389b36SDavid du Colombier 			mesg('d', file);
315*219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
316*219b2ee8SDavid du Colombier 			if (strcmp(file, symdef) == 0)
317*219b2ee8SDavid du Colombier 				allobj = 0;
318*219b2ee8SDavid du Colombier 		} else if (i == 0 && strcmp(file, symdef) == 0)
319*219b2ee8SDavid du Colombier 				skip(&bar, bp->size);
320*219b2ee8SDavid du Colombier 		else {
321*219b2ee8SDavid du Colombier 			scanobj(&bar, astart, bp->size);
322*219b2ee8SDavid du Colombier 			arcopy(&bar, astart, bp);
323bd389b36SDavid du Colombier 		}
324*219b2ee8SDavid du Colombier 	}
325*219b2ee8SDavid du Colombier 	close(fd);
326bd389b36SDavid du Colombier 	install(arname, astart, 0, 0);
3273e12c5d1SDavid du Colombier }
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier void
330bd389b36SDavid du Colombier xcmd(char *arname, int count, char **files)
3313e12c5d1SDavid du Colombier {
332bd389b36SDavid du Colombier 	int fd, f, mode, i;
333bd389b36SDavid du Colombier 	Armember *bp;
334*219b2ee8SDavid du Colombier 	Dir dx;
3353e12c5d1SDavid du Colombier 
336bd389b36SDavid du Colombier 	fd = openar(arname, OREAD, 0);
337*219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
338*219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
339bd389b36SDavid du Colombier 	i = 0;
340*219b2ee8SDavid du Colombier 	while (bp = getdir(&bar)) {
341bd389b36SDavid du Colombier 		if(count == 0 || match(count, files)) {
342bd389b36SDavid du Colombier 			mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
343bd389b36SDavid du Colombier 			f = create(file, OWRITE, mode);
344bd389b36SDavid du Colombier 			if(f < 0) {
345bd389b36SDavid du Colombier 				fprint(2, "ar: %s cannot create\n", file);
346*219b2ee8SDavid du Colombier 				skip(&bar, bp->size);
347bd389b36SDavid du Colombier 			} else {
348bd389b36SDavid du Colombier 				mesg('x', file);
349*219b2ee8SDavid du Colombier 				arcopy(&bar, 0, bp);
350bd389b36SDavid du Colombier 				if (write(f, bp->member, bp->size) < 0)
3513e12c5d1SDavid du Colombier 					wrerr();
352bd389b36SDavid du Colombier 				if(oflag) {
353*219b2ee8SDavid du Colombier 					if(dirfstat(f, &dx) < 0)
354bd389b36SDavid du Colombier 						perror(file);
355bd389b36SDavid du Colombier 					else {
356*219b2ee8SDavid du Colombier 						dx.atime = bp->date;
357*219b2ee8SDavid du Colombier 						dx.mtime = bp->date;
358*219b2ee8SDavid du Colombier 						if(dirwstat(file, &dx) < 0)
359bd389b36SDavid du Colombier 							perror(file);
3603e12c5d1SDavid du Colombier 					}
361bd389b36SDavid du Colombier 				}
362bd389b36SDavid du Colombier 				free(bp->member);
363bd389b36SDavid du Colombier 				close(f);
364bd389b36SDavid du Colombier 			}
365bd389b36SDavid du Colombier 			free(bp);
366bd389b36SDavid du Colombier 			if (count && ++i >= count)
367bd389b36SDavid du Colombier 				break;
368bd389b36SDavid du Colombier 		} else {
369*219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
370bd389b36SDavid du Colombier 			free(bp);
371bd389b36SDavid du Colombier 		}
372bd389b36SDavid du Colombier 	}
373bd389b36SDavid du Colombier 	close(fd);
374bd389b36SDavid du Colombier }
375bd389b36SDavid du Colombier void
376bd389b36SDavid du Colombier pcmd(char *arname, int count, char **files)
377bd389b36SDavid du Colombier {
378bd389b36SDavid du Colombier 	int fd;
379bd389b36SDavid du Colombier 	Armember *bp;
3803e12c5d1SDavid du Colombier 
381bd389b36SDavid du Colombier 	fd = openar(arname, OREAD, 0);
382*219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
383*219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
384*219b2ee8SDavid du Colombier 	while(bp = getdir(&bar)) {
385bd389b36SDavid du Colombier 		if(count == 0 || match(count, files)) {
386bd389b36SDavid du Colombier 			if(vflag)
387bd389b36SDavid du Colombier 				print("\n<%s>\n\n", file);
388*219b2ee8SDavid du Colombier 			arcopy(&bar, 0, bp);
389bd389b36SDavid du Colombier 			if (write(1, bp->member, bp->size) < 0)
390bd389b36SDavid du Colombier 				wrerr();
391bd389b36SDavid du Colombier 		} else
392*219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
393bd389b36SDavid du Colombier 		free(bp);
394bd389b36SDavid du Colombier 	}
395bd389b36SDavid du Colombier 	close(fd);
396bd389b36SDavid du Colombier }
397bd389b36SDavid du Colombier void
398bd389b36SDavid du Colombier mcmd(char *arname, int count, char **files)
399bd389b36SDavid du Colombier {
400*219b2ee8SDavid du Colombier 	int fd, i;
401bd389b36SDavid du Colombier 	Arfile *ap;
402bd389b36SDavid du Colombier 	Armember *bp;
403bd389b36SDavid du Colombier 
404bd389b36SDavid du Colombier 	if (count == 0)
405bd389b36SDavid du Colombier 		return;
406bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 0);
407*219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
408*219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
409bd389b36SDavid du Colombier 	astart = newtempfile(artemp);
410bd389b36SDavid du Colombier 	amiddle = newtempfile(movtemp);
411bd389b36SDavid du Colombier 	aend = 0;
412bd389b36SDavid du Colombier 	ap = astart;
413*219b2ee8SDavid du Colombier 	for (i = 0; bp = getdir(&bar); i++) {
414bd389b36SDavid du Colombier 		if (bamatch(file, poname)) {
415bd389b36SDavid du Colombier 			aend = newtempfile(tailtemp);
416bd389b36SDavid du Colombier 			ap = aend;
417bd389b36SDavid du Colombier 		}
418bd389b36SDavid du Colombier 		if(match(count, files)) {
419bd389b36SDavid du Colombier 			mesg('m', file);
420*219b2ee8SDavid du Colombier 			scanobj(&bar, amiddle, bp->size);
421*219b2ee8SDavid du Colombier 			arcopy(&bar, amiddle, bp);
422bd389b36SDavid du Colombier 		} else
423*219b2ee8SDavid du Colombier 			/*
424*219b2ee8SDavid du Colombier 			 * pitch the symdef file if it is at the beginning
425*219b2ee8SDavid du Colombier 			 * of the archive and we aren't inserting in front
426*219b2ee8SDavid du Colombier 			 * of it (ap == astart).
427*219b2ee8SDavid du Colombier 			 */
428*219b2ee8SDavid du Colombier 		if (ap == astart && i == 0 && strcmp(file, symdef) == 0)
429*219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
430*219b2ee8SDavid du Colombier 		else {
431*219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
432*219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
433*219b2ee8SDavid du Colombier 		}
434bd389b36SDavid du Colombier 	}
435bd389b36SDavid du Colombier 	close(fd);
436bd389b36SDavid du Colombier 	if (poname[0] && aend == 0)
437bd389b36SDavid du Colombier 		fprint(2, "ar: %s not found - files moved to end.\n", poname);
438bd389b36SDavid du Colombier 	install(arname, astart, amiddle, aend);
439bd389b36SDavid du Colombier }
440bd389b36SDavid du Colombier void
441bd389b36SDavid du Colombier tcmd(char *arname, int count, char **files)
442bd389b36SDavid du Colombier {
443bd389b36SDavid du Colombier 	int fd;
444bd389b36SDavid du Colombier 	Armember *bp;
445bd389b36SDavid du Colombier 	char name[ARNAMESIZE+1];
446bd389b36SDavid du Colombier 
447bd389b36SDavid du Colombier 	fd = openar(arname, OREAD, 0);
448*219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
449*219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
450*219b2ee8SDavid du Colombier 	while(bp = getdir(&bar)) {
451bd389b36SDavid du Colombier 		if(count == 0 || match(count, files)) {
452bd389b36SDavid du Colombier 			if(vflag)
453bd389b36SDavid du Colombier 				longt(bp);
454*219b2ee8SDavid du Colombier 			trim(file, name, ARNAMESIZE);
455bd389b36SDavid du Colombier 			Bprint(&bout, "%s\n", name);
456bd389b36SDavid du Colombier 		}
457*219b2ee8SDavid du Colombier 		skip(&bar, bp->size);
458bd389b36SDavid du Colombier 		free(bp);
459bd389b36SDavid du Colombier 	}
460bd389b36SDavid du Colombier 	close(fd);
461bd389b36SDavid du Colombier }
462bd389b36SDavid du Colombier void
463bd389b36SDavid du Colombier qcmd(char *arname, int count, char **files)
464bd389b36SDavid du Colombier {
465*219b2ee8SDavid du Colombier 	int fd, i;
466bd389b36SDavid du Colombier 	Armember *bp;
467*219b2ee8SDavid du Colombier 	Biobuf *bfile;
468bd389b36SDavid du Colombier 
469bd389b36SDavid du Colombier 	if(aflag || bflag) {
470bd389b36SDavid du Colombier 		fprint(2, "ar: abi not allowed with q\n");
471bd389b36SDavid du Colombier 		exits("error");
472bd389b36SDavid du Colombier 	}
473bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 1);
474bd389b36SDavid du Colombier 	if (fd < 0) {
475bd389b36SDavid du Colombier 		if(!cflag)
476bd389b36SDavid du Colombier 			fprint(2, "ar: creating %s\n", arname);
477bd389b36SDavid du Colombier 		fd = arcreate(arname);
478bd389b36SDavid du Colombier 	}
479*219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
480*219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
481bd389b36SDavid du Colombier 	/* leave note group behind when writing archive; i.e. sidestep interrupts */
482bd389b36SDavid du Colombier 	rfork(RFNOTEG);
483*219b2ee8SDavid du Colombier 	Bseek(&bar, 0, 2);
484bd389b36SDavid du Colombier 	bp = newmember();
485bd389b36SDavid du Colombier 	for(i=0; i<count && files[i]; i++) {
486bd389b36SDavid du Colombier 		file = files[i];
487bd389b36SDavid du Colombier 		files[i] = 0;
488*219b2ee8SDavid du Colombier 		bfile = Bopen(file, OREAD);
489*219b2ee8SDavid du Colombier 		if(!bfile)
490bd389b36SDavid du Colombier 			fprint(2, "ar: %s cannot open\n", file);
491bd389b36SDavid du Colombier 		else {
492bd389b36SDavid du Colombier 			mesg('q', file);
493*219b2ee8SDavid du Colombier 			armove(bfile, 0, bp);
494bd389b36SDavid du Colombier 			if (!arwrite(fd, bp))
495bd389b36SDavid du Colombier 				wrerr();
496bd389b36SDavid du Colombier 			free(bp->member);
497bd389b36SDavid du Colombier 			bp->member = 0;
498*219b2ee8SDavid du Colombier 			Bterm(bfile);
499bd389b36SDavid du Colombier 		}
500bd389b36SDavid du Colombier 	}
501bd389b36SDavid du Colombier 	free(bp);
502bd389b36SDavid du Colombier 	close(fd);
503bd389b36SDavid du Colombier }
504*219b2ee8SDavid du Colombier 
505*219b2ee8SDavid du Colombier /*
506*219b2ee8SDavid du Colombier  *	extract the symbol references from an object file
507*219b2ee8SDavid du Colombier  */
508*219b2ee8SDavid du Colombier 
509*219b2ee8SDavid du Colombier void
510*219b2ee8SDavid du Colombier scanobj(Biobuf *b, Arfile *ap, int size)
511*219b2ee8SDavid du Colombier {
512*219b2ee8SDavid du Colombier 	int obj;
513*219b2ee8SDavid du Colombier 	long offset;
514*219b2ee8SDavid du Colombier 	static int lastobj = -1;
515*219b2ee8SDavid du Colombier 
516*219b2ee8SDavid du Colombier 	if (!allobj)			/* non-object file encountered */
517*219b2ee8SDavid du Colombier 		return;
518*219b2ee8SDavid du Colombier 	offset = BOFFSET(b);
519*219b2ee8SDavid du Colombier 	obj = objtype(b, 0);
520*219b2ee8SDavid du Colombier 	if (obj < 0) {			/* not an object file */
521*219b2ee8SDavid du Colombier 		allobj = 0;
522*219b2ee8SDavid du Colombier 		Bseek(b, offset, 0);
523*219b2ee8SDavid du Colombier 		return;
524*219b2ee8SDavid du Colombier 	}
525*219b2ee8SDavid du Colombier 	if (lastobj >= 0 && obj != lastobj) {
526*219b2ee8SDavid du Colombier 		fprint(2, "ar: inconsistent object file %s\n", file);
527*219b2ee8SDavid du Colombier 		allobj = 0;
528*219b2ee8SDavid du Colombier 		Bseek(b, offset, 0);
529*219b2ee8SDavid du Colombier 		return;
530*219b2ee8SDavid du Colombier 	}
531*219b2ee8SDavid du Colombier 	lastobj = obj;
532*219b2ee8SDavid du Colombier 	if (!readar(b, obj, offset+size, 0)) {
533*219b2ee8SDavid du Colombier 		fprint(2, "ar: invalid symbol reference in file %s\n", file);
534*219b2ee8SDavid du Colombier 		allobj = 0;
535*219b2ee8SDavid du Colombier 		Bseek(b, offset, 0);
536*219b2ee8SDavid du Colombier 		return;
537*219b2ee8SDavid du Colombier 	}
538*219b2ee8SDavid du Colombier 	Bseek(b, offset, 0);
539*219b2ee8SDavid du Colombier 	objtraverse(objsym, ap);
540*219b2ee8SDavid du Colombier }
541*219b2ee8SDavid du Colombier 
542*219b2ee8SDavid du Colombier /*
543*219b2ee8SDavid du Colombier  *	add text and data symbols to the symbol list
544*219b2ee8SDavid du Colombier  */
545*219b2ee8SDavid du Colombier void
546*219b2ee8SDavid du Colombier objsym(Sym *s, void *p)
547*219b2ee8SDavid du Colombier {
548*219b2ee8SDavid du Colombier 	int n;
549*219b2ee8SDavid du Colombier 	Arsymref *as;
550*219b2ee8SDavid du Colombier 	Arfile *ap;
551*219b2ee8SDavid du Colombier 
552*219b2ee8SDavid du Colombier 	if (s->type != 'T' &&  s->type != 'D')
553*219b2ee8SDavid du Colombier 		return;
554*219b2ee8SDavid du Colombier 	ap = (Arfile*)p;
555*219b2ee8SDavid du Colombier 	as = (Arsymref*)armalloc(sizeof(Arsymref));
556*219b2ee8SDavid du Colombier 	as->offset = ap->size;
557*219b2ee8SDavid du Colombier 	n = strlen(s->name);
558*219b2ee8SDavid du Colombier 	as->name = armalloc(n+1);
559*219b2ee8SDavid du Colombier 	strcpy(as->name, s->name);
560*219b2ee8SDavid du Colombier 	as->type = s->type;
561*219b2ee8SDavid du Colombier 	symdefsize += 4+(n+1)+1;
562*219b2ee8SDavid du Colombier 	as->len = n;
563*219b2ee8SDavid du Colombier 	as->next = ap->sym;
564*219b2ee8SDavid du Colombier 	ap->sym = as;
565*219b2ee8SDavid du Colombier }
566*219b2ee8SDavid du Colombier 
567bd389b36SDavid du Colombier /*
568bd389b36SDavid du Colombier  *	open an archive and validate its header
569bd389b36SDavid du Colombier  */
5703e12c5d1SDavid du Colombier int
571bd389b36SDavid du Colombier openar(char *arname, int mode, int errok)
5723e12c5d1SDavid du Colombier {
573bd389b36SDavid du Colombier 	int fd;
5743e12c5d1SDavid du Colombier 	char mbuf[SARMAG];
5753e12c5d1SDavid du Colombier 
576bd389b36SDavid du Colombier 	fd = open(arname, mode);
577bd389b36SDavid du Colombier 	if(fd >= 0){
578bd389b36SDavid du Colombier 		if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
579bd389b36SDavid du Colombier 			fprint(2, "ar: %s not in archive format\n", arname);
580bd389b36SDavid du Colombier 			exits("error");
5813e12c5d1SDavid du Colombier 		}
582bd389b36SDavid du Colombier 	}else if(!errok){
583bd389b36SDavid du Colombier 		fprint(2, "ar: cannot open %s: %r\n", arname);
584bd389b36SDavid du Colombier 		exits("error");
585bd389b36SDavid du Colombier 	}
586bd389b36SDavid du Colombier 	return fd;
587bd389b36SDavid du Colombier }
588bd389b36SDavid du Colombier /*
589bd389b36SDavid du Colombier  *	create an archive and set its header
590bd389b36SDavid du Colombier  */
591bd389b36SDavid du Colombier int
592bd389b36SDavid du Colombier arcreate(char *arname)
593bd389b36SDavid du Colombier {
594bd389b36SDavid du Colombier 	int fd;
595bd389b36SDavid du Colombier 
596bd389b36SDavid du Colombier 	fd = create(arname, OWRITE, 0664);
597bd389b36SDavid du Colombier 	if(fd < 0){
598bd389b36SDavid du Colombier 		fprint(2, "ar: cannot create %s: %r\n", arname);
599bd389b36SDavid du Colombier 		exits("error");
600bd389b36SDavid du Colombier 	}
601bd389b36SDavid du Colombier 	if(write(fd, ARMAG, SARMAG) != SARMAG)
602bd389b36SDavid du Colombier 		wrerr();
603bd389b36SDavid du Colombier 	return fd;
604bd389b36SDavid du Colombier }
605bd389b36SDavid du Colombier /*
606bd389b36SDavid du Colombier  *		error handling
607bd389b36SDavid du Colombier  */
608bd389b36SDavid du Colombier void
609bd389b36SDavid du Colombier wrerr(void)
610bd389b36SDavid du Colombier {
611bd389b36SDavid du Colombier 	perror("ar: write error");
612bd389b36SDavid du Colombier 	exits("error");
6133e12c5d1SDavid du Colombier }
6143e12c5d1SDavid du Colombier 
6153e12c5d1SDavid du Colombier void
616bd389b36SDavid du Colombier rderr(void)
6173e12c5d1SDavid du Colombier {
618bd389b36SDavid du Colombier 	perror("ar: read error");
619bd389b36SDavid du Colombier 	exits("error");
620bd389b36SDavid du Colombier }
6213e12c5d1SDavid du Colombier 
622bd389b36SDavid du Colombier void
623bd389b36SDavid du Colombier phaseerr(int offset)
624bd389b36SDavid du Colombier {
625bd389b36SDavid du Colombier 	fprint(2, "ar: phase error at offset %d\n", offset);
626bd389b36SDavid du Colombier 	exits("error");
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier 
6293e12c5d1SDavid du Colombier void
6303e12c5d1SDavid du Colombier usage(void)
6313e12c5d1SDavid du Colombier {
632bd389b36SDavid du Colombier 	fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man);
633bd389b36SDavid du Colombier 	exits("error");
6343e12c5d1SDavid du Colombier }
6353e12c5d1SDavid du Colombier /*
636bd389b36SDavid du Colombier  *	read the header for the next archive member
6373e12c5d1SDavid du Colombier  */
638bd389b36SDavid du Colombier Armember *
639*219b2ee8SDavid du Colombier getdir(Biobuf *b)
6403e12c5d1SDavid du Colombier {
641bd389b36SDavid du Colombier 	Armember *bp;
6423e12c5d1SDavid du Colombier 	char *cp;
643bd389b36SDavid du Colombier 	static char name[ARNAMESIZE+1];
6443e12c5d1SDavid du Colombier 
645bd389b36SDavid du Colombier 	bp = newmember();
646*219b2ee8SDavid du Colombier 	if(HEADER_IO(Bread, b, bp->hdr)) {
647bd389b36SDavid du Colombier 		free(bp);
648bd389b36SDavid du Colombier 		return 0;
6493e12c5d1SDavid du Colombier 	}
650bd389b36SDavid du Colombier 	if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
651*219b2ee8SDavid du Colombier 		phaseerr(BOFFSET(b));
652bd389b36SDavid du Colombier 	strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
653bd389b36SDavid du Colombier 	cp = name+sizeof(name)-1;
6543e12c5d1SDavid du Colombier 	while(*--cp==' ')
6553e12c5d1SDavid du Colombier 		;
6563e12c5d1SDavid du Colombier 	cp[1] = '\0';
6573e12c5d1SDavid du Colombier 	file = name;
658bd389b36SDavid du Colombier 	bp->date = atol(bp->hdr.date);
659bd389b36SDavid du Colombier 	bp->size = atol(bp->hdr.size);
660bd389b36SDavid du Colombier 	return bp;
6613e12c5d1SDavid du Colombier }
662bd389b36SDavid du Colombier /*
663bd389b36SDavid du Colombier  *	Copy the file referenced by fd to the temp file
664bd389b36SDavid du Colombier  */
665bd389b36SDavid du Colombier void
666*219b2ee8SDavid du Colombier armove(Biobuf *b, Arfile *ap, Armember *bp)
667bd389b36SDavid du Colombier {
668bd389b36SDavid du Colombier 	char *cp;
669bd389b36SDavid du Colombier 	Dir d;
6703e12c5d1SDavid du Colombier 
671*219b2ee8SDavid du Colombier 	if (dirfstat(Bfildes(b), &d) < 0) {
672bd389b36SDavid du Colombier 		fprint(2, "ar: cannot stat %s\n", file);
673bd389b36SDavid du Colombier 		return;
674bd389b36SDavid du Colombier 	}
675bd389b36SDavid du Colombier 	trim(file, bp->hdr.name, sizeof(bp->hdr.name));
676bd389b36SDavid du Colombier 	for (cp = strchr(bp->hdr.name, 0);		/* blank pad on right */
677bd389b36SDavid du Colombier 		cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
678bd389b36SDavid du Colombier 			*cp = ' ';
679bd389b36SDavid du Colombier 	sprint(bp->hdr.date, "%-12ld", d.mtime);
680bd389b36SDavid du Colombier 	sprint(bp->hdr.uid, "%-6d", 0);
681bd389b36SDavid du Colombier 	sprint(bp->hdr.gid, "%-6d", 0);
682bd389b36SDavid du Colombier 	sprint(bp->hdr.mode, "%-8lo", d.mode);
683bd389b36SDavid du Colombier 	sprint(bp->hdr.size, "%-10ld", d.length);
684bd389b36SDavid du Colombier 	strncpy(bp->hdr.fmag, ARFMAG, 2);
685bd389b36SDavid du Colombier 	bp->size = d.length;
686bd389b36SDavid du Colombier 	bp->date = d.mtime;
687*219b2ee8SDavid du Colombier 	arread(b, bp, bp->size);
688*219b2ee8SDavid du Colombier 	if (d.length&0x01)
689*219b2ee8SDavid du Colombier 		d.length++;
690*219b2ee8SDavid du Colombier 	if (ap) {
691bd389b36SDavid du Colombier 		arinsert(ap, bp);
692*219b2ee8SDavid du Colombier 		ap->size += d.length+SAR_HDR;
693*219b2ee8SDavid du Colombier 	}
694bd389b36SDavid du Colombier }
695bd389b36SDavid du Colombier /*
696bd389b36SDavid du Colombier  *	Copy the archive member at the current offset into the temp file.
697bd389b36SDavid du Colombier  */
698bd389b36SDavid du Colombier void
699*219b2ee8SDavid du Colombier arcopy(Biobuf *b, Arfile *ap, Armember *bp)
700bd389b36SDavid du Colombier {
701bd389b36SDavid du Colombier 	int n;
7023e12c5d1SDavid du Colombier 
703bd389b36SDavid du Colombier 	n = bp->size;
704bd389b36SDavid du Colombier 	if (n & 01)
705bd389b36SDavid du Colombier 		n++;
706*219b2ee8SDavid du Colombier 	arread(b, bp, n);
707*219b2ee8SDavid du Colombier 	if (ap) {
708bd389b36SDavid du Colombier 		arinsert(ap, bp);
709*219b2ee8SDavid du Colombier 		ap->size += n+SAR_HDR;
710*219b2ee8SDavid du Colombier 	}
711bd389b36SDavid du Colombier }
712bd389b36SDavid du Colombier /*
713bd389b36SDavid du Colombier  *	Skip an archive member
714bd389b36SDavid du Colombier  */
715bd389b36SDavid du Colombier void
716*219b2ee8SDavid du Colombier skip(Biobuf *bp, long len)
717bd389b36SDavid du Colombier {
718bd389b36SDavid du Colombier 	if (len & 01)
719bd389b36SDavid du Colombier 		len++;
720*219b2ee8SDavid du Colombier 	Bseek(bp, len, 1);
721bd389b36SDavid du Colombier }
722bd389b36SDavid du Colombier /*
723bd389b36SDavid du Colombier  *	Stream the three temp files to an archive
724bd389b36SDavid du Colombier  */
725bd389b36SDavid du Colombier void
726bd389b36SDavid du Colombier install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend)
727bd389b36SDavid du Colombier {
728bd389b36SDavid du Colombier 	int fd;
729bd389b36SDavid du Colombier 
730bd389b36SDavid du Colombier 	/* leave note group behind when copying back; i.e. sidestep interrupts */
731bd389b36SDavid du Colombier 	rfork(RFNOTEG);
732bd389b36SDavid du Colombier 	fd = arcreate(arname);
733*219b2ee8SDavid du Colombier 	rl(fd);
734bd389b36SDavid du Colombier 	if (astart) {
735bd389b36SDavid du Colombier 		arstream(fd, astart);
736bd389b36SDavid du Colombier 		arfree(astart);
737bd389b36SDavid du Colombier 	}
738bd389b36SDavid du Colombier 	if (amiddle) {
739bd389b36SDavid du Colombier 		arstream(fd, amiddle);
740bd389b36SDavid du Colombier 		arfree(amiddle);
741bd389b36SDavid du Colombier 	}
742bd389b36SDavid du Colombier 	if (aend) {
743bd389b36SDavid du Colombier 		arstream(fd, aend);
744bd389b36SDavid du Colombier 		arfree(aend);
745bd389b36SDavid du Colombier 	}
746bd389b36SDavid du Colombier 	close(fd);
747bd389b36SDavid du Colombier }
748*219b2ee8SDavid du Colombier void
749*219b2ee8SDavid du Colombier rl(int fd)
750*219b2ee8SDavid du Colombier {
751*219b2ee8SDavid du Colombier 
752*219b2ee8SDavid du Colombier 	Biobuf b;
753*219b2ee8SDavid du Colombier 	char *cp;
754*219b2ee8SDavid du Colombier 	struct ar_hdr a;
755*219b2ee8SDavid du Colombier 	long len;
756*219b2ee8SDavid du Colombier 
757*219b2ee8SDavid du Colombier 	if (!allobj)
758*219b2ee8SDavid du Colombier 		return;
759*219b2ee8SDavid du Colombier 
760*219b2ee8SDavid du Colombier 	Binit(&b, fd, OWRITE);
761*219b2ee8SDavid du Colombier 	Bseek(&b,seek(fd,0,1), 0);
762*219b2ee8SDavid du Colombier 
763*219b2ee8SDavid du Colombier 	len = symdefsize;
764*219b2ee8SDavid du Colombier 	if(len&01)
765*219b2ee8SDavid du Colombier 		len++;
766*219b2ee8SDavid du Colombier 	sprint(a.date, "%-12ld", time(0));
767*219b2ee8SDavid du Colombier 	sprint(a.uid, "%-6d", 0);
768*219b2ee8SDavid du Colombier 	sprint(a.gid, "%-6d", 0);
769*219b2ee8SDavid du Colombier 	sprint(a.mode, "%-8lo", 0644);
770*219b2ee8SDavid du Colombier 	sprint(a.size, "%-10ld", len);
771*219b2ee8SDavid du Colombier 	strncpy(a.fmag, ARFMAG, 2);
772*219b2ee8SDavid du Colombier 	strcpy(a.name, symdef);
773*219b2ee8SDavid du Colombier 	for (cp = strchr(a.name, 0);		/* blank pad on right */
774*219b2ee8SDavid du Colombier 		cp < a.name+sizeof(a.name); cp++)
775*219b2ee8SDavid du Colombier 			*cp = ' ';
776*219b2ee8SDavid du Colombier 	if(HEADER_IO(Bwrite, &b, a))
777*219b2ee8SDavid du Colombier 			wrerr();
778*219b2ee8SDavid du Colombier 
779*219b2ee8SDavid du Colombier 	len += BOFFSET(&b);
780*219b2ee8SDavid du Colombier 	if (astart) {
781*219b2ee8SDavid du Colombier 		wrsym(&b, len, astart->sym);
782*219b2ee8SDavid du Colombier 		len += astart->size;
783*219b2ee8SDavid du Colombier 	}
784*219b2ee8SDavid du Colombier 	if(amiddle) {
785*219b2ee8SDavid du Colombier 		wrsym(&b, len, amiddle->sym);
786*219b2ee8SDavid du Colombier 		len += amiddle->size;
787*219b2ee8SDavid du Colombier 	}
788*219b2ee8SDavid du Colombier 	if(aend)
789*219b2ee8SDavid du Colombier 		wrsym(&b, len, aend->sym);
790*219b2ee8SDavid du Colombier 
791*219b2ee8SDavid du Colombier 	if(symdefsize&0x01)
792*219b2ee8SDavid du Colombier 		Bputc(&b, 0);
793*219b2ee8SDavid du Colombier 	Bterm(&b);
794*219b2ee8SDavid du Colombier }
795*219b2ee8SDavid du Colombier /*
796*219b2ee8SDavid du Colombier  *	Write the defined symbols to the symdef file
797*219b2ee8SDavid du Colombier  */
798*219b2ee8SDavid du Colombier void
799*219b2ee8SDavid du Colombier wrsym(Biobuf *bp, int offset, Arsymref *as)
800*219b2ee8SDavid du Colombier {
801*219b2ee8SDavid du Colombier 	int off;
802*219b2ee8SDavid du Colombier 
803*219b2ee8SDavid du Colombier 	while(as) {
804*219b2ee8SDavid du Colombier 		Bputc(bp, as->type);
805*219b2ee8SDavid du Colombier 		off = as->offset+offset;
806*219b2ee8SDavid du Colombier 		Bputc(bp, off);
807*219b2ee8SDavid du Colombier 		Bputc(bp, off>>8);
808*219b2ee8SDavid du Colombier 		Bputc(bp, off>>16);
809*219b2ee8SDavid du Colombier 		Bputc(bp, off>>24);
810*219b2ee8SDavid du Colombier 		if (Bwrite(bp, as->name, as->len+1) != as->len+1)
811*219b2ee8SDavid du Colombier 			wrerr();
812*219b2ee8SDavid du Colombier 		as = as->next;
813*219b2ee8SDavid du Colombier 	}
814*219b2ee8SDavid du Colombier }
815bd389b36SDavid du Colombier /*
816bd389b36SDavid du Colombier  *	Check if the archive member matches an entry on the command line.
817bd389b36SDavid du Colombier  */
8183e12c5d1SDavid du Colombier int
819bd389b36SDavid du Colombier match(int count, char **files)
8203e12c5d1SDavid du Colombier {
8213e12c5d1SDavid du Colombier 	int i;
822bd389b36SDavid du Colombier 	char name[ARNAMESIZE+1];
8233e12c5d1SDavid du Colombier 
824bd389b36SDavid du Colombier 	for(i=0; i<count; i++) {
825bd389b36SDavid du Colombier 		if(files[i] == 0)
8263e12c5d1SDavid du Colombier 			continue;
827*219b2ee8SDavid du Colombier 		trim(files[i], name, ARNAMESIZE);
828*219b2ee8SDavid du Colombier 		if(strncmp(name, file, ARNAMESIZE) == 0) {
829bd389b36SDavid du Colombier 			file = files[i];
830bd389b36SDavid du Colombier 			files[i] = 0;
8313e12c5d1SDavid du Colombier 			return 1;
8323e12c5d1SDavid du Colombier 		}
8333e12c5d1SDavid du Colombier 	}
8343e12c5d1SDavid du Colombier 	return 0;
8353e12c5d1SDavid du Colombier }
836bd389b36SDavid du Colombier /*
837bd389b36SDavid du Colombier  *	compare the current member to the name of the pivot member
838bd389b36SDavid du Colombier  */
839bd389b36SDavid du Colombier int
840bd389b36SDavid du Colombier bamatch(char *file, char *pivot)
8413e12c5d1SDavid du Colombier {
842bd389b36SDavid du Colombier 	static int state = 0;
8433e12c5d1SDavid du Colombier 
844bd389b36SDavid du Colombier 	switch(state)
845bd389b36SDavid du Colombier 	{
846bd389b36SDavid du Colombier 	case 0:			/* looking for position file */
847bd389b36SDavid du Colombier 		if (aflag) {
848*219b2ee8SDavid du Colombier 			if (strncmp(file, pivot, ARNAMESIZE) == 0)
849bd389b36SDavid du Colombier 				state = 1;
850bd389b36SDavid du Colombier 		} else if (bflag) {
851*219b2ee8SDavid du Colombier 			if (strncmp(file, pivot, ARNAMESIZE) == 0) {
852bd389b36SDavid du Colombier 				state = 2;	/* found */
853bd389b36SDavid du Colombier 				return 1;
8543e12c5d1SDavid du Colombier 			}
8553e12c5d1SDavid du Colombier 		}
856bd389b36SDavid du Colombier 		break;
857bd389b36SDavid du Colombier 	case 1:			/* found - after previous file */
858bd389b36SDavid du Colombier 		state = 2;
859bd389b36SDavid du Colombier 		return 1;
860bd389b36SDavid du Colombier 	case 2:			/* already found position file */
861bd389b36SDavid du Colombier 		break;
862bd389b36SDavid du Colombier 	}
863bd389b36SDavid du Colombier 	return 0;
864bd389b36SDavid du Colombier }
865bd389b36SDavid du Colombier /*
866bd389b36SDavid du Colombier  *	output a message, if 'v' option was specified
867bd389b36SDavid du Colombier  */
8683e12c5d1SDavid du Colombier void
869bd389b36SDavid du Colombier mesg(int c, char *file)
8703e12c5d1SDavid du Colombier {
8713e12c5d1SDavid du Colombier 
872bd389b36SDavid du Colombier 	if(vflag)
8733e12c5d1SDavid du Colombier 		Bprint(&bout, "%c - %s\n", c, file);
8743e12c5d1SDavid du Colombier }
875bd389b36SDavid du Colombier /*
876bd389b36SDavid du Colombier  *	isolate file name by stripping leading directories and trailing slashes
877bd389b36SDavid du Colombier  */
878bd389b36SDavid du Colombier void
879bd389b36SDavid du Colombier trim(char *s, char *buf, int n)
8803e12c5d1SDavid du Colombier {
881bd389b36SDavid du Colombier 	char *p;
8823e12c5d1SDavid du Colombier 
883bd389b36SDavid du Colombier 	for(;;) {
884bd389b36SDavid du Colombier 		p = strrchr(s, '/');
885bd389b36SDavid du Colombier 		if (!p) {		/* no slash in name */
886bd389b36SDavid du Colombier 			strncpy(buf, s, n);
887bd389b36SDavid du Colombier 			return;
8883e12c5d1SDavid du Colombier 		}
889bd389b36SDavid du Colombier 		if (p[1] != 0) {	/* p+1 is first char of file name */
890bd389b36SDavid du Colombier 			strncpy(buf, p+1, n);
891bd389b36SDavid du Colombier 			return;
8923e12c5d1SDavid du Colombier 		}
893bd389b36SDavid du Colombier 		*p = 0;			/* strip trailing slash */
894bd389b36SDavid du Colombier 	}
895bd389b36SDavid du Colombier }
896bd389b36SDavid du Colombier /*
897bd389b36SDavid du Colombier  *	utilities for printing long form of 't' command
898bd389b36SDavid du Colombier  */
8993e12c5d1SDavid du Colombier #define	SUID	04000
9003e12c5d1SDavid du Colombier #define	SGID	02000
9013e12c5d1SDavid du Colombier #define	ROWN	0400
9023e12c5d1SDavid du Colombier #define	WOWN	0200
9033e12c5d1SDavid du Colombier #define	XOWN	0100
9043e12c5d1SDavid du Colombier #define	RGRP	040
9053e12c5d1SDavid du Colombier #define	WGRP	020
9063e12c5d1SDavid du Colombier #define	XGRP	010
9073e12c5d1SDavid du Colombier #define	ROTH	04
9083e12c5d1SDavid du Colombier #define	WOTH	02
9093e12c5d1SDavid du Colombier #define	XOTH	01
9103e12c5d1SDavid du Colombier #define	STXT	01000
9113e12c5d1SDavid du Colombier 
9123e12c5d1SDavid du Colombier void
913bd389b36SDavid du Colombier longt(Armember *bp)
9143e12c5d1SDavid du Colombier {
9153e12c5d1SDavid du Colombier 	char *cp;
9163e12c5d1SDavid du Colombier 
917bd389b36SDavid du Colombier 	pmode(strtoul(bp->hdr.mode, 0, 8));
918bd389b36SDavid du Colombier 	Bprint(&bout, "%3d/%1d", atol(bp->hdr.uid), atol(bp->hdr.gid));
919bd389b36SDavid du Colombier 	Bprint(&bout, "%7ld", bp->size);
920bd389b36SDavid du Colombier 	cp = ctime(bp->date);
9213e12c5d1SDavid du Colombier 	Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
9223e12c5d1SDavid du Colombier }
9233e12c5d1SDavid du Colombier 
9243e12c5d1SDavid du Colombier int	m1[] = { 1, ROWN, 'r', '-' };
9253e12c5d1SDavid du Colombier int	m2[] = { 1, WOWN, 'w', '-' };
9263e12c5d1SDavid du Colombier int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
9273e12c5d1SDavid du Colombier int	m4[] = { 1, RGRP, 'r', '-' };
9283e12c5d1SDavid du Colombier int	m5[] = { 1, WGRP, 'w', '-' };
9293e12c5d1SDavid du Colombier int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
9303e12c5d1SDavid du Colombier int	m7[] = { 1, ROTH, 'r', '-' };
9313e12c5d1SDavid du Colombier int	m8[] = { 1, WOTH, 'w', '-' };
9323e12c5d1SDavid du Colombier int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
9333e12c5d1SDavid du Colombier 
9343e12c5d1SDavid du Colombier int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
9353e12c5d1SDavid du Colombier 
9363e12c5d1SDavid du Colombier void
937bd389b36SDavid du Colombier pmode(long mode)
9383e12c5d1SDavid du Colombier {
9393e12c5d1SDavid du Colombier 	int **mp;
9403e12c5d1SDavid du Colombier 
9413e12c5d1SDavid du Colombier 	for(mp = &m[0]; mp < &m[9];)
942bd389b36SDavid du Colombier 		select(*mp++, mode);
9433e12c5d1SDavid du Colombier }
9443e12c5d1SDavid du Colombier 
9453e12c5d1SDavid du Colombier void
946bd389b36SDavid du Colombier select(int *ap, long mode)
9473e12c5d1SDavid du Colombier {
948bd389b36SDavid du Colombier 	int n;
9493e12c5d1SDavid du Colombier 
9503e12c5d1SDavid du Colombier 	n = *ap++;
951bd389b36SDavid du Colombier 	while(--n>=0 && (mode&*ap++)==0)
9523e12c5d1SDavid du Colombier 		ap++;
9533e12c5d1SDavid du Colombier 	Bputc(&bout, *ap);
9543e12c5d1SDavid du Colombier }
955bd389b36SDavid du Colombier /*
956bd389b36SDavid du Colombier  *	Temp file I/O subsystem.  We attempt to cache all three temp files in
957bd389b36SDavid du Colombier  *	core.  When we run out of memory we spill to disk.
958bd389b36SDavid du Colombier  *	The I/O model assumes that temp files:
959bd389b36SDavid du Colombier  *		1) are only written on the end
960bd389b36SDavid du Colombier  *		2) are only read from the beginning
961bd389b36SDavid du Colombier  *		3) are only read after all writing is complete.
962bd389b36SDavid du Colombier  *	The architecture uses one control block per temp file.  Each control
963bd389b36SDavid du Colombier  *	block anchors a chain of buffers, each containing an archive member.
964bd389b36SDavid du Colombier  */
965bd389b36SDavid du Colombier Arfile *
966bd389b36SDavid du Colombier newtempfile(char *name)		/* allocate a file control block */
967bd389b36SDavid du Colombier {
968bd389b36SDavid du Colombier 	Arfile *ap;
969bd389b36SDavid du Colombier 
970bd389b36SDavid du Colombier 	ap = (Arfile *) armalloc(sizeof(Arfile));
971bd389b36SDavid du Colombier 	ap->fname = name;
972bd389b36SDavid du Colombier 	return ap;
973bd389b36SDavid du Colombier }
974bd389b36SDavid du Colombier 
975bd389b36SDavid du Colombier Armember *
976bd389b36SDavid du Colombier newmember(void)			/* allocate a member buffer */
977bd389b36SDavid du Colombier {
978bd389b36SDavid du Colombier 	return (Armember *)armalloc(sizeof(Armember));
979bd389b36SDavid du Colombier }
9803e12c5d1SDavid du Colombier 
9813e12c5d1SDavid du Colombier void
982*219b2ee8SDavid du Colombier arread(Biobuf *b, Armember *bp, int n)	/* read an image into a member buffer */
9833e12c5d1SDavid du Colombier {
984bd389b36SDavid du Colombier 	int i;
985bd389b36SDavid du Colombier 
986bd389b36SDavid du Colombier 	bp->member = armalloc(n);
987*219b2ee8SDavid du Colombier 	i = Bread(b, bp->member, n);
988bd389b36SDavid du Colombier 	if (i < 0) {
989bd389b36SDavid du Colombier 		free(bp->member);
990bd389b36SDavid du Colombier 		bp->member = 0;
991bd389b36SDavid du Colombier 		rderr();
992bd389b36SDavid du Colombier 	}
993bd389b36SDavid du Colombier }
994bd389b36SDavid du Colombier /*
995bd389b36SDavid du Colombier  * insert a member buffer into the member chain
996bd389b36SDavid du Colombier  */
997bd389b36SDavid du Colombier void
998bd389b36SDavid du Colombier arinsert(Arfile *ap, Armember *bp)
999bd389b36SDavid du Colombier {
1000bd389b36SDavid du Colombier 	bp->next = 0;
1001bd389b36SDavid du Colombier 	if (!ap->tail)
1002bd389b36SDavid du Colombier 		ap->head = bp;
1003bd389b36SDavid du Colombier 	else
1004bd389b36SDavid du Colombier 		ap->tail->next = bp;
1005bd389b36SDavid du Colombier 	ap->tail = bp;
1006bd389b36SDavid du Colombier }
1007bd389b36SDavid du Colombier /*
1008bd389b36SDavid du Colombier  *	stream the members in a temp file to the file referenced by 'fd'.
1009bd389b36SDavid du Colombier  */
1010bd389b36SDavid du Colombier void
1011bd389b36SDavid du Colombier arstream(int fd, Arfile *ap)
1012bd389b36SDavid du Colombier {
1013bd389b36SDavid du Colombier 	Armember *bp;
1014bd389b36SDavid du Colombier 	int i;
1015bd389b36SDavid du Colombier 	char buf[8192];
1016bd389b36SDavid du Colombier 
1017bd389b36SDavid du Colombier 	if (ap->paged) {		/* copy from disk */
1018bd389b36SDavid du Colombier 		seek(ap->fd, 0, 0);
1019bd389b36SDavid du Colombier 		for (;;) {
1020bd389b36SDavid du Colombier 			i = read(ap->fd, buf, sizeof(buf));
1021bd389b36SDavid du Colombier 			if (i < 0)
1022bd389b36SDavid du Colombier 				rderr();
1023bd389b36SDavid du Colombier 			if (i == 0)
1024bd389b36SDavid du Colombier 				break;
1025bd389b36SDavid du Colombier 			if (write(fd, buf, i) != i)
1026bd389b36SDavid du Colombier 				wrerr();
1027bd389b36SDavid du Colombier 		}
1028bd389b36SDavid du Colombier 		close(ap->fd);
1029bd389b36SDavid du Colombier 		ap->paged = 0;
1030bd389b36SDavid du Colombier 	}
1031bd389b36SDavid du Colombier 		/* dump the in-core buffers */
1032bd389b36SDavid du Colombier 	for (bp = ap->head; bp; bp = bp->next) {
1033bd389b36SDavid du Colombier 		if (!arwrite(fd, bp))
1034bd389b36SDavid du Colombier 			wrerr();
1035bd389b36SDavid du Colombier 	}
1036bd389b36SDavid du Colombier }
1037bd389b36SDavid du Colombier /*
1038bd389b36SDavid du Colombier  *	write a member to 'fd'.
1039bd389b36SDavid du Colombier  */
1040bd389b36SDavid du Colombier int
1041bd389b36SDavid du Colombier arwrite(int fd, Armember *bp)
1042bd389b36SDavid du Colombier {
1043bd389b36SDavid du Colombier 	int len;
1044bd389b36SDavid du Colombier 
1045*219b2ee8SDavid du Colombier 	if(HEADER_IO(write, fd, bp->hdr))
1046bd389b36SDavid du Colombier 		return 0;
1047bd389b36SDavid du Colombier 	len = bp->size;
1048bd389b36SDavid du Colombier 	if (len & 01)
1049bd389b36SDavid du Colombier 		len++;
1050bd389b36SDavid du Colombier 	if (write(fd, bp->member, len) != len)
1051bd389b36SDavid du Colombier 		return 0;
1052bd389b36SDavid du Colombier 	return 1;
1053bd389b36SDavid du Colombier }
1054bd389b36SDavid du Colombier /*
1055bd389b36SDavid du Colombier  *	Spill a member to a disk copy of a temp file
1056bd389b36SDavid du Colombier  */
1057bd389b36SDavid du Colombier int
1058bd389b36SDavid du Colombier page(Arfile *ap)
1059bd389b36SDavid du Colombier {
1060bd389b36SDavid du Colombier 	Armember *bp;
1061bd389b36SDavid du Colombier 
1062bd389b36SDavid du Colombier 	bp = ap->head;
1063bd389b36SDavid du Colombier 	if (!ap->paged) {		/* not yet paged - create file */
1064bd389b36SDavid du Colombier 		ap->fname = mktemp(ap->fname);
1065bd389b36SDavid du Colombier 		ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
1066bd389b36SDavid du Colombier 		if (ap->fd < 0) {
1067bd389b36SDavid du Colombier 			fprint(2,"ar: can't create temp file\n");
1068bd389b36SDavid du Colombier 			return 0;
1069bd389b36SDavid du Colombier 		}
1070bd389b36SDavid du Colombier 		ap->paged = 1;
1071bd389b36SDavid du Colombier 	}
1072bd389b36SDavid du Colombier 	if (!arwrite(ap->fd, bp))	/* write member and free buffer block */
1073bd389b36SDavid du Colombier 		return 0;
1074bd389b36SDavid du Colombier 	ap->head = bp->next;
1075bd389b36SDavid du Colombier 	if (ap->tail == bp)
1076bd389b36SDavid du Colombier 		ap->tail = bp->next;
1077bd389b36SDavid du Colombier 	free(bp->member);
1078bd389b36SDavid du Colombier 	free(bp);
1079bd389b36SDavid du Colombier 	return 1;
1080bd389b36SDavid du Colombier }
1081bd389b36SDavid du Colombier /*
1082bd389b36SDavid du Colombier  *	try to reclaim space by paging.  we try to spill the start, middle,
1083bd389b36SDavid du Colombier  *	and end files, in that order.  there is no particular reason for the
1084bd389b36SDavid du Colombier  *	ordering.
1085bd389b36SDavid du Colombier  */
1086bd389b36SDavid du Colombier int
1087bd389b36SDavid du Colombier getspace(void)
1088bd389b36SDavid du Colombier {
1089bd389b36SDavid du Colombier 	if (astart && astart->head && page(astart))
1090bd389b36SDavid du Colombier 			return 1;
1091bd389b36SDavid du Colombier 	if (amiddle && amiddle->head && page(amiddle))
1092bd389b36SDavid du Colombier 			return 1;
1093bd389b36SDavid du Colombier 	if (aend && aend->head && page(aend))
1094bd389b36SDavid du Colombier 			return 1;
1095bd389b36SDavid du Colombier 	return 0;
1096bd389b36SDavid du Colombier }
1097bd389b36SDavid du Colombier 
1098bd389b36SDavid du Colombier void
1099bd389b36SDavid du Colombier arfree(Arfile *ap)		/* free a member buffer */
1100bd389b36SDavid du Colombier {
1101bd389b36SDavid du Colombier 	Armember *bp, *next;
1102bd389b36SDavid du Colombier 
1103bd389b36SDavid du Colombier 	for (bp = ap->head; bp; bp = next) {
1104bd389b36SDavid du Colombier 		next = bp->next;
1105bd389b36SDavid du Colombier 		if (bp->member)
1106bd389b36SDavid du Colombier 			free(bp->member);
1107bd389b36SDavid du Colombier 		free(bp);
1108bd389b36SDavid du Colombier 	}
1109bd389b36SDavid du Colombier 	free(ap);
1110bd389b36SDavid du Colombier }
1111bd389b36SDavid du Colombier /*
1112bd389b36SDavid du Colombier  *	allocate space for a control block or member buffer.  if the malloc
1113bd389b36SDavid du Colombier  *	fails we try to reclaim space by spilling previously allocated
1114bd389b36SDavid du Colombier  *	member buffers.
1115bd389b36SDavid du Colombier  */
1116bd389b36SDavid du Colombier char *
1117bd389b36SDavid du Colombier armalloc(int n)
1118bd389b36SDavid du Colombier {
1119bd389b36SDavid du Colombier 	char *cp;
1120bd389b36SDavid du Colombier 
1121bd389b36SDavid du Colombier 	do {
1122bd389b36SDavid du Colombier 		cp = malloc(n);
1123bd389b36SDavid du Colombier 		if (cp) {
1124bd389b36SDavid du Colombier 			memset(cp, 0, n);
1125bd389b36SDavid du Colombier 			return cp;
1126bd389b36SDavid du Colombier 		}
1127bd389b36SDavid du Colombier 	} while (getspace());
1128bd389b36SDavid du Colombier 	fprint(2, "ar: out of memory\n");
1129bd389b36SDavid du Colombier 	exits("malloc");
1130bd389b36SDavid du Colombier 	return 0;
11313e12c5d1SDavid du Colombier }
1132