henesyinit from p9f0ed2a895 years agoHistory
218 lines · 4.6 KB · C
RawDownload
/* * wrap/update - create software package and updates */#include <u.h>#include <libc.h>#include <bio.h>#include <disk.h>#include <libsec.h>#include "wrap.h" char *root = "/";char *desc;char *proto;int verbose;int update;int debug;int listonly; Wrap *w;char **prefix;int nprefix; Biobuf bmd5;Biobuf barch;Biobuf bstdout; static voidmkarch(char *new, char *old, Dir *d, void*){	uchar digest[MD5dlen];	vlong t; 	if(match(new, prefix, nprefix) == 0)		return; 	if(md5file(old, digest) < 0)		sysfatal("cannot open %s: %r", old);	if(getfileinfo(w, new, &t, digest, nil) >= 0)		return; 	if(listonly) {		if((d->mode & CHDIR) == 0) 			Bprint(&bstdout, "%s\n", new);		return;	} 	Bputhdr(&barch, new, d);	if((d->mode & CHDIR) == 0) {		Bprint(&bmd5, "%s %M\n", new, digest);		if(Bcopyfile(&barch, old, d->length) < 0)			sysfatal("error copying %lld %s: %r\n", d->length, old);	}} voidusage(void){	fprint(2, "usage: wrap/create [-d desc] [-p proto] [-r root] [-t time] [-lv] name\n");	fprint(2, "or  wrap/create -u [-d desc] [-p proto] [-r root] [-t time] [-lv] old-package [prefix...]\n");	exits("usage");} /* * creating an archive goes through the following steps: * *	process proto, writing md5 sums to /tmp/wrap.md5.* and *		the archive to /tmp/wrap.arch.*. *	sort /tmp/wrap.md5.* into /tmp/wrap.md5sort.* *	write an archive to stdout that begins with the md5 list *		and other wrap files, and then continues with /tmp/wrap.arch.*. * * the pain of making sure the wrap metadata is at the beginning * of the archive means that we can access it in gzipped archives without * needing to gunzip the whole thing. * * we used to use an algorithm that processed the proto twice, once * to create the md5 sum file and once to create the archive. * it's much better to copy the archive to a temporary file since you * can put it in ramfs, you avoid walking the entire tree again, * and prefetching can help you if you're not using ramfs. */voidmain(int argc, char **argv){	char *name, md5file[2*NAMELEN], md5sort[2*NAMELEN], tmparch[2*NAMELEN],		rmfile[2*NAMELEN], *p, *q;	Biobuf bout;	vlong t, archlen;	int archfd, fd; 	t = time(0);	ARGBEGIN{	case 'D':		debug = 1;		break;	case 'd':		desc = ARGF();		break;	case 'l':		listonly = 1;		break;	case 'p':		proto = ARGF();		break;	case 'r':		root = ARGF();		break;	case 't':		t = strtoll(ARGF(), 0, 10);		break;	case 'u':		update = 1;		break;	case 'v':		verbose = 1;		break;	default:		usage();	}ARGEND 	rfork(RFNAMEG);	fmtinstall('M', md5conv); 	if(!update && argc != 1)		usage(); 	if(update) {		prefix = argv+1;		nprefix = argc-1;	} 	if(update) { 		w = openwraphdr(argv[0], root, nil, 0);		if(w == nil)			sysfatal("no such package found"); 		/* ignore any updates */		while(w->nu > 0 && w->u[w->nu-1].type == UPD)			w->nu--; 		if(proto == nil)			proto = mkpath(w->u->dir, "proto");		name = w->name;	} else {		name = argv[0];		if(strlen(name) >= NAMELEN)			sysfatal("name '%s' too long", name);		if(proto == nil)			proto = "/sys/lib/sysconfig/proto/allproto";	} 	if(access(proto, AREAD) < 0)		sysfatal("cannot read proto: %r"); 	if(listonly) {		Binit(&bstdout, 1, OWRITE);		if(rdproto(proto, root, mkarch, nil, nil) < 0)			sysfatal("rdproto: %r");		Bterm(&bstdout);		exits(nil);	}		strcpy(md5file, "/tmp/wrap.md5.XXXXXX");	fd = opentemp(md5file);	Binit(&bmd5, fd, OWRITE); 	strcpy(tmparch, "/tmp/wrap.arch.XXXXXX");	archfd = opentemp(tmparch);	Binit(&barch, archfd, OWRITE); 	if(rdproto(proto, root, mkarch, nil, nil) < 0)		sysfatal("rdproto: %r");	Bflush(&bmd5);	Bterm(&bmd5);	Bflush(&barch);	archlen = Boffset(&barch);	Bterm(&barch); 	strcpy(md5sort, "/tmp/wrap.md5sort.XXXXXX");	fd = opentemp(md5sort);	fsort(fd, md5file); 	if(update) {		strcpy(rmfile, "/tmp/wrap.rm.XXXXXX");		fd = opentemp(rmfile);		Bseek(w->u->bmd5, 0, 0);		while(p = Bgetline(w->u->bmd5)) {			if(match(p, prefix, nprefix) == 0)				continue;			if(q = strchr(p, ' '))				*q = 0;			q = mkpath(root, p);			if(access(q, 0) < 0)				fprint(fd, "%s\n", p);			free(q);			free(p);		}	} 	Binit(&bout, 1, OWRITE);	if(update)		Bputwrap(&bout, name, t, desc, w->tfull, nprefix==0);	else		Bputwrap(&bout, name, t, desc, 0, 1);	Bputwrapfile(&bout, name, t, "proto", proto);	Bputwrapfile(&bout, name, t, "md5sum", md5sort);	if(update)		Bputwrapfile(&bout, name, t, "remove", rmfile); 	seek(archfd, 0, 0);	/* Binit assumes this */	Binit(&barch, archfd, OREAD);	if(Bcopy(&bout, &barch, archlen) < 0)		sysfatal("copy of temp file did not succeed: %lld %lld", Boffset(&barch), archlen); 	Bprint(&bout, "end of archive\n");	Bterm(&bout);	exits(0);}