scripts: dbglfs.py: Added --ckmeta/--ckdata

For more aggressive checking of filesystem state. These should match the
behavior of LFS_M_CKMETA/CKDATA in lfs.c.

Also tweaked dbgbmapd3.py (and eventually dbgmap.py) to match, though we
don't need new flags there since we're already checking every block in
the filesystem.
This commit is contained in:
Christopher Haster
2025-04-05 17:41:11 -05:00
parent cbd3fed8b8
commit 5682fd6163
3 changed files with 153 additions and 46 deletions
+34 -24
View File
@@ -1550,7 +1550,11 @@ class Mdir:
return self.rbyd.gcksumdelta
def addr(self):
return self.rbyd.addr()
if len(self.blocks) == 1:
return '0x%x' % self.block
else:
return '0x{%s}' % (
','.join('%x' % block for block in self.blocks))
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, self.repr())
@@ -4636,12 +4640,12 @@ class RangeDict:
def main(disk, output, mroots=None, *,
quiet=False,
trunk=None,
mtree_only=False,
block_size=None,
block_count=None,
blocks=None,
mtree_only=False,
quiet=False,
labels=[],
colors=[],
width=None,
@@ -4752,6 +4756,7 @@ def main(disk, output, mroots=None, *,
# fetch the filesystem
bd = Bd(f, block_size, block_count)
lfs = Lfs.fetch(bd, mroots, trunk)
corrupted = not bool(lfs)
# if we can't figure out the block_count, guess
if block_count is None:
@@ -4832,9 +4837,12 @@ def main(disk, output, mroots=None, *,
bmap[b] = Block(b, 'conflict', [
bmap[b].value,
child])
corrupted = True
# corrupt block?
elif not child:
bmap[b] = Block(b, 'corrupt', child)
corrupted = True
# normal block
else:
@@ -5663,19 +5671,21 @@ def main(disk, output, mroots=None, *,
# print some summary info
if not quiet:
print('updated %s, littlefs%s v%s.%s %sx%s %s w%s.%s, cksum %08x%s' % (
output,
'' if lfs.ckmagic() else '?',
lfs.version.major if lfs.version is not None else '?',
lfs.version.minor if lfs.version is not None else '?',
lfs.block_size if lfs.block_size is not None else '?',
lfs.block_count if lfs.block_count is not None else '?',
lfs.addr(),
lfs.mbweightrepr(), lfs.mrweightrepr(),
lfs.cksum,
'' if lfs.ckcksum() else '?'))
print('updated %s, '
'littlefs%s v%s.%s %sx%s %s w%s.%s, '
'cksum %08x%s' % (
output,
'' if lfs.ckmagic() else '?',
lfs.version.major if lfs.version is not None else '?',
lfs.version.minor if lfs.version is not None else '?',
lfs.block_size if lfs.block_size is not None else '?',
lfs.block_count if lfs.block_count is not None else '?',
lfs.addr(),
lfs.mbweightrepr(), lfs.mrweightrepr(),
lfs.cksum,
'' if lfs.ckcksum() else '?'))
if args.get('error_on_corrupt') and not lfs:
if args.get('error_on_corrupt') and corrupted:
sys.exit(2)
@@ -5698,19 +5708,10 @@ if __name__ == "__main__":
'-o', '--output',
required=True,
help="Output *.svg file.")
parser.add_argument(
'-q', '--quiet',
action='store_true',
help="Don't print info.")
parser.add_argument(
'--trunk',
type=lambda x: int(x, 0),
help="Use this offset as the trunk of the mroots.")
# TODO adopt this in dbglfs.py for --ckdata?
parser.add_argument(
'--mtree-only',
action='store_true',
help="Only traverse the mtree.")
parser.add_argument(
'-b', '--block-size',
type=bdgeom,
@@ -5768,6 +5769,15 @@ if __name__ == "__main__":
if ',' in x
else int(x, 0)),
help="Show a specific block, may be a range.")
parser.add_argument(
'--mtree-only',
action='store_true',
help="Only traverse the mtree.")
parser.add_argument(
'-q', '--quiet',
action='store_true',
help="Don't print info.")
parser.add_argument(
'-L', '--add-label',
dest='labels',
+114 -21
View File
@@ -1481,7 +1481,11 @@ class Mdir:
return self.rbyd.gcksumdelta
def addr(self):
return self.rbyd.addr()
if len(self.blocks) == 1:
return '0x%x' % self.block
else:
return '0x{%s}' % (
','.join('%x' % block for block in self.blocks))
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, self.repr())
@@ -4011,7 +4015,7 @@ TreeArt.fromfile = treeartfromfile
# show the littlefs config
def dbg_config(lfs,
def dbg_config(lfs, *,
color=False,
w_width=2,
**args):
@@ -4049,7 +4053,7 @@ def dbg_config(lfs,
line))
# show the littlefs gstate
def dbg_gstate(lfs,
def dbg_gstate(lfs, *,
color=False,
w_width=2,
**args):
@@ -4115,7 +4119,7 @@ def dbg_gstate(lfs,
line))
# show the littlefs file tree
def dbg_files(lfs, paths,
def dbg_files(lfs, paths, *,
color=False,
w_width=2,
recurse=None,
@@ -4445,11 +4449,57 @@ def dbg_files(lfs, paths,
for dir in dirs:
dbg_dir(dir, recurse)
# common ck function
def dbg_ck(lfs, *,
meta=True,
data=True,
mtree_only=False,
quiet=False,
color=False,
**args):
# lfs traverse does most of the work here
corrupted = False
for child in lfs.traverse(
mtree_only=mtree_only):
# limit to metadata blocks?
if (((meta and isinstance(child, (Mdir, Rbyd)))
or (data and isinstance(child, Bptr)))
and not child):
if not quiet:
print('%11s: %s%s%s' % (
'{%s}' % ','.join('%04x' % block
for block in child.blocks)
if isinstance(child, Mdir)
else '%04x.%04x' % (child.block, child.trunk)
if isinstance(child, Rbyd)
else '%04x.%04x' % (child.block, child.off),
'\x1b[31m' if color else '',
'(corrupted %s %s)' % (
'mroot' if isinstance(child, Mdir)
and child.mid == -1
else 'mdir' if isinstance(child, Mdir)
else 'rbyd' if isinstance(child, Rbyd)
else 'bptr',
child.addr()),
'\x1b[m' if color else ''))
corrupted = True
return not corrupted
# check metadata blocks for errors
def dbg_ckmeta(lfs, **args):
return dbg_ck(lfs, meta=True, **args)
# check metadata + data blocks for errors
def dbg_ckdata(lfs, **args):
return dbg_ck(lfs, meta=True, data=True, **args)
def main(disk, mroots=None, paths=None, *,
trunk=None,
block_size=None,
block_count=None,
quiet=False,
color='auto',
**args):
# figure out what color should be
@@ -4468,10 +4518,14 @@ def main(disk, mroots=None, paths=None, *,
show_files = (args.get('files')
or args.get('structs')
or args.get('attrs'))
show_ckmeta = args.get('ckmeta')
show_ckdata = args.get('ckdata')
if (not show_config
and not show_gstate
and not show_files):
and not show_files
and not show_ckmeta
and not show_ckdata):
show_files = True
# is bd geometry specified?
@@ -4507,17 +4561,20 @@ def main(disk, mroots=None, paths=None, *,
lfs = Lfs.fetch(bd, mroots, trunk)
# print some information about the filesystem
print('littlefs%s v%s.%s %sx%s %s w%s.%s, rev %08x, cksum %08x%s' % (
'' if lfs.ckmagic() else '?',
lfs.version.major if lfs.version is not None else '?',
lfs.version.minor if lfs.version is not None else '?',
lfs.block_size if lfs.block_size is not None else '?',
lfs.block_count if lfs.block_count is not None else '?',
lfs.addr(),
lfs.mbweightrepr(), lfs.mrweightrepr(),
lfs.rev,
lfs.cksum,
'' if lfs.ckcksum() else '?'))
if not quiet:
print('littlefs%s v%s.%s %sx%s %s w%s.%s, '
'rev %08x, '
'cksum %08x%s' % (
'' if lfs.ckmagic() else '?',
lfs.version.major if lfs.version is not None else '?',
lfs.version.minor if lfs.version is not None else '?',
lfs.block_size if lfs.block_size is not None else '?',
lfs.block_count if lfs.block_count is not None else '?',
lfs.addr(),
lfs.mbweightrepr(), lfs.mrweightrepr(),
lfs.rev,
lfs.cksum,
'' if lfs.ckcksum() else '?'))
# dynamically size the id field
w_width = max(
@@ -4528,30 +4585,50 @@ def main(disk, mroots=None, paths=None, *,
2)
# show the on-disk config?
if show_config:
if show_config and not quiet:
dbg_config(lfs,
color=color,
w_width=w_width,
**args)
# show the on-disk gstate?
if show_gstate:
if show_gstate and not quiet:
dbg_gstate(lfs,
color=color,
w_width=w_width,
**args)
# show the on-disk file tree?
if show_files:
if show_files and not quiet:
dbg_files(lfs, paths,
color=color,
w_width=w_width,
**args)
# is the filesystem corrupt?
# always check magic/gcksum
corrupted = not bool(lfs)
if args.get('error_on_corrupt') and corrupted:
# check metadata blocks for errors
if show_ckmeta and not show_ckdata:
if not dbg_ckmeta(lfs,
quiet=quiet,
color=color,
w_width=w_width,
**args):
corrupted = True
# check metadata + data blocks for errors
if show_ckdata:
if not dbg_ckdata(lfs,
quiet=quiet,
color=color,
w_width=w_width,
**args):
corrupted = True
# ckmeta/ckdata implies error_on_corrupt
if ((show_ckmeta or show_ckdata or args.get('error_on_corrupt'))
and corrupted):
sys.exit(2)
@@ -4602,6 +4679,10 @@ if __name__ == "__main__":
'--block-count',
type=lambda x: int(x, 0),
help="Block count in blocks.")
parser.add_argument(
'-q', '--quiet',
action='store_true',
help="Don't show anything, useful when checking for errors.")
parser.add_argument(
'--color',
choices=['never', 'always', 'auto'],
@@ -4632,6 +4713,18 @@ if __name__ == "__main__":
'--attrs',
action='store_true',
help="Show custom attributes attached to files. Implies --files.")
parser.add_argument(
'--ckmeta',
action='store_true',
help="Check metadata blocks for errors.")
parser.add_argument(
'--ckdata',
action='store_true',
help="Check metadata + data blocks for errors.")
parser.add_argument(
'--mtree-only',
action='store_true',
help="Only traverse the mtree.")
parser.add_argument(
'-r', '--recurse', '--file-depth',
nargs='?',
+5 -1
View File
@@ -1447,7 +1447,11 @@ class Mdir:
return self.rbyd.gcksumdelta
def addr(self):
return self.rbyd.addr()
if len(self.blocks) == 1:
return '0x%x' % self.block
else:
return '0x{%s}' % (
','.join('%x' % block for block in self.blocks))
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, self.repr())