xref: /plan9/sys/lib/dist/cmd/bzfs/mkext.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /*
2*9a747e4fSDavid du Colombier  * bzip2-based file system.
3*9a747e4fSDavid du Colombier  * the file system itself is just a bzipped2 xzipped mkfs archive
4*9a747e4fSDavid du Colombier  * prefixed with "bzfilesystem\n" and suffixed with
5*9a747e4fSDavid du Colombier  * a kilobyte of zeros.
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * changes to the file system are only kept in
8*9a747e4fSDavid du Colombier  * memory, not written back to the disk.
9*9a747e4fSDavid du Colombier  *
10*9a747e4fSDavid du Colombier  * this is intended for use on a floppy boot disk.
11*9a747e4fSDavid du Colombier  * we assume the file is in the dos file system and
12*9a747e4fSDavid du Colombier  * contiguous on the disk: finding it amounts to
13*9a747e4fSDavid du Colombier  * looking at the beginning of each sector for
14*9a747e4fSDavid du Colombier  * "bzfilesystem\n".  then we pipe it through
15*9a747e4fSDavid du Colombier  * bunzip2 and store the files in a file tree in memory.
16*9a747e4fSDavid du Colombier  * things are slightly complicated by the fact that
17*9a747e4fSDavid du Colombier  * devfloppy requires reads to be on a 512-byte
18*9a747e4fSDavid du Colombier  * boundary and be a multiple of 512 bytes; we
19*9a747e4fSDavid du Colombier  * fork a process to relieve bunzip2 of this restriction.
20*9a747e4fSDavid du Colombier  */
21*9a747e4fSDavid du Colombier 
22*9a747e4fSDavid du Colombier #include <u.h>
23*9a747e4fSDavid du Colombier #include <libc.h>
24*9a747e4fSDavid du Colombier #include <bio.h>
25*9a747e4fSDavid du Colombier #include <auth.h>
26*9a747e4fSDavid du Colombier #include <fcall.h>
27*9a747e4fSDavid du Colombier #include "bzfs.h"
28*9a747e4fSDavid du Colombier 
29*9a747e4fSDavid du Colombier enum{
30*9a747e4fSDavid du Colombier 	LEN	= 8*1024,
31*9a747e4fSDavid du Colombier 	NFLDS	= 6,		/* filename, modes, uid, gid, mtime, bytes */
32*9a747e4fSDavid du Colombier };
33*9a747e4fSDavid du Colombier 
34*9a747e4fSDavid du Colombier void	mkdirs(char*, char*);
35*9a747e4fSDavid du Colombier void	mkdir(char*, ulong, ulong, char*, char*);
36*9a747e4fSDavid du Colombier void	extract(char*, ulong, ulong, char*, char*, ulong);
37*9a747e4fSDavid du Colombier void	seekpast(ulong);
38*9a747e4fSDavid du Colombier void	error(char*, ...);
39*9a747e4fSDavid du Colombier void	warn(char*, ...);
40*9a747e4fSDavid du Colombier void	usage(void);
41*9a747e4fSDavid du Colombier char *mtpt;
42*9a747e4fSDavid du Colombier Biobufhdr bin;
43*9a747e4fSDavid du Colombier uchar	binbuf[2*LEN];
44*9a747e4fSDavid du Colombier 
45*9a747e4fSDavid du Colombier void
usage(void)46*9a747e4fSDavid du Colombier usage(void)
47*9a747e4fSDavid du Colombier {
48*9a747e4fSDavid du Colombier 	fprint(2, "usage: bzfs [-m mtpt] [-s] [-f file] [-h]\n");
49*9a747e4fSDavid du Colombier 	exits("usage");
50*9a747e4fSDavid du Colombier }
51*9a747e4fSDavid du Colombier 
52*9a747e4fSDavid du Colombier /*
53*9a747e4fSDavid du Colombier  * floppy disks can only be read on 512-byte
54*9a747e4fSDavid du Colombier  * boundaries and in 512 byte multiples.
55*9a747e4fSDavid du Colombier  * feed one over a pipe to allow arbitrary reading.
56*9a747e4fSDavid du Colombier  */
57*9a747e4fSDavid du Colombier char zero[512];
58*9a747e4fSDavid du Colombier int
blockread(int in,char * first,int nfirst)59*9a747e4fSDavid du Colombier blockread(int in, char *first, int nfirst)
60*9a747e4fSDavid du Colombier {
61*9a747e4fSDavid du Colombier 	int p[2], out, n, rv;
62*9a747e4fSDavid du Colombier 	char blk[512];
63*9a747e4fSDavid du Colombier 
64*9a747e4fSDavid du Colombier 	if(pipe(p) < 0)
65*9a747e4fSDavid du Colombier 		sysfatal("pipe: %r");
66*9a747e4fSDavid du Colombier 	rv = p[0];
67*9a747e4fSDavid du Colombier 	out = p[1];
68*9a747e4fSDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFFDG)){
69*9a747e4fSDavid du Colombier 	case -1:
70*9a747e4fSDavid du Colombier 		sysfatal("fork: %r");
71*9a747e4fSDavid du Colombier 	case 0:
72*9a747e4fSDavid du Colombier 		close(rv);
73*9a747e4fSDavid du Colombier 		break;
74*9a747e4fSDavid du Colombier 	default:
75*9a747e4fSDavid du Colombier 		close(in);
76*9a747e4fSDavid du Colombier 		close(out);
77*9a747e4fSDavid du Colombier 		return rv;
78*9a747e4fSDavid du Colombier 	}
79*9a747e4fSDavid du Colombier 
80*9a747e4fSDavid du Colombier 	write(out, first, nfirst);
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier 	while((n=read(in, blk, sizeof blk)) > 0){
83*9a747e4fSDavid du Colombier 		if(write(out, blk, n) != n)
84*9a747e4fSDavid du Colombier 			break;
85*9a747e4fSDavid du Colombier 		if(n == sizeof(blk) && memcmp(zero, blk, n) == n)
86*9a747e4fSDavid du Colombier 			break;
87*9a747e4fSDavid du Colombier 	}
88*9a747e4fSDavid du Colombier 	_exits(0);
89*9a747e4fSDavid du Colombier 	return -1;
90*9a747e4fSDavid du Colombier }
91*9a747e4fSDavid du Colombier 
92*9a747e4fSDavid du Colombier enum { NAMELEN = 28 };
93*9a747e4fSDavid du Colombier 
94*9a747e4fSDavid du Colombier void
main(int argc,char ** argv)95*9a747e4fSDavid du Colombier main(int argc, char **argv)
96*9a747e4fSDavid du Colombier {
97*9a747e4fSDavid du Colombier 	char *rargv[10];
98*9a747e4fSDavid du Colombier 	int rargc;
99*9a747e4fSDavid du Colombier 	char *fields[NFLDS], name[2*LEN], *p, *namep;
100*9a747e4fSDavid du Colombier 	char uid[NAMELEN], gid[NAMELEN];
101*9a747e4fSDavid du Colombier 	ulong mode, bytes, mtime;
102*9a747e4fSDavid du Colombier 	char *file;
103*9a747e4fSDavid du Colombier 	int i, n, stdin, fd, chatty;
104*9a747e4fSDavid du Colombier 	char blk[512];
105*9a747e4fSDavid du Colombier 
106*9a747e4fSDavid du Colombier 	if(argc>1 && strcmp(argv[1], "RAMFS") == 0){
107*9a747e4fSDavid du Colombier 		argv[1] = argv[0];
108*9a747e4fSDavid du Colombier 		ramfsmain(argc-1, argv+1);
109*9a747e4fSDavid du Colombier 		exits(nil);
110*9a747e4fSDavid du Colombier 	}
111*9a747e4fSDavid du Colombier 	if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){
112*9a747e4fSDavid du Colombier 		_unbzip(0, 1);
113*9a747e4fSDavid du Colombier 		exits(nil);
114*9a747e4fSDavid du Colombier 	}
115*9a747e4fSDavid du Colombier 
116*9a747e4fSDavid du Colombier 	rfork(RFNOTEG);
117*9a747e4fSDavid du Colombier 	stdin = 0;
118*9a747e4fSDavid du Colombier 	file = nil;
119*9a747e4fSDavid du Colombier 	namep = name;
120*9a747e4fSDavid du Colombier 	mtpt = "/root";
121*9a747e4fSDavid du Colombier 	chatty = 0;
122*9a747e4fSDavid du Colombier 	ARGBEGIN{
123*9a747e4fSDavid du Colombier 	case 'd':
124*9a747e4fSDavid du Colombier 		chatty = !chatty;
125*9a747e4fSDavid du Colombier 		break;
126*9a747e4fSDavid du Colombier 	case 'f':
127*9a747e4fSDavid du Colombier 		file = ARGF();
128*9a747e4fSDavid du Colombier 		break;
129*9a747e4fSDavid du Colombier 	case 's':
130*9a747e4fSDavid du Colombier 		stdin++;
131*9a747e4fSDavid du Colombier 		break;
132*9a747e4fSDavid du Colombier 	case 'm':
133*9a747e4fSDavid du Colombier 		mtpt = ARGF();
134*9a747e4fSDavid du Colombier 		break;
135*9a747e4fSDavid du Colombier 	default:
136*9a747e4fSDavid du Colombier 		usage();
137*9a747e4fSDavid du Colombier 	}ARGEND
138*9a747e4fSDavid du Colombier 
139*9a747e4fSDavid du Colombier 	if(argc != 0)
140*9a747e4fSDavid du Colombier 		usage();
141*9a747e4fSDavid du Colombier 
142*9a747e4fSDavid du Colombier 	if(file == nil) {
143*9a747e4fSDavid du Colombier 		fprint(2, "must specify -f file\n");
144*9a747e4fSDavid du Colombier 		usage();
145*9a747e4fSDavid du Colombier 	}
146*9a747e4fSDavid du Colombier 
147*9a747e4fSDavid du Colombier 	if((fd = open(file, OREAD)) < 0) {
148*9a747e4fSDavid du Colombier 		fprint(2, "cannot open \"%s\": %r\n", file);
149*9a747e4fSDavid du Colombier 		exits("open");
150*9a747e4fSDavid du Colombier 	}
151*9a747e4fSDavid du Colombier 
152*9a747e4fSDavid du Colombier 	rargv[0] = "ramfs";
153*9a747e4fSDavid du Colombier 	rargc = 1;
154*9a747e4fSDavid du Colombier 	if(stdin)
155*9a747e4fSDavid du Colombier 		rargv[rargc++] = "-i";
156*9a747e4fSDavid du Colombier 	rargv[rargc++] = "-m";
157*9a747e4fSDavid du Colombier 	rargv[rargc++] = mtpt;
158*9a747e4fSDavid du Colombier 	rargv[rargc] = nil;
159*9a747e4fSDavid du Colombier 	ramfsmain(rargc, rargv);
160*9a747e4fSDavid du Colombier 
161*9a747e4fSDavid du Colombier 	if(1 || strstr(file, "disk")) {	/* search for archive on block boundary */
162*9a747e4fSDavid du Colombier if(chatty) fprint(2, "searching for bz\n");
163*9a747e4fSDavid du Colombier 		for(i=0;; i++){
164*9a747e4fSDavid du Colombier 			if((n = readn(fd, blk, sizeof blk)) != sizeof blk)
165*9a747e4fSDavid du Colombier 				sysfatal("read %d gets %d: %r\n", i, n);
166*9a747e4fSDavid du Colombier 			if(strncmp(blk, "bzfilesystem\n", 13) == 0)
167*9a747e4fSDavid du Colombier 				break;
168*9a747e4fSDavid du Colombier 		}
169*9a747e4fSDavid du Colombier if(chatty) fprint(2, "found at %d\n", i);
170*9a747e4fSDavid du Colombier 	}
171*9a747e4fSDavid du Colombier 
172*9a747e4fSDavid du Colombier 	if(chdir(mtpt) < 0)
173*9a747e4fSDavid du Colombier 		error("chdir %s: %r", mtpt);
174*9a747e4fSDavid du Colombier 
175*9a747e4fSDavid du Colombier 	fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13)));
176*9a747e4fSDavid du Colombier 
177*9a747e4fSDavid du Colombier 	Binits(&bin, fd, OREAD, binbuf, sizeof binbuf);
178*9a747e4fSDavid du Colombier 	while(p = Brdline(&bin, '\n')){
179*9a747e4fSDavid du Colombier 		p[Blinelen(&bin)-1] = '\0';
180*9a747e4fSDavid du Colombier if(chatty) fprint(2, "%s\n", p);
181*9a747e4fSDavid du Colombier 		if(strcmp(p, "end of archive") == 0){
182*9a747e4fSDavid du Colombier 			_exits(0);
183*9a747e4fSDavid du Colombier 		}
184*9a747e4fSDavid du Colombier 		if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){
185*9a747e4fSDavid du Colombier 			warn("too few fields in file header");
186*9a747e4fSDavid du Colombier 			continue;
187*9a747e4fSDavid du Colombier 		}
188*9a747e4fSDavid du Colombier 		strcpy(namep, fields[0]);
189*9a747e4fSDavid du Colombier 		mode = strtoul(fields[1], 0, 8);
190*9a747e4fSDavid du Colombier 		mtime = strtoul(fields[4], 0, 10);
191*9a747e4fSDavid du Colombier 		bytes = strtoul(fields[5], 0, 10);
192*9a747e4fSDavid du Colombier 		strncpy(uid, fields[2], NAMELEN);
193*9a747e4fSDavid du Colombier 		strncpy(gid, fields[3], NAMELEN);
194*9a747e4fSDavid du Colombier 		if(mode & DMDIR)
195*9a747e4fSDavid du Colombier 			mkdir(name, mode, mtime, uid, gid);
196*9a747e4fSDavid du Colombier 		else
197*9a747e4fSDavid du Colombier 			extract(name, mode, mtime, uid, gid, bytes);
198*9a747e4fSDavid du Colombier 	}
199*9a747e4fSDavid du Colombier 	fprint(2, "premature end of archive\n");
200*9a747e4fSDavid du Colombier 	exits("premature end of archive");
201*9a747e4fSDavid du Colombier }
202*9a747e4fSDavid du Colombier 
203*9a747e4fSDavid du Colombier char buf[8192];
204*9a747e4fSDavid du Colombier 
205*9a747e4fSDavid du Colombier int
ffcreate(char * name,ulong mode,char * uid,char * gid,ulong mtime,int length)206*9a747e4fSDavid du Colombier ffcreate(char *name, ulong mode, char *uid, char *gid, ulong mtime, int length)
207*9a747e4fSDavid du Colombier {
208*9a747e4fSDavid du Colombier 	int fd, om;
209*9a747e4fSDavid du Colombier 	Dir nd;
210*9a747e4fSDavid du Colombier 
211*9a747e4fSDavid du Colombier 	sprint(buf, "%s/%s", mtpt, name);
212*9a747e4fSDavid du Colombier 	om = ORDWR;
213*9a747e4fSDavid du Colombier 	if(mode&DMDIR)
214*9a747e4fSDavid du Colombier 		om = OREAD;
215*9a747e4fSDavid du Colombier 	if((fd = create(buf, om, (mode&DMDIR)|0666)) < 0)
216*9a747e4fSDavid du Colombier 		error("create %s: %r", buf);
217*9a747e4fSDavid du Colombier 
218*9a747e4fSDavid du Colombier 	nulldir(&nd);
219*9a747e4fSDavid du Colombier 	nd.mode = mode;
220*9a747e4fSDavid du Colombier 	nd.uid = uid;
221*9a747e4fSDavid du Colombier 	nd.gid = gid;
222*9a747e4fSDavid du Colombier 	nd.mtime = mtime;
223*9a747e4fSDavid du Colombier 	if(length)
224*9a747e4fSDavid du Colombier 		nd.length = length;
225*9a747e4fSDavid du Colombier 	if(dirfwstat(fd, &nd) < 0)
226*9a747e4fSDavid du Colombier 		error("fwstat %s: %r", buf);
227*9a747e4fSDavid du Colombier 
228*9a747e4fSDavid du Colombier 	return fd;
229*9a747e4fSDavid du Colombier }
230*9a747e4fSDavid du Colombier 
231*9a747e4fSDavid du Colombier void
mkdir(char * name,ulong mode,ulong mtime,char * uid,char * gid)232*9a747e4fSDavid du Colombier mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
233*9a747e4fSDavid du Colombier {
234*9a747e4fSDavid du Colombier 	close(ffcreate(name, mode, uid, gid, mtime, 0));
235*9a747e4fSDavid du Colombier }
236*9a747e4fSDavid du Colombier 
237*9a747e4fSDavid du Colombier void
extract(char * name,ulong mode,ulong mtime,char * uid,char * gid,ulong bytes)238*9a747e4fSDavid du Colombier extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes)
239*9a747e4fSDavid du Colombier {
240*9a747e4fSDavid du Colombier 	int fd, tot, n;
241*9a747e4fSDavid du Colombier 
242*9a747e4fSDavid du Colombier 	fd = ffcreate(name, mode, uid, gid, mtime, bytes);
243*9a747e4fSDavid du Colombier 
244*9a747e4fSDavid du Colombier 	for(tot = 0; tot < bytes; tot += n){
245*9a747e4fSDavid du Colombier 		n = sizeof buf;
246*9a747e4fSDavid du Colombier 		if(tot + n > bytes)
247*9a747e4fSDavid du Colombier 			n = bytes - tot;
248*9a747e4fSDavid du Colombier 		n = Bread(&bin, buf, n);
249*9a747e4fSDavid du Colombier 		if(n <= 0)
250*9a747e4fSDavid du Colombier 			error("premature eof reading %s", name);
251*9a747e4fSDavid du Colombier 		if(write(fd, buf, n) != n)
252*9a747e4fSDavid du Colombier 			error("short write writing %s", name);
253*9a747e4fSDavid du Colombier 	}
254*9a747e4fSDavid du Colombier 	close(fd);
255*9a747e4fSDavid du Colombier }
256*9a747e4fSDavid du Colombier 
257*9a747e4fSDavid du Colombier void
error(char * fmt,...)258*9a747e4fSDavid du Colombier error(char *fmt, ...)
259*9a747e4fSDavid du Colombier {
260*9a747e4fSDavid du Colombier 	char buf[1024];
261*9a747e4fSDavid du Colombier 	va_list arg;
262*9a747e4fSDavid du Colombier 
263*9a747e4fSDavid du Colombier 	sprint(buf, "%s: ", argv0);
264*9a747e4fSDavid du Colombier 	va_start(arg, fmt);
265*9a747e4fSDavid du Colombier 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
266*9a747e4fSDavid du Colombier 	va_end(arg);
267*9a747e4fSDavid du Colombier 	fprint(2, "%s\n", buf);
268*9a747e4fSDavid du Colombier 	exits(0);
269*9a747e4fSDavid du Colombier }
270*9a747e4fSDavid du Colombier 
271*9a747e4fSDavid du Colombier void
warn(char * fmt,...)272*9a747e4fSDavid du Colombier warn(char *fmt, ...)
273*9a747e4fSDavid du Colombier {
274*9a747e4fSDavid du Colombier 	char buf[1024];
275*9a747e4fSDavid du Colombier 	va_list arg;
276*9a747e4fSDavid du Colombier 
277*9a747e4fSDavid du Colombier 	sprint(buf, "%s: ", argv0);
278*9a747e4fSDavid du Colombier 	va_start(arg, fmt);
279*9a747e4fSDavid du Colombier 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
280*9a747e4fSDavid du Colombier 	va_end(arg);
281*9a747e4fSDavid du Colombier 	fprint(2, "%s\n", buf);
282*9a747e4fSDavid du Colombier }
283*9a747e4fSDavid du Colombier 
284*9a747e4fSDavid du Colombier int
_efgfmt(Fmt *)285*9a747e4fSDavid du Colombier _efgfmt(Fmt*)
286*9a747e4fSDavid du Colombier {
287*9a747e4fSDavid du Colombier 	return -1;
288*9a747e4fSDavid du Colombier }
289