223 lines · 4.2 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * generate a list of files and their metadata * using a given proto file. */#include "all.h" int changesonly;char *uid;Db *db;Biobuf blog;ulong now;int n;char **x;int nx;int justlog;char *root=".";char **match;int nmatch; intismatch(char *s){	int i, len; 	if(nmatch == 0)		return 1;	for(i=0; i<nmatch; i++){		if(strcmp(s, match[i]) == 0)			return 1;		len = strlen(match[i]);		if(strncmp(s, match[i], len) == 0 && s[len]=='/')			return 1;	}	return 0;} voidxlog(int c, char *name, Dir *d){	char *dname; 	dname = d->name;	if(strcmp(dname, name) == 0)		dname = "-";	if(!justlog)		Bprint(&blog, "%lud %d ", now, n++);	Bprint(&blog, "%c %q %q %luo %q %q %lud %lld\n",		c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length);} voidwalk(char *new, char *old, Dir *xd, void*){	int i, change, len;	Dir od, d; 	new = unroot(new, "/");	old = unroot(old, root); 	if(!ismatch(new))		return;	for(i=0; i<nx; i++){		if(strcmp(new, x[i]) == 0)			return;		len = strlen(x[i]);		if(strncmp(new, x[i], len)==0 && new[len]=='/')			return;	} 	d = *xd;	d.name = old;	memset(&od, 0, sizeof od);	change = 0;	if(markdb(db, new, &od) < 0){		if(!changesonly){			xlog('a', new, &d);			change = 1;		}	}else{		if((d.mode&DMDIR)==0 && (od.mtime!=d.mtime || od.length!=d.length)){			xlog('c', new, &d);			change = 1;		}		if((!uid&&strcmp(od.uid,d.uid)!=0)		|| strcmp(od.gid,d.gid)!=0 		|| od.mode!=d.mode){			xlog('m', new, &d);			change = 1;		}	}	if(!justlog && change){		if(uid)			d.uid = uid;		d.muid = "mark";	/* mark bit */		insertdb(db, new, &d);	}} voidwarn(char *msg, void*){	char *p; 	fprint(2, "warning: %s\n", msg); 	/* find the %r in "can't open foo: %r" */	p = strstr(msg, ": ");	if(p)		p += 2; 	/*	 * if the error is about a remote server failing,	 * then there's no point in continuing to look	 * for changes -- we'll think everything got deleted!	 *	 * actual errors i see are:	 *	"i/o on hungup channel" for a local hangup	 *	"i/o on hungup channel" for a timeout (yank the network wire)	 *	"'/n/sources/plan9' Hangup" for a remote hangup	 * the rest is paranoia.	 */	if(p){		if(cistrstr(p, "hungup") || cistrstr(p, "Hangup")		|| cistrstr(p, "rpc error")		|| cistrstr(p, "shut down")		|| cistrstr(p, "i/o")		|| cistrstr(p, "connection"))			sysfatal("suspected network or i/o error - bailing out");	}} voidusage(void){	fprint(2, "usage: replica/updatedb [-c] [-p proto] [-r root] [-t now n] [-u uid] [-x path]... db [paths]\n");	exits("usage");} voidmain(int argc, char **argv){	char *proto;	Avlwalk *w;	Dir d;	Entry *e; 	quotefmtinstall();	proto = "/sys/lib/sysconfig/proto/allproto";	now = time(0);	Binit(&blog, 1, OWRITE);	ARGBEGIN{	case 'c':		changesonly = 1;		break;	case 'l':		justlog = 1;		break;	case 'p':		proto = EARGF(usage());		break;	case 'r':		root = EARGF(usage());		break;	case 't':		now = strtoul(EARGF(usage()), 0, 0);		n = atoi(EARGF(usage()));		break;	case 'u':		uid = EARGF(usage());		break;	case 'x':		if(nx%16 == 0)			x = erealloc(x, (nx+16)*sizeof(x[0]));		x[nx++] = EARGF(usage());		break;	default:		usage();	}ARGEND 	if(argc <1)		usage(); 	match = argv+1;	nmatch = argc-1; 	db = opendb(argv[0]);	if(rdproto(proto, root, walk, warn, nil) < 0)		sysfatal("rdproto: %r"); 	if(!changesonly){		w = avlwalk(db->avl);		while(e = (Entry*)avlprev(w)){			if(!ismatch(e->name))				continue;			if(!e->d.mark){		/* not visited during walk */				memset(&d, 0, sizeof d);				d.name = e->d.name;				d.uid = e->d.uid;				d.gid = e->d.gid;				d.mtime = e->d.mtime;				d.mode = e->d.mode;				xlog('d', e->name, &d);				if(!justlog)					removedb(db, e->name);			}		}	} 	if(Bterm(&blog) < 0)		sysfatal("writing output: %r"); 	exits(nil);}