xref: /plan9/sys/src/cmd/replica/updatedb.c (revision 41ac1ab6ba97d8749fe58c188f657e9c0515bf1f)
19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier  * generate a list of files and their metadata
39a747e4fSDavid du Colombier  * using a given proto file.
49a747e4fSDavid du Colombier  */
59a747e4fSDavid du Colombier #include "all.h"
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier int changesonly;
89a747e4fSDavid du Colombier char *uid;
99a747e4fSDavid du Colombier Db *db;
109a747e4fSDavid du Colombier Biobuf blog;
119a747e4fSDavid du Colombier ulong now;
129a747e4fSDavid du Colombier int n;
139a747e4fSDavid du Colombier char **x;
149a747e4fSDavid du Colombier int nx;
159a747e4fSDavid du Colombier int justlog;
169a747e4fSDavid du Colombier char *root=".";
179a747e4fSDavid du Colombier char **match;
189a747e4fSDavid du Colombier int nmatch;
199a747e4fSDavid du Colombier 
209a747e4fSDavid du Colombier int
ismatch(char * s)219a747e4fSDavid du Colombier ismatch(char *s)
229a747e4fSDavid du Colombier {
239a747e4fSDavid du Colombier 	int i, len;
249a747e4fSDavid du Colombier 
259a747e4fSDavid du Colombier 	if(nmatch == 0)
269a747e4fSDavid du Colombier 		return 1;
279a747e4fSDavid du Colombier 	for(i=0; i<nmatch; i++){
289a747e4fSDavid du Colombier 		if(strcmp(s, match[i]) == 0)
299a747e4fSDavid du Colombier 			return 1;
309a747e4fSDavid du Colombier 		len = strlen(match[i]);
319a747e4fSDavid du Colombier 		if(strncmp(s, match[i], len) == 0 && s[len]=='/')
329a747e4fSDavid du Colombier 			return 1;
339a747e4fSDavid du Colombier 	}
349a747e4fSDavid du Colombier 	return 0;
359a747e4fSDavid du Colombier }
369a747e4fSDavid du Colombier 
379a747e4fSDavid du Colombier void
xlog(int c,char * name,Dir * d)389a747e4fSDavid du Colombier xlog(int c, char *name, Dir *d)
399a747e4fSDavid du Colombier {
409a747e4fSDavid du Colombier 	char *dname;
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier 	dname = d->name;
439a747e4fSDavid du Colombier 	if(strcmp(dname, name) == 0)
449a747e4fSDavid du Colombier 		dname = "-";
459a747e4fSDavid du Colombier 	if(!justlog)
469a747e4fSDavid du Colombier 		Bprint(&blog, "%lud %d ", now, n++);
479a747e4fSDavid du Colombier 	Bprint(&blog, "%c %q %q %luo %q %q %lud %lld\n",
489a747e4fSDavid du Colombier 		c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length);
499a747e4fSDavid du Colombier }
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier void
walk(char * new,char * old,Dir * xd,void *)529a747e4fSDavid du Colombier walk(char *new, char *old, Dir *xd, void*)
539a747e4fSDavid du Colombier {
549a747e4fSDavid du Colombier 	int i, change, len;
559a747e4fSDavid du Colombier 	Dir od, d;
569a747e4fSDavid du Colombier 
573ff48bf5SDavid du Colombier 	new = unroot(new, "/");
583ff48bf5SDavid du Colombier 	old = unroot(old, root);
593ff48bf5SDavid du Colombier 
609a747e4fSDavid du Colombier 	if(!ismatch(new))
619a747e4fSDavid du Colombier 		return;
629a747e4fSDavid du Colombier 	for(i=0; i<nx; i++){
639a747e4fSDavid du Colombier 		if(strcmp(new, x[i]) == 0)
649a747e4fSDavid du Colombier 			return;
659a747e4fSDavid du Colombier 		len = strlen(x[i]);
669a747e4fSDavid du Colombier 		if(strncmp(new, x[i], len)==0 && new[len]=='/')
679a747e4fSDavid du Colombier 			return;
689a747e4fSDavid du Colombier 	}
699a747e4fSDavid du Colombier 
709a747e4fSDavid du Colombier 	d = *xd;
719a747e4fSDavid du Colombier 	d.name = old;
729a747e4fSDavid du Colombier 	memset(&od, 0, sizeof od);
739a747e4fSDavid du Colombier 	change = 0;
749a747e4fSDavid du Colombier 	if(markdb(db, new, &od) < 0){
759a747e4fSDavid du Colombier 		if(!changesonly){
769a747e4fSDavid du Colombier 			xlog('a', new, &d);
779a747e4fSDavid du Colombier 			change = 1;
789a747e4fSDavid du Colombier 		}
799a747e4fSDavid du Colombier 	}else{
809a747e4fSDavid du Colombier 		if((d.mode&DMDIR)==0 && (od.mtime!=d.mtime || od.length!=d.length)){
819a747e4fSDavid du Colombier 			xlog('c', new, &d);
829a747e4fSDavid du Colombier 			change = 1;
839a747e4fSDavid du Colombier 		}
849a747e4fSDavid du Colombier 		if((!uid&&strcmp(od.uid,d.uid)!=0)
859a747e4fSDavid du Colombier 		|| strcmp(od.gid,d.gid)!=0
869a747e4fSDavid du Colombier 		|| od.mode!=d.mode){
879a747e4fSDavid du Colombier 			xlog('m', new, &d);
889a747e4fSDavid du Colombier 			change = 1;
899a747e4fSDavid du Colombier 		}
909a747e4fSDavid du Colombier 	}
919a747e4fSDavid du Colombier 	if(!justlog && change){
929a747e4fSDavid du Colombier 		if(uid)
939a747e4fSDavid du Colombier 			d.uid = uid;
949a747e4fSDavid du Colombier 		d.muid = "mark";	/* mark bit */
959a747e4fSDavid du Colombier 		insertdb(db, new, &d);
969a747e4fSDavid du Colombier 	}
979a747e4fSDavid du Colombier }
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier void
warn(char * msg,void *)100*41ac1ab6SDavid du Colombier warn(char *msg, void*)
101*41ac1ab6SDavid du Colombier {
102*41ac1ab6SDavid du Colombier 	char *p;
103*41ac1ab6SDavid du Colombier 
104*41ac1ab6SDavid du Colombier 	fprint(2, "warning: %s\n", msg);
105*41ac1ab6SDavid du Colombier 
106*41ac1ab6SDavid du Colombier 	/* find the %r in "can't open foo: %r" */
107*41ac1ab6SDavid du Colombier 	p = strstr(msg, ": ");
108*41ac1ab6SDavid du Colombier 	if(p)
109*41ac1ab6SDavid du Colombier 		p += 2;
110*41ac1ab6SDavid du Colombier 
111*41ac1ab6SDavid du Colombier 	/*
112*41ac1ab6SDavid du Colombier 	 * if the error is about a remote server failing,
113*41ac1ab6SDavid du Colombier 	 * then there's no point in continuing to look
114*41ac1ab6SDavid du Colombier 	 * for changes -- we'll think everything got deleted!
115*41ac1ab6SDavid du Colombier 	 *
116*41ac1ab6SDavid du Colombier 	 * actual errors i see are:
117*41ac1ab6SDavid du Colombier 	 *	"i/o on hungup channel" for a local hangup
118*41ac1ab6SDavid du Colombier 	 *	"i/o on hungup channel" for a timeout (yank the network wire)
119*41ac1ab6SDavid du Colombier 	 *	"'/n/sources/plan9' Hangup" for a remote hangup
120*41ac1ab6SDavid du Colombier 	 * the rest is paranoia.
121*41ac1ab6SDavid du Colombier 	 */
122*41ac1ab6SDavid du Colombier 	if(p){
123*41ac1ab6SDavid du Colombier 		if(cistrstr(p, "hungup") || cistrstr(p, "Hangup")
124*41ac1ab6SDavid du Colombier 		|| cistrstr(p, "rpc error")
125*41ac1ab6SDavid du Colombier 		|| cistrstr(p, "shut down")
126*41ac1ab6SDavid du Colombier 		|| cistrstr(p, "i/o")
127*41ac1ab6SDavid du Colombier 		|| cistrstr(p, "connection"))
128*41ac1ab6SDavid du Colombier 			sysfatal("suspected network or i/o error - bailing out");
129*41ac1ab6SDavid du Colombier 	}
130*41ac1ab6SDavid du Colombier }
131*41ac1ab6SDavid du Colombier 
132*41ac1ab6SDavid du Colombier void
usage(void)1339a747e4fSDavid du Colombier usage(void)
1349a747e4fSDavid du Colombier {
1359a747e4fSDavid du Colombier 	fprint(2, "usage: replica/updatedb [-c] [-p proto] [-r root] [-t now n] [-u uid] [-x path]... db [paths]\n");
1369a747e4fSDavid du Colombier 	exits("usage");
1379a747e4fSDavid du Colombier }
1389a747e4fSDavid du Colombier 
1399a747e4fSDavid du Colombier void
main(int argc,char ** argv)1409a747e4fSDavid du Colombier main(int argc, char **argv)
1419a747e4fSDavid du Colombier {
1429a747e4fSDavid du Colombier 	char *proto;
1439a747e4fSDavid du Colombier 	Avlwalk *w;
1449a747e4fSDavid du Colombier 	Dir d;
1459a747e4fSDavid du Colombier 	Entry *e;
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 	quotefmtinstall();
1489a747e4fSDavid du Colombier 	proto = "/sys/lib/sysconfig/proto/allproto";
1499a747e4fSDavid du Colombier 	now = time(0);
1509a747e4fSDavid du Colombier 	Binit(&blog, 1, OWRITE);
1519a747e4fSDavid du Colombier 	ARGBEGIN{
1529a747e4fSDavid du Colombier 	case 'c':
1539a747e4fSDavid du Colombier 		changesonly = 1;
1549a747e4fSDavid du Colombier 		break;
1559a747e4fSDavid du Colombier 	case 'l':
1569a747e4fSDavid du Colombier 		justlog = 1;
1579a747e4fSDavid du Colombier 		break;
1589a747e4fSDavid du Colombier 	case 'p':
1599a747e4fSDavid du Colombier 		proto = EARGF(usage());
1609a747e4fSDavid du Colombier 		break;
1619a747e4fSDavid du Colombier 	case 'r':
1629a747e4fSDavid du Colombier 		root = EARGF(usage());
1639a747e4fSDavid du Colombier 		break;
1649a747e4fSDavid du Colombier 	case 't':
1659a747e4fSDavid du Colombier 		now = strtoul(EARGF(usage()), 0, 0);
1669a747e4fSDavid du Colombier 		n = atoi(EARGF(usage()));
1679a747e4fSDavid du Colombier 		break;
1689a747e4fSDavid du Colombier 	case 'u':
1699a747e4fSDavid du Colombier 		uid = EARGF(usage());
1709a747e4fSDavid du Colombier 		break;
1719a747e4fSDavid du Colombier 	case 'x':
1729a747e4fSDavid du Colombier 		if(nx%16 == 0)
1739a747e4fSDavid du Colombier 			x = erealloc(x, (nx+16)*sizeof(x[0]));
1749a747e4fSDavid du Colombier 		x[nx++] = EARGF(usage());
1759a747e4fSDavid du Colombier 		break;
1769a747e4fSDavid du Colombier 	default:
1779a747e4fSDavid du Colombier 		usage();
1789a747e4fSDavid du Colombier 	}ARGEND
1799a747e4fSDavid du Colombier 
1809a747e4fSDavid du Colombier 	if(argc <1)
1819a747e4fSDavid du Colombier 		usage();
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	match = argv+1;
1849a747e4fSDavid du Colombier 	nmatch = argc-1;
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier 	db = opendb(argv[0]);
187*41ac1ab6SDavid du Colombier 	if(rdproto(proto, root, walk, warn, nil) < 0)
1889a747e4fSDavid du Colombier 		sysfatal("rdproto: %r");
1899a747e4fSDavid du Colombier 
1909a747e4fSDavid du Colombier 	if(!changesonly){
1919a747e4fSDavid du Colombier 		w = avlwalk(db->avl);
192867bfcc6SDavid du Colombier 		while(e = (Entry*)avlprev(w)){
1939a747e4fSDavid du Colombier 			if(!ismatch(e->name))
1949a747e4fSDavid du Colombier 				continue;
1959a747e4fSDavid du Colombier 			if(!e->d.mark){		/* not visited during walk */
1969a747e4fSDavid du Colombier 				memset(&d, 0, sizeof d);
1979a747e4fSDavid du Colombier 				d.name = e->d.name;
1989a747e4fSDavid du Colombier 				d.uid = e->d.uid;
1999a747e4fSDavid du Colombier 				d.gid = e->d.gid;
2009a747e4fSDavid du Colombier 				d.mtime = e->d.mtime;
2019a747e4fSDavid du Colombier 				d.mode = e->d.mode;
2029a747e4fSDavid du Colombier 				xlog('d', e->name, &d);
2039a747e4fSDavid du Colombier 				if(!justlog)
2049a747e4fSDavid du Colombier 					removedb(db, e->name);
2059a747e4fSDavid du Colombier 			}
2069a747e4fSDavid du Colombier 		}
2079a747e4fSDavid du Colombier 	}
2089a747e4fSDavid du Colombier 
2099a747e4fSDavid du Colombier 	if(Bterm(&blog) < 0)
2109a747e4fSDavid du Colombier 		sysfatal("writing output: %r");
2119a747e4fSDavid du Colombier 
2129a747e4fSDavid du Colombier 	exits(nil);
2139a747e4fSDavid du Colombier }
2149a747e4fSDavid du Colombier 
215