xref: /plan9/sys/src/cmd/replica/updatedb.c (revision 41ac1ab6ba97d8749fe58c188f657e9c0515bf1f)
1 /*
2  * generate a list of files and their metadata
3  * using a given proto file.
4  */
5 #include "all.h"
6 
7 int changesonly;
8 char *uid;
9 Db *db;
10 Biobuf blog;
11 ulong now;
12 int n;
13 char **x;
14 int nx;
15 int justlog;
16 char *root=".";
17 char **match;
18 int nmatch;
19 
20 int
ismatch(char * s)21 ismatch(char *s)
22 {
23 	int i, len;
24 
25 	if(nmatch == 0)
26 		return 1;
27 	for(i=0; i<nmatch; i++){
28 		if(strcmp(s, match[i]) == 0)
29 			return 1;
30 		len = strlen(match[i]);
31 		if(strncmp(s, match[i], len) == 0 && s[len]=='/')
32 			return 1;
33 	}
34 	return 0;
35 }
36 
37 void
xlog(int c,char * name,Dir * d)38 xlog(int c, char *name, Dir *d)
39 {
40 	char *dname;
41 
42 	dname = d->name;
43 	if(strcmp(dname, name) == 0)
44 		dname = "-";
45 	if(!justlog)
46 		Bprint(&blog, "%lud %d ", now, n++);
47 	Bprint(&blog, "%c %q %q %luo %q %q %lud %lld\n",
48 		c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length);
49 }
50 
51 void
walk(char * new,char * old,Dir * xd,void *)52 walk(char *new, char *old, Dir *xd, void*)
53 {
54 	int i, change, len;
55 	Dir od, d;
56 
57 	new = unroot(new, "/");
58 	old = unroot(old, root);
59 
60 	if(!ismatch(new))
61 		return;
62 	for(i=0; i<nx; i++){
63 		if(strcmp(new, x[i]) == 0)
64 			return;
65 		len = strlen(x[i]);
66 		if(strncmp(new, x[i], len)==0 && new[len]=='/')
67 			return;
68 	}
69 
70 	d = *xd;
71 	d.name = old;
72 	memset(&od, 0, sizeof od);
73 	change = 0;
74 	if(markdb(db, new, &od) < 0){
75 		if(!changesonly){
76 			xlog('a', new, &d);
77 			change = 1;
78 		}
79 	}else{
80 		if((d.mode&DMDIR)==0 && (od.mtime!=d.mtime || od.length!=d.length)){
81 			xlog('c', new, &d);
82 			change = 1;
83 		}
84 		if((!uid&&strcmp(od.uid,d.uid)!=0)
85 		|| strcmp(od.gid,d.gid)!=0
86 		|| od.mode!=d.mode){
87 			xlog('m', new, &d);
88 			change = 1;
89 		}
90 	}
91 	if(!justlog && change){
92 		if(uid)
93 			d.uid = uid;
94 		d.muid = "mark";	/* mark bit */
95 		insertdb(db, new, &d);
96 	}
97 }
98 
99 void
warn(char * msg,void *)100 warn(char *msg, void*)
101 {
102 	char *p;
103 
104 	fprint(2, "warning: %s\n", msg);
105 
106 	/* find the %r in "can't open foo: %r" */
107 	p = strstr(msg, ": ");
108 	if(p)
109 		p += 2;
110 
111 	/*
112 	 * if the error is about a remote server failing,
113 	 * then there's no point in continuing to look
114 	 * for changes -- we'll think everything got deleted!
115 	 *
116 	 * actual errors i see are:
117 	 *	"i/o on hungup channel" for a local hangup
118 	 *	"i/o on hungup channel" for a timeout (yank the network wire)
119 	 *	"'/n/sources/plan9' Hangup" for a remote hangup
120 	 * the rest is paranoia.
121 	 */
122 	if(p){
123 		if(cistrstr(p, "hungup") || cistrstr(p, "Hangup")
124 		|| cistrstr(p, "rpc error")
125 		|| cistrstr(p, "shut down")
126 		|| cistrstr(p, "i/o")
127 		|| cistrstr(p, "connection"))
128 			sysfatal("suspected network or i/o error - bailing out");
129 	}
130 }
131 
132 void
usage(void)133 usage(void)
134 {
135 	fprint(2, "usage: replica/updatedb [-c] [-p proto] [-r root] [-t now n] [-u uid] [-x path]... db [paths]\n");
136 	exits("usage");
137 }
138 
139 void
main(int argc,char ** argv)140 main(int argc, char **argv)
141 {
142 	char *proto;
143 	Avlwalk *w;
144 	Dir d;
145 	Entry *e;
146 
147 	quotefmtinstall();
148 	proto = "/sys/lib/sysconfig/proto/allproto";
149 	now = time(0);
150 	Binit(&blog, 1, OWRITE);
151 	ARGBEGIN{
152 	case 'c':
153 		changesonly = 1;
154 		break;
155 	case 'l':
156 		justlog = 1;
157 		break;
158 	case 'p':
159 		proto = EARGF(usage());
160 		break;
161 	case 'r':
162 		root = EARGF(usage());
163 		break;
164 	case 't':
165 		now = strtoul(EARGF(usage()), 0, 0);
166 		n = atoi(EARGF(usage()));
167 		break;
168 	case 'u':
169 		uid = EARGF(usage());
170 		break;
171 	case 'x':
172 		if(nx%16 == 0)
173 			x = erealloc(x, (nx+16)*sizeof(x[0]));
174 		x[nx++] = EARGF(usage());
175 		break;
176 	default:
177 		usage();
178 	}ARGEND
179 
180 	if(argc <1)
181 		usage();
182 
183 	match = argv+1;
184 	nmatch = argc-1;
185 
186 	db = opendb(argv[0]);
187 	if(rdproto(proto, root, walk, warn, nil) < 0)
188 		sysfatal("rdproto: %r");
189 
190 	if(!changesonly){
191 		w = avlwalk(db->avl);
192 		while(e = (Entry*)avlprev(w)){
193 			if(!ismatch(e->name))
194 				continue;
195 			if(!e->d.mark){		/* not visited during walk */
196 				memset(&d, 0, sizeof d);
197 				d.name = e->d.name;
198 				d.uid = e->d.uid;
199 				d.gid = e->d.gid;
200 				d.mtime = e->d.mtime;
201 				d.mode = e->d.mode;
202 				xlog('d', e->name, &d);
203 				if(!justlog)
204 					removedb(db, e->name);
205 			}
206 		}
207 	}
208 
209 	if(Bterm(&blog) < 0)
210 		sysfatal("writing output: %r");
211 
212 	exits(nil);
213 }
214 
215