1368c31abSDavid du Colombier #include <u.h>
2368c31abSDavid du Colombier #include <libc.h>
3368c31abSDavid du Colombier #include <venti.h>
4368c31abSDavid du Colombier #include <libsec.h>
5368c31abSDavid du Colombier #include <avl.h>
6368c31abSDavid du Colombier #include <bin.h>
76a9fc400SDavid du Colombier
8368c31abSDavid du Colombier int changes;
9368c31abSDavid du Colombier int rewrite;
10368c31abSDavid du Colombier int ignoreerrors;
11368c31abSDavid du Colombier int fast;
12368c31abSDavid du Colombier int verbose;
13368c31abSDavid du Colombier int nskip;
14368c31abSDavid du Colombier int nwrite;
156a9fc400SDavid du Colombier
16368c31abSDavid du Colombier VtConn *zsrc, *zdst;
17368c31abSDavid du Colombier uchar zeroscore[VtScoreSize]; /* all zeros */
18368c31abSDavid du Colombier
19368c31abSDavid du Colombier typedef struct ScoreTree ScoreTree;
20368c31abSDavid du Colombier struct ScoreTree
21368c31abSDavid du Colombier {
22368c31abSDavid du Colombier Avl avl;
23368c31abSDavid du Colombier uchar score[VtScoreSize];
24368c31abSDavid du Colombier int type;
25368c31abSDavid du Colombier };
26368c31abSDavid du Colombier
27368c31abSDavid du Colombier Avltree *scoretree;
28368c31abSDavid du Colombier Bin *scorebin;
29368c31abSDavid du Colombier
30368c31abSDavid du Colombier static int
scoretreecmp(Avl * va,Avl * vb)31368c31abSDavid du Colombier scoretreecmp(Avl *va, Avl *vb)
32368c31abSDavid du Colombier {
33368c31abSDavid du Colombier ScoreTree *a, *b;
34368c31abSDavid du Colombier int i;
35368c31abSDavid du Colombier
36368c31abSDavid du Colombier a = (ScoreTree*)va;
37368c31abSDavid du Colombier b = (ScoreTree*)vb;
38368c31abSDavid du Colombier
39368c31abSDavid du Colombier i = memcmp(a->score, b->score, VtScoreSize);
40368c31abSDavid du Colombier if(i != 0)
41368c31abSDavid du Colombier return i;
42368c31abSDavid du Colombier return a->type - b->type;
43368c31abSDavid du Colombier }
44368c31abSDavid du Colombier
45368c31abSDavid du Colombier static int
havevisited(uchar score[VtScoreSize],int type)46368c31abSDavid du Colombier havevisited(uchar score[VtScoreSize], int type)
47368c31abSDavid du Colombier {
48368c31abSDavid du Colombier ScoreTree a;
49368c31abSDavid du Colombier
50368c31abSDavid du Colombier if(scoretree == nil)
51368c31abSDavid du Colombier return 0;
52368c31abSDavid du Colombier memmove(a.score, score, VtScoreSize);
53368c31abSDavid du Colombier a.type = type;
54368c31abSDavid du Colombier return lookupavl(scoretree, &a.avl) != nil;
55368c31abSDavid du Colombier }
56368c31abSDavid du Colombier
57368c31abSDavid du Colombier static void
markvisited(uchar score[VtScoreSize],int type)58368c31abSDavid du Colombier markvisited(uchar score[VtScoreSize], int type)
59368c31abSDavid du Colombier {
60368c31abSDavid du Colombier ScoreTree *a;
61368c31abSDavid du Colombier Avl *old;
62368c31abSDavid du Colombier
63368c31abSDavid du Colombier if(scoretree == nil)
64368c31abSDavid du Colombier return;
65368c31abSDavid du Colombier a = binalloc(&scorebin, sizeof *a, 1);
66368c31abSDavid du Colombier memmove(a->score, score, VtScoreSize);
67368c31abSDavid du Colombier a->type = type;
68368c31abSDavid du Colombier insertavl(scoretree, &a->avl, &old);
69368c31abSDavid du Colombier }
706a9fc400SDavid du Colombier
716a9fc400SDavid du Colombier void
usage(void)726a9fc400SDavid du Colombier usage(void)
736a9fc400SDavid du Colombier {
74431b537fSDavid du Colombier fprint(2, "usage: %s [-fimrv] [-t type] srchost dsthost score\n", argv0);
756a9fc400SDavid du Colombier exits("usage");
766a9fc400SDavid du Colombier }
776a9fc400SDavid du Colombier
786a9fc400SDavid du Colombier void
walk(uchar score[VtScoreSize],uint type,int base)796a9fc400SDavid du Colombier walk(uchar score[VtScoreSize], uint type, int base)
806a9fc400SDavid du Colombier {
81368c31abSDavid du Colombier int i, n;
826a9fc400SDavid du Colombier uchar *buf;
83368c31abSDavid du Colombier uchar nscore[VtScoreSize];
846a9fc400SDavid du Colombier VtEntry e;
856a9fc400SDavid du Colombier VtRoot root;
866a9fc400SDavid du Colombier
87368c31abSDavid du Colombier if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
886a9fc400SDavid du Colombier return;
896a9fc400SDavid du Colombier
90368c31abSDavid du Colombier if(havevisited(score, type)){
91368c31abSDavid du Colombier nskip++;
92368c31abSDavid du Colombier return;
93368c31abSDavid du Colombier }
94368c31abSDavid du Colombier
95368c31abSDavid du Colombier buf = vtmallocz(VtMaxLumpSize);
96368c31abSDavid du Colombier if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
97368c31abSDavid du Colombier if(verbose)
98368c31abSDavid du Colombier fprint(2, "skip %V\n", score);
996a9fc400SDavid du Colombier free(buf);
1006a9fc400SDavid du Colombier return;
1016a9fc400SDavid du Colombier }
1026a9fc400SDavid du Colombier
103368c31abSDavid du Colombier n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
1046a9fc400SDavid du Colombier if(n < 0){
105368c31abSDavid du Colombier if(rewrite){
106368c31abSDavid du Colombier changes++;
107368c31abSDavid du Colombier memmove(score, vtzeroscore, VtScoreSize);
108368c31abSDavid du Colombier }else if(!ignoreerrors)
109368c31abSDavid du Colombier sysfatal("reading block %V (type %d): %r", score, type);
1106a9fc400SDavid du Colombier return;
1116a9fc400SDavid du Colombier }
1126a9fc400SDavid du Colombier
1136a9fc400SDavid du Colombier switch(type){
1146a9fc400SDavid du Colombier case VtRootType:
115368c31abSDavid du Colombier if(vtrootunpack(&root, buf) < 0){
1166a9fc400SDavid du Colombier fprint(2, "warning: could not unpack root in %V %d\n", score, type);
1176a9fc400SDavid du Colombier break;
1186a9fc400SDavid du Colombier }
1196a9fc400SDavid du Colombier walk(root.prev, VtRootType, 0);
120368c31abSDavid du Colombier walk(root.score, VtDirType, 0);
121368c31abSDavid du Colombier if(rewrite)
122368c31abSDavid du Colombier vtrootpack(&root, buf); /* walk might have changed score */
1236a9fc400SDavid du Colombier break;
1246a9fc400SDavid du Colombier
1256a9fc400SDavid du Colombier case VtDirType:
126*8ffb2beeSDavid du Colombier for(i=0; i*VtEntrySize<n; i++){
127368c31abSDavid du Colombier if(vtentryunpack(&e, buf, i) < 0){
1286a9fc400SDavid du Colombier fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
1296a9fc400SDavid du Colombier continue;
1306a9fc400SDavid du Colombier }
1316a9fc400SDavid du Colombier if(!(e.flags & VtEntryActive))
1326a9fc400SDavid du Colombier continue;
133368c31abSDavid du Colombier walk(e.score, e.type, e.type&VtTypeBaseMask);
134368c31abSDavid du Colombier /*
135368c31abSDavid du Colombier * Don't repack unless we're rewriting -- some old
136368c31abSDavid du Colombier * vac files have psize==0 and dsize==0, and these
137368c31abSDavid du Colombier * get rewritten by vtentryunpack to have less strange
138368c31abSDavid du Colombier * block sizes. So vtentryunpack; vtentrypack does not
139368c31abSDavid du Colombier * guarantee to preserve the exact bytes in buf.
140368c31abSDavid du Colombier */
141368c31abSDavid du Colombier if(rewrite)
142368c31abSDavid du Colombier vtentrypack(&e, buf, i);
1436a9fc400SDavid du Colombier }
1446a9fc400SDavid du Colombier break;
1456a9fc400SDavid du Colombier
1466a9fc400SDavid du Colombier case VtDataType:
1476a9fc400SDavid du Colombier break;
1486a9fc400SDavid du Colombier
1496a9fc400SDavid du Colombier default: /* pointers */
1506a9fc400SDavid du Colombier for(i=0; i<n; i+=VtScoreSize)
151368c31abSDavid du Colombier if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
152368c31abSDavid du Colombier walk(buf+i, type-1, base);
1536a9fc400SDavid du Colombier break;
1546a9fc400SDavid du Colombier }
1556a9fc400SDavid du Colombier
156368c31abSDavid du Colombier nwrite++;
157368c31abSDavid du Colombier if(vtwrite(zdst, nscore, type, buf, n) < 0){
158368c31abSDavid du Colombier /* figure out score for better error message */
159368c31abSDavid du Colombier /* can't use input argument - might have changed contents */
160368c31abSDavid du Colombier n = vtzerotruncate(type, buf, n);
161368c31abSDavid du Colombier sha1(buf, n, score, nil);
162368c31abSDavid du Colombier sysfatal("writing block %V (type %d): %r", score, type);
163368c31abSDavid du Colombier }
164368c31abSDavid du Colombier if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0){
165368c31abSDavid du Colombier fprint(2, "not rewriting: wrote %V got %V\n", score, nscore);
166368c31abSDavid du Colombier abort();
167368c31abSDavid du Colombier sysfatal("not rewriting: wrote %V got %V", score, nscore);
168368c31abSDavid du Colombier }
169368c31abSDavid du Colombier
170368c31abSDavid du Colombier markvisited(score, type);
1716a9fc400SDavid du Colombier free(buf);
1726a9fc400SDavid du Colombier }
1736a9fc400SDavid du Colombier
1740aa8dc3cSDavid du Colombier void
main(int argc,char * argv[])1756a9fc400SDavid du Colombier main(int argc, char *argv[])
1766a9fc400SDavid du Colombier {
1776a9fc400SDavid du Colombier int type, n;
1786a9fc400SDavid du Colombier uchar score[VtScoreSize];
1796a9fc400SDavid du Colombier uchar *buf;
180368c31abSDavid du Colombier char *prefix;
1816a9fc400SDavid du Colombier
182368c31abSDavid du Colombier fmtinstall('F', vtfcallfmt);
183368c31abSDavid du Colombier fmtinstall('V', vtscorefmt);
184368c31abSDavid du Colombier
185368c31abSDavid du Colombier type = -1;
1866a9fc400SDavid du Colombier ARGBEGIN{
187368c31abSDavid du Colombier case 'V':
188368c31abSDavid du Colombier chattyventi++;
189368c31abSDavid du Colombier break;
1906a9fc400SDavid du Colombier case 'f':
1916a9fc400SDavid du Colombier fast = 1;
1926a9fc400SDavid du Colombier break;
193368c31abSDavid du Colombier case 'i':
194368c31abSDavid du Colombier if(rewrite)
195368c31abSDavid du Colombier usage();
196368c31abSDavid du Colombier ignoreerrors = 1;
197368c31abSDavid du Colombier break;
198368c31abSDavid du Colombier case 'm':
199368c31abSDavid du Colombier scoretree = mkavltree(scoretreecmp);
200368c31abSDavid du Colombier break;
201368c31abSDavid du Colombier case 'r':
202368c31abSDavid du Colombier if(ignoreerrors)
203368c31abSDavid du Colombier usage();
204368c31abSDavid du Colombier rewrite = 1;
205368c31abSDavid du Colombier break;
206368c31abSDavid du Colombier case 't':
207368c31abSDavid du Colombier type = atoi(EARGF(usage()));
208368c31abSDavid du Colombier break;
209368c31abSDavid du Colombier case 'v':
210368c31abSDavid du Colombier verbose = 1;
211dc5a79c1SDavid du Colombier break;
2126a9fc400SDavid du Colombier default:
2136a9fc400SDavid du Colombier usage();
2146a9fc400SDavid du Colombier break;
2156a9fc400SDavid du Colombier }ARGEND
2166a9fc400SDavid du Colombier
217368c31abSDavid du Colombier if(argc != 3)
2186a9fc400SDavid du Colombier usage();
2196a9fc400SDavid du Colombier
220368c31abSDavid du Colombier if(vtparsescore(argv[2], &prefix, score) < 0)
221368c31abSDavid du Colombier sysfatal("could not parse score: %r");
2226a9fc400SDavid du Colombier
223368c31abSDavid du Colombier buf = vtmallocz(VtMaxLumpSize);
2246a9fc400SDavid du Colombier
225368c31abSDavid du Colombier zsrc = vtdial(argv[0]);
2266a9fc400SDavid du Colombier if(zsrc == nil)
227368c31abSDavid du Colombier sysfatal("could not dial src server: %r");
228368c31abSDavid du Colombier if(vtconnect(zsrc) < 0)
229368c31abSDavid du Colombier sysfatal("vtconnect src: %r");
2306a9fc400SDavid du Colombier
231368c31abSDavid du Colombier zdst = vtdial(argv[1]);
2326a9fc400SDavid du Colombier if(zdst == nil)
233368c31abSDavid du Colombier sysfatal("could not dial dst server: %r");
234368c31abSDavid du Colombier if(vtconnect(zdst) < 0)
235368c31abSDavid du Colombier sysfatal("vtconnect dst: %r");
2366a9fc400SDavid du Colombier
237368c31abSDavid du Colombier if(type != -1){
238368c31abSDavid du Colombier n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
2396a9fc400SDavid du Colombier if(n < 0)
240368c31abSDavid du Colombier sysfatal("could not read block: %r");
2416a9fc400SDavid du Colombier }else{
2426a9fc400SDavid du Colombier for(type=0; type<VtMaxType; type++){
243368c31abSDavid du Colombier n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
2446a9fc400SDavid du Colombier if(n >= 0)
2456a9fc400SDavid du Colombier break;
2466a9fc400SDavid du Colombier }
2476a9fc400SDavid du Colombier if(type == VtMaxType)
248368c31abSDavid du Colombier sysfatal("could not find block %V of any type", score);
2496a9fc400SDavid du Colombier }
2506a9fc400SDavid du Colombier
2516a9fc400SDavid du Colombier walk(score, type, VtDirType);
252368c31abSDavid du Colombier if(changes)
253368c31abSDavid du Colombier print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
2546a9fc400SDavid du Colombier
255368c31abSDavid du Colombier if(verbose)
256368c31abSDavid du Colombier print("%d skipped, %d written\n", nskip, nwrite);
2576a9fc400SDavid du Colombier
258368c31abSDavid du Colombier if(vtsync(zdst) < 0)
259368c31abSDavid du Colombier sysfatal("could not sync dst server: %r");
260368c31abSDavid du Colombier
2616a9fc400SDavid du Colombier exits(0);
2626a9fc400SDavid du Colombier }
263