Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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