monotone

monotone Mtn Source Tree

Root/database_check.cc

1// copyright (C) 2005 derek scherger <derek@echologic.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <map>
7#include <set>
8
9#include "app_state.hh"
10#include "constants.hh"
11#include "database_check.hh"
12#include "keys.hh"
13#include "revision.hh"
14#include "ui.hh"
15#include "vocab.hh"
16#include "transforms.hh"
17
18// the database has roughly the following structure
19//
20// certs
21// |
22// +---+---+
23// | |
24// keys revisions
25// |
26// manifests
27// |
28// files
29//
30
31struct checked_cert {
32 revision<cert> rcert;
33 bool found_key;
34 bool good_sig;
35
36 checked_cert(revision<cert> const & c): rcert(c), found_key(false), good_sig(false) {}
37};
38
39struct checked_key {
40 bool found; // found public keypair id in db
41 size_t sigs; // number of signatures by this key
42
43 base64<rsa_pub_key> pub_encoded;
44
45 checked_key(): found(false), sigs(0) {}
46};
47
48struct checked_file {
49 bool found; // found in db, retrieved and verified sha1 hash
50 size_t manifest_refs; // number of manifest references to this file
51
52 checked_file(): found(false), manifest_refs(0) {}
53};
54
55struct checked_manifest {
56 bool found; // found in db, retrieved and verified sha1 hash
57 size_t revision_refs; // number of revision references to this manifest
58 size_t missing_files; // number of missing files referenced by this manifest
59
60 bool parseable; // read_manifest_map does not throw
61 bool normalized; // write_manifest_map( read_manifest_map(dat) ) == dat
62
63 checked_manifest():
64 found(false), revision_refs(0),
65 missing_files(0), parseable(false), normalized(false) {}
66};
67
68// the number of times a revision is referenced (revision_refs)
69// should match the number of times it is listed as a parent in
70// the ancestry cache (ancestry_parent_refs)
71//
72// the number of parents a revision has should match the number
73// of times it is listed as a child in the ancestry cache
74// (ancestry_child_refs)
75
76struct checked_revision {
77 bool found; // found in db, retrieved and verified sha1 hash
78 size_t revision_refs; // number of references to this revision from other revisions
79 size_t ancestry_parent_refs; // number of references to this revision by ancestry parent
80 size_t ancestry_child_refs; // number of references to this revision by ancestry child
81
82 size_t missing_manifests; // number of missing manifests referenced by this revision
83 size_t missing_revisions; // number of missing revisions referenced by this revision
84 size_t incomplete_manifests; // number of manifests missing files referenced by this revision
85
86 size_t cert_refs; // number of references to this revision by revision certs;
87
88 bool parseable; // read_revision_set does not throw
89 bool normalized; // write_revision_set( read_revision_set(dat) ) == dat
90
91 std::string history_error;
92
93 std::set<revision_id> parents;
94 std::vector<checked_cert> checked_certs;
95
96 checked_revision():
97 found(false),
98 revision_refs(0), ancestry_parent_refs(0), ancestry_child_refs(0),
99 missing_manifests(0), missing_revisions(0), incomplete_manifests(0),
100 cert_refs(0), parseable(false), normalized(false) {}
101};
102
103static void
104check_files(app_state & app, std::map<file_id, checked_file> & checked_files)
105{
106 std::set<file_id> files;
107
108 app.db.get_file_ids(files);
109 L(F("checking %d files\n") % files.size());
110
111 ticker ticks(_("files"), "f", files.size()/70+1);
112
113 for (std::set<file_id>::const_iterator i = files.begin();
114 i != files.end(); ++i)
115 {
116 L(F("checking file %s\n") % *i);
117 file_data data;
118 app.db.get_file_version(*i, data);
119 checked_files[*i].found = true;
120 ++ticks;
121 }
122
123 I(checked_files.size() == files.size());
124}
125
126static void
127check_manifests(app_state & app,
128 std::map<manifest_id, checked_manifest> & checked_manifests,
129 std::map<file_id, checked_file> & checked_files)
130{
131 std::set<manifest_id> manifests;
132
133 app.db.get_manifest_ids(manifests);
134 L(F("checking %d manifests\n") % manifests.size());
135
136 ticker ticks(_("manifests"), "m", manifests.size()/70+1);
137
138 for (std::set<manifest_id>::const_iterator i = manifests.begin();
139 i != manifests.end(); ++i)
140 {
141 L(F("checking manifest %s\n") % *i);
142 manifest_data data;
143 app.db.get_manifest_version(*i, data);
144 checked_manifests[*i].found = true;
145
146 manifest_map man;
147 try
148 {
149 read_manifest_map(data, man);
150 }
151 catch (std::logic_error & e)
152 {
153 L(F("error parsing manifest %s: %s") % *i % e.what());
154 checked_manifests[*i].parseable = false;
155 continue;
156 }
157 checked_manifests[*i].parseable = true;
158
159 // normalisation check
160 manifest_id norm_ident;
161 manifest_data norm_data;
162 write_manifest_map(man, norm_data);
163 calculate_ident(norm_data, norm_ident);
164 if (norm_ident == *i)
165 checked_manifests[*i].normalized = true;
166
167 for (manifest_map::const_iterator entry = man.begin(); entry != man.end();
168 ++entry)
169 {
170 checked_files[manifest_entry_id(entry)].manifest_refs++;
171
172 if (!checked_files[manifest_entry_id(entry)].found)
173 checked_manifests[*i].missing_files++;
174 }
175
176 ++ticks;
177 }
178
179 I(checked_manifests.size() == manifests.size());
180}
181
182static void
183check_revisions(app_state & app,
184 std::map<revision_id, checked_revision> & checked_revisions,
185 std::map<manifest_id, checked_manifest> & checked_manifests)
186{
187 std::set<revision_id> revisions;
188
189 app.db.get_revision_ids(revisions);
190 L(F("checking %d revisions\n") % revisions.size());
191
192 ticker ticks(_("revisions"), "r", revisions.size()/70+1);
193
194 for (std::set<revision_id>::const_iterator i = revisions.begin();
195 i != revisions.end(); ++i)
196 {
197 L(F("checking revision %s\n") % *i);
198 revision_data data;
199 app.db.get_revision(*i, data);
200 checked_revisions[*i].found = true;
201
202 revision_set rev;
203 try
204 {
205 read_revision_set(data, rev);
206 }
207 catch (std::logic_error & e)
208 {
209 L(F("error parsing revision %s: %s") % *i % e.what());
210 checked_revisions[*i].parseable = false;
211 continue;
212 }
213 checked_revisions[*i].parseable = true;
214
215 // normalisation check
216 revision_id norm_ident;
217 revision_data norm_data;
218 write_revision_set(rev, norm_data);
219 calculate_ident(norm_data, norm_ident);
220 if (norm_ident == *i)
221 checked_revisions[*i].normalized = true;
222
223 checked_manifests[rev.new_manifest].revision_refs++;
224
225 if (!checked_manifests[rev.new_manifest].found)
226 checked_revisions[*i].missing_manifests++;
227
228 if (checked_manifests[rev.new_manifest].missing_files > 0)
229 checked_revisions[*i].incomplete_manifests++;
230
231 for (edge_map::const_iterator edge = rev.edges.begin();
232 edge != rev.edges.end(); ++edge)
233 {
234 // ignore [] -> [...] manifests
235
236 if (!null_id(edge_old_manifest(edge)))
237 {
238 checked_manifests[edge_old_manifest(edge)].revision_refs++;
239
240 if (!checked_manifests[edge_old_manifest(edge)].found)
241 checked_revisions[*i].missing_manifests++;
242
243 if (checked_manifests[edge_old_manifest(edge)].missing_files > 0)
244 checked_revisions[*i].incomplete_manifests++;
245 }
246
247 // ignore [] -> [...] revisions
248
249 // delay checking parents until we've processed all revisions
250 if (!null_id(edge_old_revision(edge)))
251 {
252 checked_revisions[edge_old_revision(edge)].revision_refs++;
253 checked_revisions[*i].parents.insert(edge_old_revision(edge));
254 }
255
256 // also check that change_sets applied to old manifests == new
257 // manifests (which might be a merge)
258 }
259
260 ++ticks;
261 }
262
263 // now check for parent revision existence and problems
264
265 for (std::map<revision_id, checked_revision>::iterator
266 revision = checked_revisions.begin();
267 revision != checked_revisions.end(); ++revision)
268 {
269 for (std::set<revision_id>::const_iterator p = revision->second.parents.begin();
270 p != revision->second.parents.end(); ++p)
271 {
272 if (!checked_revisions[*p].found)
273 revision->second.missing_revisions++;
274 }
275 }
276
277 L(F("checked %d revisions after starting with %d\n")
278 % checked_revisions.size()
279 % revisions.size());
280}
281
282static void
283check_ancestry(app_state & app,
284 std::map<revision_id, checked_revision> & checked_revisions)
285{
286 std::multimap<revision_id, revision_id> graph;
287
288 app.db.get_revision_ancestry(graph);
289 L(F("checking %d ancestry edges\n") % graph.size());
290
291 ticker ticks(_("ancestry"), "a", graph.size()/70+1);
292
293 // checked revision has set of parents
294 // graph has revision and associated parents
295 // these two representations of the graph should agree!
296
297 std::set<revision_id> seen;
298 for (std::multimap<revision_id, revision_id>::const_iterator i = graph.begin();
299 i != graph.end(); ++i)
300 {
301 // ignore the [] -> [...] edges here too
302 if (!null_id(i->first))
303 {
304 checked_revisions[i->first].ancestry_parent_refs++;
305
306 if (!null_id(i->second))
307 checked_revisions[i->second].ancestry_child_refs++;
308 }
309
310 ++ticks;
311 }
312}
313
314static void
315check_keys(app_state & app,
316 std::map<rsa_keypair_id, checked_key> & checked_keys)
317{
318 std::vector<rsa_keypair_id> pubkeys;
319
320 app.db.get_public_keys(pubkeys);
321
322 L(F("checking %d public keys\n") % pubkeys.size());
323
324 ticker ticks(_("keys"), "k", 1);
325
326 for (std::vector<rsa_keypair_id>::const_iterator i = pubkeys.begin();
327 i != pubkeys.end(); ++i)
328 {
329 app.db.get_key(*i, checked_keys[*i].pub_encoded);
330 checked_keys[*i].found = true;
331 ++ticks;
332 }
333
334}
335
336static void
337check_certs(app_state & app,
338 std::map<revision_id, checked_revision> & checked_revisions,
339 std::map<rsa_keypair_id, checked_key> & checked_keys,
340 size_t & total_certs)
341{
342
343 std::vector< revision<cert> > certs;
344 app.db.get_revision_certs(certs);
345
346 total_certs = certs.size();
347
348 L(F("checking %d revision certs\n") % certs.size());
349
350 ticker ticks(_("certs"), "c", certs.size()/70+1);
351
352 for (std::vector< revision<cert> >::const_iterator i = certs.begin();
353 i != certs.end(); ++i)
354 {
355 checked_cert checked(*i);
356 checked.found_key = checked_keys[i->inner().key].found;
357
358 if (checked.found_key)
359 {
360 std::string signed_text;
361 cert_signable_text(i->inner(), signed_text);
362 checked.good_sig = check_signature(app, i->inner().key,
363 checked_keys[i->inner().key].pub_encoded,
364 signed_text, i->inner().sig);
365 }
366
367 checked_keys[i->inner().key].sigs++;
368 checked_revisions[i->inner().ident].checked_certs.push_back(checked);
369
370 ++ticks;
371 }
372}
373
374static void
375check_sane(app_state & app,
376 std::map<revision_id, checked_revision> & checked_revisions)
377{
378 L(F("checking local history of %d revisions\n") % checked_revisions.size());
379
380 ticker ticks(_("revisions"), "r", 1);
381
382 for (std::map<revision_id, checked_revision>::iterator
383 i = checked_revisions.begin(); i != checked_revisions.end(); ++i)
384 {
385 if (i->second.found)
386 {
387 try
388 {
389 check_sane_history(i->first, constants::verify_depth, app);
390 }
391 catch (std::exception & e)
392 {
393 i->second.history_error = e.what();
394 }
395 }
396 ++ticks;
397 }
398}
399
400static void
401report_files(std::map<file_id, checked_file> const & checked_files,
402 size_t & missing_files,
403 size_t & unreferenced_files)
404{
405 for (std::map<file_id, checked_file>::const_iterator
406 i = checked_files.begin(); i != checked_files.end(); ++i)
407 {
408 checked_file file = i->second;
409
410 if (!file.found)
411 {
412 missing_files++;
413 P(F("file %s missing (%d manifest references)\n")
414 % i->first % file.manifest_refs);
415 }
416
417 if (file.manifest_refs == 0)
418 {
419 unreferenced_files++;
420 P(F("file %s unreferenced\n") % i->first);
421 }
422
423 }
424}
425
426static void
427report_manifests(std::map<manifest_id, checked_manifest> const & checked_manifests,
428 size_t & missing_manifests,
429 size_t & unreferenced_manifests,
430 size_t & incomplete_manifests,
431 size_t & non_parseable_manifests,
432 size_t & non_normalized_manifests)
433{
434 for (std::map<manifest_id, checked_manifest>::const_iterator
435 i = checked_manifests.begin(); i != checked_manifests.end(); ++i)
436 {
437 checked_manifest manifest = i->second;
438
439 if (!manifest.found)
440 {
441 missing_manifests++;
442 P(F("manifest %s missing (%d revision references)\n")
443 % i->first % manifest.revision_refs);
444 }
445
446 if (manifest.revision_refs == 0)
447 {
448 unreferenced_manifests++;
449 P(F("manifest %s unreferenced\n") % i->first);
450 }
451
452 if (manifest.missing_files > 0)
453 {
454 incomplete_manifests++;
455 P(F("manifest %s incomplete (%d missing files)\n")
456 % i->first % manifest.missing_files);
457 }
458
459 if (!manifest.parseable)
460 {
461 non_parseable_manifests++;
462 P(F("manifest %s is not parseable (perhaps with unnormalized paths?)\n")
463 % i->first);
464 }
465
466 if (manifest.parseable && !manifest.normalized)
467 {
468 non_normalized_manifests++;
469 P(F("manifest %s is not in normalized form\n")
470 % i->first);
471 }
472 }
473}
474
475static void
476report_revisions(std::map<revision_id, checked_revision> const & checked_revisions,
477 size_t & missing_revisions,
478 size_t & incomplete_revisions,
479 size_t & mismatched_parents,
480 size_t & mismatched_children,
481 size_t & bad_history,
482 size_t & non_parseable_revisions,
483 size_t & non_normalized_revisions)
484{
485 for (std::map<revision_id, checked_revision>::const_iterator
486 i = checked_revisions.begin(); i != checked_revisions.end(); ++i)
487 {
488 checked_revision revision = i->second;
489
490 if (!revision.found)
491 {
492 missing_revisions++;
493 P(F("revision %s missing (%d revision references; %d cert references)\n")
494 % i->first % revision.revision_refs % revision.cert_refs);
495 }
496
497 if (revision.missing_manifests > 0)
498 {
499 incomplete_revisions++;
500 P(F("revision %s incomplete (%d missing manifests)\n")
501 % i->first % revision.missing_manifests);
502 }
503
504 if (revision.missing_revisions > 0)
505 {
506 incomplete_revisions++;
507 P(F("revision %s incomplete (%d missing revisions)\n")
508 % i->first % revision.missing_revisions);
509 }
510
511 if (revision.incomplete_manifests > 0)
512 {
513 incomplete_revisions++;
514 P(F("revision %s incomplete (%d incomplete manifests)\n")
515 % i->first % revision.incomplete_manifests);
516 }
517
518 if (revision.ancestry_parent_refs != revision.revision_refs)
519 {
520 mismatched_parents++;
521 P(F("revision %s mismatched parents (%d ancestry parents; %d revision refs)\n")
522 % i->first
523 % revision.ancestry_parent_refs
524 % revision.revision_refs );
525 }
526
527 if (revision.ancestry_child_refs != revision.parents.size())
528 {
529 mismatched_children++;
530 P(F("revision %s mismatched children (%d ancestry children; %d parents)\n")
531 % i->first
532 % revision.ancestry_child_refs
533 % revision.parents.size() );
534 }
535
536 if (!revision.history_error.empty())
537 {
538 bad_history++;
539 std::string tmp = revision.history_error;
540 if (tmp[tmp.length() - 1] == '\n')
541 tmp.erase(tmp.length() - 1);
542 P(F("revision %s has bad history (%s)\n")
543 % i->first % tmp);
544 }
545
546 if (!revision.parseable)
547 {
548 non_parseable_revisions++;
549 P(F("revision %s is not parseable (perhaps with unnormalized paths?)\n")
550 % i->first);
551 }
552
553 if (revision.parseable && !revision.normalized)
554 {
555 non_normalized_revisions++;
556 P(F("revision %s is not in normalized form\n")
557 % i->first);
558 }
559 }
560}
561
562static void
563report_keys(std::map<rsa_keypair_id, checked_key> const & checked_keys,
564 size_t & missing_keys)
565{
566 for (std::map<rsa_keypair_id, checked_key>::const_iterator
567 i = checked_keys.begin(); i != checked_keys.end(); ++i)
568 {
569 checked_key key = i->second;
570
571 if (key.found)
572 {
573 L(F("key %s signed %d certs\n")
574 % i->first
575 % key.sigs);
576 }
577 else
578 {
579 missing_keys++;
580 P(F("key %s missing (signed %d certs)\n")
581 % i->first
582 % key.sigs);
583 }
584 }
585}
586
587static void
588report_certs(std::map<revision_id, checked_revision> const & checked_revisions,
589 size_t & missing_certs,
590 size_t & mismatched_certs,
591 size_t & unchecked_sigs,
592 size_t & bad_sigs)
593{
594 std::set<cert_name> cnames;
595
596 cnames.insert(cert_name(author_cert_name));
597 cnames.insert(cert_name(branch_cert_name));
598 cnames.insert(cert_name(changelog_cert_name));
599 cnames.insert(cert_name(date_cert_name));
600
601 for (std::map<revision_id, checked_revision>::const_iterator
602 i = checked_revisions.begin(); i != checked_revisions.end(); ++i)
603 {
604 checked_revision revision = i->second;
605 std::map<cert_name, size_t> cert_counts;
606
607 for (std::vector<checked_cert>::const_iterator checked = revision.checked_certs.begin();
608 checked != revision.checked_certs.end(); ++checked)
609 {
610 if (!checked->found_key)
611 {
612 unchecked_sigs++;
613 P(F("revision %s unchecked signature in %s cert from missing key %s\n")
614 % i->first
615 % checked->rcert.inner().name
616 % checked->rcert.inner().key);
617 }
618 else if (!checked->good_sig)
619 {
620 bad_sigs++;
621 P(F("revision %s bad signature in %s cert from key %s\n")
622 % i->first
623 % checked->rcert.inner().name
624 % checked->rcert.inner().key);
625 }
626
627 cert_counts[checked->rcert.inner().name]++;
628 }
629
630 for (std::set<cert_name>::const_iterator n = cnames.begin();
631 n != cnames.end(); ++n)
632 {
633 if (revision.found && cert_counts[*n] == 0)
634 {
635 missing_certs++;
636 P(F("revision %s missing %s cert\n") % i->first % *n);
637 }
638 }
639
640 if (cert_counts[cert_name(author_cert_name)] != cert_counts[cert_name(changelog_cert_name)] ||
641 cert_counts[cert_name(author_cert_name)] != cert_counts[cert_name(date_cert_name)] ||
642 cert_counts[cert_name(date_cert_name)] != cert_counts[cert_name(changelog_cert_name)])
643 {
644 mismatched_certs++;
645 P(F("revision %s mismatched certs (%d authors %d dates %d changelogs)\n")
646 % i->first
647 % cert_counts[cert_name(author_cert_name)]
648 % cert_counts[cert_name(date_cert_name)]
649 % cert_counts[cert_name(changelog_cert_name)]);
650 }
651
652 }
653}
654
655void
656check_db(app_state & app)
657{
658 std::map<file_id, checked_file> checked_files;
659 std::map<manifest_id, checked_manifest> checked_manifests;
660 std::map<revision_id, checked_revision> checked_revisions;
661 std::map<rsa_keypair_id, checked_key> checked_keys;
662
663 size_t missing_files = 0;
664 size_t unreferenced_files = 0;
665
666 size_t missing_manifests = 0;
667 size_t unreferenced_manifests = 0;
668 size_t incomplete_manifests = 0;
669 size_t non_parseable_manifests = 0;
670 size_t non_normalized_manifests = 0;
671
672 size_t missing_revisions = 0;
673 size_t incomplete_revisions = 0;
674 size_t mismatched_parents = 0;
675 size_t mismatched_children = 0;
676 size_t bad_history = 0;
677 size_t non_parseable_revisions = 0;
678 size_t non_normalized_revisions = 0;
679
680 size_t missing_keys = 0;
681
682 size_t total_certs = 0;
683 size_t missing_certs = 0;
684 size_t mismatched_certs = 0;
685 size_t unchecked_sigs = 0;
686 size_t bad_sigs = 0;
687
688 check_files(app, checked_files);
689 check_manifests(app, checked_manifests, checked_files);
690 check_revisions(app, checked_revisions, checked_manifests);
691 check_ancestry(app, checked_revisions);
692 check_sane(app, checked_revisions);
693 check_keys(app, checked_keys);
694 check_certs(app, checked_revisions, checked_keys, total_certs);
695
696 report_files(checked_files, missing_files, unreferenced_files);
697
698 report_manifests(checked_manifests,
699 missing_manifests, unreferenced_manifests,
700 incomplete_manifests,
701 non_parseable_manifests,
702 non_normalized_manifests);
703
704 report_revisions(checked_revisions,
705 missing_revisions, incomplete_revisions,
706 mismatched_parents, mismatched_children,
707 bad_history, non_parseable_revisions,
708 non_normalized_revisions);
709
710 report_keys(checked_keys, missing_keys);
711
712 report_certs(checked_revisions,
713 missing_certs, mismatched_certs,
714 unchecked_sigs, bad_sigs);
715
716 if (missing_files > 0)
717 W(F("%d missing files\n") % missing_files);
718 if (unreferenced_files > 0)
719 W(F("%d unreferenced files\n") % unreferenced_files);
720
721 if (missing_manifests > 0)
722 W(F("%d missing manifests\n") % missing_manifests);
723 if (unreferenced_manifests > 0)
724 W(F("%d unreferenced manifests\n") % unreferenced_manifests);
725 if (incomplete_manifests > 0)
726 W(F("%d incomplete manifests\n") % incomplete_manifests);
727 if (non_parseable_manifests > 0)
728 W(F("%d manifests not parseable (perhaps with invalid paths)\n")
729 % non_parseable_manifests);
730 if (non_normalized_manifests > 0)
731 W(F("%d manifests not in normalized form\n") % non_normalized_manifests);
732
733 if (missing_revisions > 0)
734 W(F("%d missing revisions\n") % missing_revisions);
735 if (incomplete_revisions > 0)
736 W(F("%d incomplete revisions\n") % incomplete_revisions);
737 if (mismatched_parents > 0)
738 W(F("%d mismatched parents\n") % mismatched_parents);
739 if (mismatched_children > 0)
740 W(F("%d mismatched children\n") % mismatched_children);
741 if (bad_history > 0)
742 W(F("%d revisions with bad history\n") % bad_history);
743 if (non_parseable_revisions > 0)
744 W(F("%d revisions not parseable (perhaps with invalid paths)\n")
745 % non_parseable_revisions);
746 if (non_normalized_revisions > 0)
747 W(F("%d revisions not in normalized form\n") % non_normalized_revisions);
748
749 if (missing_keys > 0)
750 W(F("%d missing keys\n") % missing_keys);
751
752 if (missing_certs > 0)
753 W(F("%d missing certs\n") % missing_certs);
754 if (mismatched_certs > 0)
755 W(F("%d mismatched certs\n") % mismatched_certs);
756 if (unchecked_sigs > 0)
757 W(F("%d unchecked signatures due to missing keys\n") % unchecked_sigs);
758 if (bad_sigs > 0)
759 W(F("%d bad signatures\n") % bad_sigs);
760
761 size_t total = missing_files + unreferenced_files +
762 missing_manifests + unreferenced_manifests + incomplete_manifests +
763 non_parseable_manifests + non_normalized_manifests +
764 missing_revisions + incomplete_revisions +
765 non_parseable_revisions + non_normalized_revisions +
766 mismatched_parents + mismatched_children +
767 bad_history +
768 missing_certs + mismatched_certs +
769 unchecked_sigs + bad_sigs +
770 missing_keys;
771 // unreferenced files and manifests and mismatched certs are not actually
772 // serious errors; odd, but nothing will break.
773 size_t serious = missing_files +
774 missing_manifests + incomplete_manifests +
775 non_parseable_manifests + non_normalized_manifests +
776 missing_revisions + incomplete_revisions +
777 non_parseable_revisions + non_normalized_revisions +
778 mismatched_parents + mismatched_children +
779 bad_history +
780 missing_certs +
781 unchecked_sigs + bad_sigs +
782 missing_keys;
783
784 P(F("check complete: %d files; %d manifests; %d revisions; %d keys; %d certs\n")
785 % checked_files.size()
786 % checked_manifests.size()
787 % checked_revisions.size()
788 % checked_keys.size()
789 % total_certs);
790 P(F("total problems detected: %d (%d serious)\n") % total % serious);
791 if (serious)
792 E(false, F("serious problems detected"));
793 else if (total)
794 P(F("minor problems detected\n"));
795 else
796 P(F("database is good\n"));
797}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status