xref: /plan9/sys/src/cmd/archfs.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * archfs - mount mkfs style archives
37dd7cddfSDavid du Colombier  */
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier #include <u.h>
67dd7cddfSDavid du Colombier #include <libc.h>
77dd7cddfSDavid du Colombier #include <bio.h>
87dd7cddfSDavid du Colombier #include <auth.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <thread.h>
117dd7cddfSDavid du Colombier #include <9p.h>
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier Tree *archtree;
147dd7cddfSDavid du Colombier Biobuf *b;
157dd7cddfSDavid du Colombier int verbose;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier typedef struct Ahdr Ahdr;
187dd7cddfSDavid du Colombier struct Ahdr {
197dd7cddfSDavid du Colombier 	char *name;
207dd7cddfSDavid du Colombier 	Dir;
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier typedef struct Arch Arch;
247dd7cddfSDavid du Colombier struct Arch {
257dd7cddfSDavid du Colombier 	vlong off;
267dd7cddfSDavid du Colombier 	vlong length;
277dd7cddfSDavid du Colombier };
287dd7cddfSDavid du Colombier 
2959cc4ca5SDavid du Colombier static void*
emalloc(long sz)3059cc4ca5SDavid du Colombier emalloc(long sz)
3159cc4ca5SDavid du Colombier {
3259cc4ca5SDavid du Colombier 	void *v;
3359cc4ca5SDavid du Colombier 
3459cc4ca5SDavid du Colombier 	v = malloc(sz);
3559cc4ca5SDavid du Colombier 	if(v == nil)
36*14cc0f53SDavid du Colombier 		sysfatal("malloc %lud fails", sz);
3759cc4ca5SDavid du Colombier 	memset(v, 0, sz);
3859cc4ca5SDavid du Colombier 	return v;
3959cc4ca5SDavid du Colombier }
4059cc4ca5SDavid du Colombier 
4159cc4ca5SDavid du Colombier static char*
estrdup(char * s)4259cc4ca5SDavid du Colombier estrdup(char *s)
4359cc4ca5SDavid du Colombier {
4459cc4ca5SDavid du Colombier 	s = strdup(s);
4559cc4ca5SDavid du Colombier 	if(s == nil)
46*14cc0f53SDavid du Colombier 		sysfatal("strdup (%.10s) fails", s);
4759cc4ca5SDavid du Colombier 	return s;
4859cc4ca5SDavid du Colombier }
4959cc4ca5SDavid du Colombier 
507dd7cddfSDavid du Colombier static char*
Bgetline(Biobuf * b)517dd7cddfSDavid du Colombier Bgetline(Biobuf *b)
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier 	char *p;
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier 	if(p = Brdline(b, '\n'))
567dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = '\0';
577dd7cddfSDavid du Colombier 	return p;
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier Ahdr*
gethdr(Biobuf * b)617dd7cddfSDavid du Colombier gethdr(Biobuf *b)
627dd7cddfSDavid du Colombier {
637dd7cddfSDavid du Colombier 	Ahdr *a;
647dd7cddfSDavid du Colombier 	char *p, *f[10];
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier 	if((p = Bgetline(b)) == nil)
677dd7cddfSDavid du Colombier 		return nil;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	if(strcmp(p, "end of archive") == 0) {
707dd7cddfSDavid du Colombier 		werrstr("");
717dd7cddfSDavid du Colombier 		return nil;
727dd7cddfSDavid du Colombier 	}
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier 	if(tokenize(p, f, nelem(f)) != 6) {
757dd7cddfSDavid du Colombier 		werrstr("bad format");
767dd7cddfSDavid du Colombier 		return nil;
777dd7cddfSDavid du Colombier 	}
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	a = emalloc(sizeof(*a));
807dd7cddfSDavid du Colombier 	a->name = estrdup(f[0]);
817dd7cddfSDavid du Colombier 	a->mode = strtoul(f[1], 0, 8);
829a747e4fSDavid du Colombier 	a->uid = estrdup(f[2]);
839a747e4fSDavid du Colombier 	a->gid = estrdup(f[3]);
847dd7cddfSDavid du Colombier 	a->mtime = strtoll(f[4], 0, 10);
857dd7cddfSDavid du Colombier 	a->length = strtoll(f[5], 0, 10);
867dd7cddfSDavid du Colombier 	return a;
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier static Arch*
newarch(vlong off,vlong length)907dd7cddfSDavid du Colombier newarch(vlong off, vlong length)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	static Arch *abuf;
937dd7cddfSDavid du Colombier 	static int nabuf;
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	if(nabuf == 0) {
967dd7cddfSDavid du Colombier 		nabuf = 256;
977dd7cddfSDavid du Colombier 		abuf = emalloc(sizeof(Arch)*nabuf);
987dd7cddfSDavid du Colombier 	}
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier 	nabuf--;
1017dd7cddfSDavid du Colombier 	abuf->off = off;
1027dd7cddfSDavid du Colombier 	abuf->length = length;
1037dd7cddfSDavid du Colombier 	return abuf++;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier static File*
createpath(File * f,char * name,char * u,ulong m)1079a747e4fSDavid du Colombier createpath(File *f, char *name, char *u, ulong m)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	char *p;
1107dd7cddfSDavid du Colombier 	File *nf;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	if(verbose)
1139a747e4fSDavid du Colombier 		fprint(2, "createpath %s\n", name);
1149a747e4fSDavid du Colombier 	incref(f);
1157dd7cddfSDavid du Colombier 	while(f && (p = strchr(name, '/'))) {
1169a747e4fSDavid du Colombier 		*p = '\0';
1179a747e4fSDavid du Colombier 		if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){
1187dd7cddfSDavid du Colombier 			/* this would be a race if we were multithreaded */
1199a747e4fSDavid du Colombier 			incref(f);	/* so walk doesn't kill it immediately on failure */
1209a747e4fSDavid du Colombier 			if((nf = walkfile(f, name)) == nil)
1219a747e4fSDavid du Colombier 				nf = createfile(f, name, u, DMDIR|0777, nil);
1229a747e4fSDavid du Colombier 			decref(f);
12359cc4ca5SDavid du Colombier 			f = nf;
1247dd7cddfSDavid du Colombier 		}
1259a747e4fSDavid du Colombier 		*p = '/';
1269a747e4fSDavid du Colombier 		name = p+1;
1279a747e4fSDavid du Colombier 	}
1287dd7cddfSDavid du Colombier 	if(f == nil)
1297dd7cddfSDavid du Colombier 		return nil;
1307dd7cddfSDavid du Colombier 
1319a747e4fSDavid du Colombier 	incref(f);
1329a747e4fSDavid du Colombier 	if((nf = walkfile(f, name)) == nil)
1339a747e4fSDavid du Colombier 		nf = createfile(f, name, u, m, nil);
1349a747e4fSDavid du Colombier 	decref(f);
1357dd7cddfSDavid du Colombier 	return nf;
1367dd7cddfSDavid du Colombier }
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier static void
archcreatefile(char * name,Arch * arch,Dir * d)1399a747e4fSDavid du Colombier archcreatefile(char *name, Arch *arch, Dir *d)
1407dd7cddfSDavid du Colombier {
1417dd7cddfSDavid du Colombier 	File *f;
1429a747e4fSDavid du Colombier 	f = createpath(archtree->root, name, d->uid, d->mode);
1437dd7cddfSDavid du Colombier 	if(f == nil)
1447dd7cddfSDavid du Colombier 		sysfatal("creating %s: %r", name);
1459a747e4fSDavid du Colombier 	free(f->gid);
1469a747e4fSDavid du Colombier 	f->gid = estrdup9p(d->gid);
1477dd7cddfSDavid du Colombier 	f->aux = arch;
1487dd7cddfSDavid du Colombier 	f->mtime = d->mtime;
1497dd7cddfSDavid du Colombier 	f->length = d->length;
1509a747e4fSDavid du Colombier 	decref(f);
1517dd7cddfSDavid du Colombier }
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier static void
fsread(Req * r)1549a747e4fSDavid du Colombier fsread(Req *r)
1557dd7cddfSDavid du Colombier {
1567dd7cddfSDavid du Colombier 	Arch *a;
1579a747e4fSDavid du Colombier 	char err[ERRMAX];
1589a747e4fSDavid du Colombier 	int n;
1597dd7cddfSDavid du Colombier 
1609a747e4fSDavid du Colombier 	a = r->fid->file->aux;
1619a747e4fSDavid du Colombier 	if(a->length <= r->ifcall.offset)
1629a747e4fSDavid du Colombier 		r->ifcall.count = 0;
1639a747e4fSDavid du Colombier 	else if(a->length <= r->ifcall.offset+r->ifcall.count)
1649a747e4fSDavid du Colombier 		r->ifcall.count = a->length - r->ifcall.offset;
1657dd7cddfSDavid du Colombier 
1669a747e4fSDavid du Colombier 	werrstr("unknown error");
1679a747e4fSDavid du Colombier 	if(Bseek(b, a->off+r->ifcall.offset, 0) < 0
1689a747e4fSDavid du Colombier 	|| (n = Bread(b, r->ofcall.data, r->ifcall.count)) < 0) {
1697dd7cddfSDavid du Colombier 		err[0] = '\0';
1709a747e4fSDavid du Colombier 		errstr(err, sizeof err);
1717dd7cddfSDavid du Colombier 		respond(r, err);
1727dd7cddfSDavid du Colombier 	} else {
1739a747e4fSDavid du Colombier 		r->ofcall.count = n;
1747dd7cddfSDavid du Colombier 		respond(r, nil);
1757dd7cddfSDavid du Colombier 	}
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier 
1789a747e4fSDavid du Colombier Srv fs = {
1799a747e4fSDavid du Colombier 	.read=	fsread,
1807dd7cddfSDavid du Colombier };
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier static void
usage(void)1837dd7cddfSDavid du Colombier usage(void)
1847dd7cddfSDavid du Colombier {
1857dd7cddfSDavid du Colombier 	fprint(2, "usage: archfs [-abcC] [-m mtpt] archfile\n");
1867dd7cddfSDavid du Colombier 	exits("usage");
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier void
main(int argc,char ** argv)1907dd7cddfSDavid du Colombier main(int argc, char **argv)
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier 	Ahdr *a;
1937dd7cddfSDavid du Colombier 	ulong flag;
1947dd7cddfSDavid du Colombier 	char *mtpt;
1959a747e4fSDavid du Colombier 	char err[ERRMAX];
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	flag = 0;
1987dd7cddfSDavid du Colombier 	mtpt = "/mnt/arch";
1997dd7cddfSDavid du Colombier 	ARGBEGIN{
2009a747e4fSDavid du Colombier 	case 'D':
2019a747e4fSDavid du Colombier 		chatty9p++;
2029a747e4fSDavid du Colombier 		break;
2037dd7cddfSDavid du Colombier 	case 'a':
2047dd7cddfSDavid du Colombier 		flag |= MAFTER;
2057dd7cddfSDavid du Colombier 		break;
2067dd7cddfSDavid du Colombier 	case 'b':
2077dd7cddfSDavid du Colombier 		flag |= MBEFORE;
2087dd7cddfSDavid du Colombier 		break;
2097dd7cddfSDavid du Colombier 	case 'c':
2107dd7cddfSDavid du Colombier 		flag |= MCREATE;
2117dd7cddfSDavid du Colombier 		break;
2127dd7cddfSDavid du Colombier 	case 'C':
2137dd7cddfSDavid du Colombier 		flag |= MCACHE;
2147dd7cddfSDavid du Colombier 		break;
2157dd7cddfSDavid du Colombier 	case 'm':
216de8abbc9SDavid du Colombier 		mtpt = EARGF(usage());
2177dd7cddfSDavid du Colombier 		break;
2187dd7cddfSDavid du Colombier 	default:
2197dd7cddfSDavid du Colombier 		usage();
2207dd7cddfSDavid du Colombier 		break;
2217dd7cddfSDavid du Colombier 	}ARGEND;
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier 	if(argc != 1)
2247dd7cddfSDavid du Colombier 		usage();
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	if((b = Bopen(argv[0], OREAD)) == nil)
2277dd7cddfSDavid du Colombier 		sysfatal("open '%s': %r", argv[0]);
2287dd7cddfSDavid du Colombier 
2299a747e4fSDavid du Colombier 	archtree = fs.tree = alloctree("sys", "sys", DMDIR|0775, nil);
2307dd7cddfSDavid du Colombier 	while(a = gethdr(b)) {
2319a747e4fSDavid du Colombier 		archcreatefile(a->name, newarch(Boffset(b), a->length), a);
2327dd7cddfSDavid du Colombier 		Bseek(b, a->length, 1);
2337dd7cddfSDavid du Colombier 	}
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier 	err[0] = '\0';
2369a747e4fSDavid du Colombier 	errstr(err, sizeof err);
2377dd7cddfSDavid du Colombier 	if(err[0])
2387dd7cddfSDavid du Colombier 		sysfatal("reading archive: %s", err);
2397dd7cddfSDavid du Colombier 
2409a747e4fSDavid du Colombier 	postmountsrv(&fs, nil, mtpt, flag);
2417dd7cddfSDavid du Colombier 	exits(0);
2427dd7cddfSDavid du Colombier }
243