From a90e25a1298602c30d0b9cc0c86acede7c8e4ed4 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sat, 24 Dec 2022 23:49:01 -0700 Subject: tree-wide: Outlaw fmt.Print, force textui --- cmd/btrfs-rec/inspect_lstrees.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'cmd/btrfs-rec/inspect_lstrees.go') diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index 54c2074..e0dc4e1 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -25,6 +25,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/maps" "git.lukeshu.com/btrfs-progs-ng/lib/slices" + "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) func init() { @@ -69,7 +70,7 @@ func init() { PreTree: func(name string, treeID btrfsprim.ObjID) { treeErrCnt = 0 treeItemCnt = make(map[btrfsitem.Type]int) - fmt.Printf("tree id=%v name=%q\n", treeID, name) + textui.Fprintf(os.Stdout, "tree id=%v name=%q\n", treeID, name) }, Err: func(_ *btrfsutil.WalkError) { treeErrCnt++ @@ -98,7 +99,7 @@ func init() { if scandevicesFilename != "" { treeErrCnt = 0 treeItemCnt = make(map[btrfsitem.Type]int) - fmt.Printf("lost+found\n") + textui.Fprintf(os.Stdout, "lost+found\n") sb, _ := fs.Superblock() for _, devResults := range scanResults { for laddr := range devResults.FoundNodes { -- cgit v1.2.3-54-g00ecf From 74bb10779338bbb06be44a523d1e166b760018f7 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sat, 24 Dec 2022 23:55:03 -0700 Subject: tree-wide: Audit for fmt.Fprint usage, in favor of textui --- cmd/btrfs-rec/inspect_lstrees.go | 7 +- cmd/btrfs-rec/main.go | 4 +- lib/btrfsprogs/btrfsinspect/print_addrspace.go | 13 +- lib/btrfsprogs/btrfsinspect/print_tree.go | 193 +++++++++++++------------ 4 files changed, 108 insertions(+), 109 deletions(-) (limited to 'cmd/btrfs-rec/inspect_lstrees.go') diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index e0dc4e1..7f59eaa 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -6,7 +6,6 @@ package main import ( "encoding/json" - "fmt" "os" "strconv" "text/tabwriter" @@ -58,11 +57,11 @@ func init() { numWidth := len(strconv.Itoa(slices.Max(treeErrCnt, totalItems))) table := tabwriter.NewWriter(os.Stdout, 0, 8, 2, ' ', 0) - fmt.Fprintf(table, " errors\t% *s\n", numWidth, strconv.Itoa(treeErrCnt)) + textui.Fprintf(table, " errors\t% *s\n", numWidth, strconv.Itoa(treeErrCnt)) for _, typ := range maps.SortedKeys(treeItemCnt) { - fmt.Fprintf(table, " %v items\t% *s\n", typ, numWidth, strconv.Itoa(treeItemCnt[typ])) + textui.Fprintf(table, " %v items\t% *s\n", typ, numWidth, strconv.Itoa(treeItemCnt[typ])) } - fmt.Fprintf(table, " total items\t% *s\n", numWidth, strconv.Itoa(totalItems)) + textui.Fprintf(table, " total items\t% *s\n", numWidth, strconv.Itoa(totalItems)) table.Flush() } visitedNodes := make(containers.Set[btrfsvol.LogicalAddr]) diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index c808237..a221cb7 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -7,7 +7,6 @@ package main import ( "context" "encoding/json" - "fmt" "os" "github.com/datawire/dlib/dgroup" @@ -20,6 +19,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil" + "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) type logLevelFlag struct { @@ -162,7 +162,7 @@ func main() { } if err := argparser.ExecuteContext(context.Background()); err != nil { - fmt.Fprintf(os.Stderr, "%v: error: %v\n", argparser.CommandPath(), err) + textui.Fprintf(os.Stderr, "%v: error: %v\n", argparser.CommandPath(), err) os.Exit(1) } } diff --git a/lib/btrfsprogs/btrfsinspect/print_addrspace.go b/lib/btrfsprogs/btrfsinspect/print_addrspace.go index cd90288..a8b992e 100644 --- a/lib/btrfsprogs/btrfsinspect/print_addrspace.go +++ b/lib/btrfsprogs/btrfsinspect/print_addrspace.go @@ -5,7 +5,6 @@ package btrfsinspect import ( - "fmt" "io" "sort" @@ -21,19 +20,19 @@ func PrintLogicalSpace(out io.Writer, fs *btrfs.FS) { for _, mapping := range mappings { if mapping.LAddr > prevEnd { size := mapping.LAddr.Sub(prevEnd) - fmt.Fprintf(out, "logical_hole laddr=%v size=%v\n", prevEnd, size) + textui.Fprintf(out, "logical_hole laddr=%v size=%v\n", prevEnd, size) sumHole += size } if mapping.LAddr != prevBeg { if !mapping.Flags.OK { - fmt.Fprintf(out, "chunk laddr=%v size=%v flags=(missing)\n", + textui.Fprintf(out, "chunk laddr=%v size=%v flags=(missing)\n", mapping.LAddr, mapping.Size) } else { - fmt.Fprintf(out, "chunk laddr=%v size=%v flags=%v\n", + textui.Fprintf(out, "chunk laddr=%v size=%v flags=%v\n", mapping.LAddr, mapping.Size, mapping.Flags.Val) } } - fmt.Fprintf(out, "\tstripe dev_id=%v paddr=%v\n", + textui.Fprintf(out, "\tstripe dev_id=%v paddr=%v\n", mapping.PAddr.Dev, mapping.PAddr.Addr) sumChunk += mapping.Size prevBeg = mapping.LAddr @@ -60,10 +59,10 @@ func PrintPhysicalSpace(out io.Writer, fs *btrfs.FS) { } if mapping.PAddr.Addr > prevEnd { size := mapping.PAddr.Addr.Sub(prevEnd) - fmt.Fprintf(out, "physical_hole paddr=%v size=%v\n", prevEnd, size) + textui.Fprintf(out, "physical_hole paddr=%v size=%v\n", prevEnd, size) sumHole += size } - fmt.Fprintf(out, "devext dev=%v paddr=%v size=%v laddr=%v\n", + textui.Fprintf(out, "devext dev=%v paddr=%v size=%v laddr=%v\n", mapping.PAddr.Dev, mapping.PAddr.Addr, mapping.Size, mapping.LAddr) sumExt += mapping.Size prevEnd = mapping.PAddr.Addr.Add(mapping.Size) diff --git a/lib/btrfsprogs/btrfsinspect/print_tree.go b/lib/btrfsprogs/btrfsinspect/print_tree.go index 9e5a5d1..b882c6b 100644 --- a/lib/btrfsprogs/btrfsinspect/print_tree.go +++ b/lib/btrfsprogs/btrfsinspect/print_tree.go @@ -22,6 +22,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/slices" + "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) func DumpTrees(ctx context.Context, out io.Writer, fs *btrfs.FS) { @@ -32,19 +33,19 @@ func DumpTrees(ctx context.Context, out io.Writer, fs *btrfs.FS) { } if superblock.RootTree != 0 { - fmt.Fprintf(out, "root tree\n") + textui.Fprintf(out, "root tree\n") printTree(ctx, out, fs, btrfsprim.ROOT_TREE_OBJECTID) } if superblock.ChunkTree != 0 { - fmt.Fprintf(out, "chunk tree\n") + textui.Fprintf(out, "chunk tree\n") printTree(ctx, out, fs, btrfsprim.CHUNK_TREE_OBJECTID) } if superblock.LogTree != 0 { - fmt.Fprintf(out, "log root tree\n") + textui.Fprintf(out, "log root tree\n") printTree(ctx, out, fs, btrfsprim.TREE_LOG_OBJECTID) } if superblock.BlockGroupRoot != 0 { - fmt.Fprintf(out, "block group tree\n") + textui.Fprintf(out, "block group tree\n") printTree(ctx, out, fs, btrfsprim.BLOCK_GROUP_TREE_OBJECTID) } fs.TreeWalk( @@ -81,15 +82,15 @@ func DumpTrees(ctx context.Context, out io.Writer, fs *btrfs.FS) { if !ok { treeName = "file" } - fmt.Fprintf(out, "%v tree %v \n", treeName, fmtKey(item.Key)) + textui.Fprintf(out, "%v tree %v \n", treeName, fmtKey(item.Key)) printTree(ctx, out, fs, item.Key.ObjectID) return nil }, }, ) - fmt.Fprintf(out, "total bytes %v\n", superblock.TotalBytes) - fmt.Fprintf(out, "bytes used %v\n", superblock.BytesUsed) - fmt.Fprintf(out, "uuid %v\n", superblock.FSUUID) + textui.Fprintf(out, "total bytes %v\n", superblock.TotalBytes) + textui.Fprintf(out, "bytes used %v\n", superblock.BytesUsed) + textui.Fprintf(out, "uuid %v\n", superblock.FSUUID) } // printTree mimics btrfs-progs @@ -104,7 +105,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri return nil }, PreKeyPointer: func(_ btrfstree.TreePath, item btrfstree.KeyPointer) error { - fmt.Fprintf(out, "\t%v block %v gen %v\n", + textui.Fprintf(out, "\t%v block %v gen %v\n", fmtKey(item.Key), item.BlockPtr, item.Generation) @@ -115,65 +116,65 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri bs, _ := binstruct.Marshal(item.Body) itemSize := uint32(len(bs)) itemOffset -= itemSize - fmt.Fprintf(out, "\titem %v %v itemoff %v itemsize %v\n", + textui.Fprintf(out, "\titem %v %v itemoff %v itemsize %v\n", i, fmtKey(item.Key), itemOffset, itemSize) switch body := item.Body.(type) { case btrfsitem.FreeSpaceHeader: - fmt.Fprintf(out, "\t\tlocation %v\n", fmtKey(body.Location)) - fmt.Fprintf(out, "\t\tcache generation %v entries %v bitmaps %v\n", + textui.Fprintf(out, "\t\tlocation %v\n", fmtKey(body.Location)) + textui.Fprintf(out, "\t\tcache generation %v entries %v bitmaps %v\n", body.Generation, body.NumEntries, body.NumBitmaps) case btrfsitem.Inode: - fmt.Fprintf(out, ""+ + textui.Fprintf(out, ""+ "\t\tgeneration %v transid %v size %v nbytes %v\n"+ "\t\tblock group %v mode %o links %v uid %v gid %v rdev %v\n"+ "\t\tsequence %v flags %v\n", body.Generation, body.TransID, body.Size, body.NumBytes, body.BlockGroup, body.Mode, body.NLink, body.UID, body.GID, body.RDev, body.Sequence, body.Flags) - fmt.Fprintf(out, "\t\tatime %v\n", fmtTime(body.ATime)) - fmt.Fprintf(out, "\t\tctime %v\n", fmtTime(body.CTime)) - fmt.Fprintf(out, "\t\tmtime %v\n", fmtTime(body.MTime)) - fmt.Fprintf(out, "\t\totime %v\n", fmtTime(body.OTime)) + textui.Fprintf(out, "\t\tatime %v\n", fmtTime(body.ATime)) + textui.Fprintf(out, "\t\tctime %v\n", fmtTime(body.CTime)) + textui.Fprintf(out, "\t\tmtime %v\n", fmtTime(body.MTime)) + textui.Fprintf(out, "\t\totime %v\n", fmtTime(body.OTime)) case btrfsitem.InodeRefs: for _, ref := range body { - fmt.Fprintf(out, "\t\tindex %v namelen %v name: %s\n", + textui.Fprintf(out, "\t\tindex %v namelen %v name: %s\n", ref.Index, ref.NameLen, ref.Name) } //case btrfsitem.INODE_EXTREF_KEY: // // TODO case btrfsitem.DirEntry: - fmt.Fprintf(out, "\t\tlocation %v type %v\n", + textui.Fprintf(out, "\t\tlocation %v type %v\n", fmtKey(body.Location), body.Type) - fmt.Fprintf(out, "\t\ttransid %v data_len %v name_len %v\n", + textui.Fprintf(out, "\t\ttransid %v data_len %v name_len %v\n", body.TransID, body.DataLen, body.NameLen) - fmt.Fprintf(out, "\t\tname: %s\n", body.Name) + textui.Fprintf(out, "\t\tname: %s\n", body.Name) if len(body.Data) > 0 { - fmt.Fprintf(out, "\t\tdata %v\n", body.Data) + textui.Fprintf(out, "\t\tdata %v\n", body.Data) } //case btrfsitem.DIR_LOG_INDEX_KEY, btrfsitem.DIR_LOG_ITEM_KEY: // // TODO case btrfsitem.Root: - fmt.Fprintf(out, "\t\tgeneration %v root_dirid %v bytenr %d byte_limit %v bytes_used %v\n", + textui.Fprintf(out, "\t\tgeneration %v root_dirid %v bytenr %d byte_limit %v bytes_used %v\n", body.Generation, body.RootDirID, body.ByteNr, body.ByteLimit, body.BytesUsed) - fmt.Fprintf(out, "\t\tlast_snapshot %v flags %v refs %v\n", + textui.Fprintf(out, "\t\tlast_snapshot %v flags %v refs %v\n", body.LastSnapshot, body.Flags, body.Refs) - fmt.Fprintf(out, "\t\tdrop_progress %v drop_level %v\n", + textui.Fprintf(out, "\t\tdrop_progress %v drop_level %v\n", fmtKey(body.DropProgress), body.DropLevel) - fmt.Fprintf(out, "\t\tlevel %v generation_v2 %v\n", + textui.Fprintf(out, "\t\tlevel %v generation_v2 %v\n", body.Level, body.GenerationV2) if body.Generation == body.GenerationV2 { - fmt.Fprintf(out, "\t\tuuid %v\n", body.UUID) - fmt.Fprintf(out, "\t\tparent_uuid %v\n", body.ParentUUID) - fmt.Fprintf(out, "\t\treceived_uuid %v\n", body.ReceivedUUID) - fmt.Fprintf(out, "\t\tctransid %v otransid %v stransid %v rtransid %v\n", + textui.Fprintf(out, "\t\tuuid %v\n", body.UUID) + textui.Fprintf(out, "\t\tparent_uuid %v\n", body.ParentUUID) + textui.Fprintf(out, "\t\treceived_uuid %v\n", body.ReceivedUUID) + textui.Fprintf(out, "\t\tctransid %v otransid %v stransid %v rtransid %v\n", body.CTransID, body.OTransID, body.STransID, body.RTransID) - fmt.Fprintf(out, "\t\tctime %v\n", fmtTime(body.CTime)) - fmt.Fprintf(out, "\t\totime %v\n", fmtTime(body.OTime)) - fmt.Fprintf(out, "\t\tstime %v\n", fmtTime(body.STime)) - fmt.Fprintf(out, "\t\trtime %v\n", fmtTime(body.RTime)) + textui.Fprintf(out, "\t\tctime %v\n", fmtTime(body.CTime)) + textui.Fprintf(out, "\t\totime %v\n", fmtTime(body.OTime)) + textui.Fprintf(out, "\t\tstime %v\n", fmtTime(body.STime)) + textui.Fprintf(out, "\t\trtime %v\n", fmtTime(body.RTime)) } case btrfsitem.RootRef: var tag string @@ -185,20 +186,20 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri default: tag = fmt.Sprintf("(error: unhandled RootRef item type: %v)", item.Key.ItemType) } - fmt.Fprintf(out, "\t\troot %v key dirid %v sequence %v name %s\n", + textui.Fprintf(out, "\t\troot %v key dirid %v sequence %v name %s\n", tag, body.DirID, body.Sequence, body.Name) case btrfsitem.Extent: - fmt.Fprintf(out, "\t\trefs %v gen %v flags %v\n", + textui.Fprintf(out, "\t\trefs %v gen %v flags %v\n", body.Head.Refs, body.Head.Generation, body.Head.Flags) if body.Head.Flags.Has(btrfsitem.EXTENT_FLAG_TREE_BLOCK) { - fmt.Fprintf(out, "\t\ttree block %v level %v\n", + textui.Fprintf(out, "\t\ttree block %v level %v\n", fmtKey(body.Info.Key), body.Info.Level) } printExtentInlineRefs(out, body.Refs) case btrfsitem.Metadata: - fmt.Fprintf(out, "\t\trefs %v gen %v flags %v\n", + textui.Fprintf(out, "\t\trefs %v gen %v flags %v\n", body.Head.Refs, body.Head.Generation, body.Head.Flags) - fmt.Fprintf(out, "\t\ttree block skinny level %v\n", item.Key.Offset) + textui.Fprintf(out, "\t\ttree block skinny level %v\n", item.Key.Offset) printExtentInlineRefs(out, body.Refs) //case btrfsitem.EXTENT_DATA_REF_KEY: // // TODO @@ -206,72 +207,72 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri // // TODO case btrfsitem.ExtentCSum: start := btrfsvol.LogicalAddr(item.Key.Offset) - fmt.Fprintf(out, "\t\trange start %d end %d length %d", + textui.Fprintf(out, "\t\trange start %d end %d length %d", start, start.Add(body.Size()), body.Size()) sumsPerLine := slices.Max(1, len(btrfssum.CSum{})/body.ChecksumSize/2) i := 0 _ = body.Walk(ctx, func(pos btrfsvol.LogicalAddr, sum btrfssum.ShortSum) error { if i%sumsPerLine == 0 { - fmt.Fprintf(out, "\n\t\t") + textui.Fprintf(out, "\n\t\t") } else { - fmt.Fprintf(out, " ") + textui.Fprintf(out, " ") } - fmt.Fprintf(out, "[%d] 0x%x", pos, sum) + textui.Fprintf(out, "[%d] 0x%x", pos, sum) i++ return nil }) - fmt.Fprintf(out, "\n") + textui.Fprintf(out, "\n") case btrfsitem.FileExtent: - fmt.Fprintf(out, "\t\tgeneration %v type %v\n", + textui.Fprintf(out, "\t\tgeneration %v type %v\n", body.Generation, body.Type) switch body.Type { case btrfsitem.FILE_EXTENT_INLINE: - fmt.Fprintf(out, "\t\tinline extent data size %v ram_bytes %v compression %v\n", + textui.Fprintf(out, "\t\tinline extent data size %v ram_bytes %v compression %v\n", len(body.BodyInline), body.RAMBytes, body.Compression) case btrfsitem.FILE_EXTENT_PREALLOC: - fmt.Fprintf(out, "\t\tprealloc data disk byte %v nr %v\n", + textui.Fprintf(out, "\t\tprealloc data disk byte %v nr %v\n", body.BodyExtent.DiskByteNr, body.BodyExtent.DiskNumBytes) - fmt.Fprintf(out, "\t\tprealloc data offset %v nr %v\n", + textui.Fprintf(out, "\t\tprealloc data offset %v nr %v\n", body.BodyExtent.Offset, body.BodyExtent.NumBytes) case btrfsitem.FILE_EXTENT_REG: - fmt.Fprintf(out, "\t\textent data disk byte %d nr %d\n", + textui.Fprintf(out, "\t\textent data disk byte %d nr %d\n", body.BodyExtent.DiskByteNr, body.BodyExtent.DiskNumBytes) - fmt.Fprintf(out, "\t\textent data offset %d nr %d ram %v\n", + textui.Fprintf(out, "\t\textent data offset %d nr %d ram %v\n", body.BodyExtent.Offset, body.BodyExtent.NumBytes, body.RAMBytes) - fmt.Fprintf(out, "\t\textent compression %v\n", + textui.Fprintf(out, "\t\textent compression %v\n", body.Compression) default: - fmt.Fprintf(out, "\t\t(error) unknown file extent type %v", body.Type) + textui.Fprintf(out, "\t\t(error) unknown file extent type %v", body.Type) } case btrfsitem.BlockGroup: - fmt.Fprintf(out, "\t\tblock group used %v chunk_objectid %v flags %v\n", + textui.Fprintf(out, "\t\tblock group used %v chunk_objectid %v flags %v\n", body.Used, body.ChunkObjectID, body.Flags) case btrfsitem.FreeSpaceInfo: - fmt.Fprintf(out, "\t\tfree space info extent count %v flags %v\n", + textui.Fprintf(out, "\t\tfree space info extent count %v flags %v\n", body.ExtentCount, body.Flags) case btrfsitem.FreeSpaceBitmap: - fmt.Fprintf(out, "\t\tfree space bitmap\n") + textui.Fprintf(out, "\t\tfree space bitmap\n") case btrfsitem.Chunk: - fmt.Fprintf(out, "\t\tlength %d owner %d stripe_len %v type %v\n", + textui.Fprintf(out, "\t\tlength %d owner %d stripe_len %v type %v\n", body.Head.Size, body.Head.Owner, body.Head.StripeLen, body.Head.Type) - fmt.Fprintf(out, "\t\tio_align %v io_width %v sector_size %v\n", + textui.Fprintf(out, "\t\tio_align %v io_width %v sector_size %v\n", body.Head.IOOptimalAlign, body.Head.IOOptimalWidth, body.Head.IOMinSize) - fmt.Fprintf(out, "\t\tnum_stripes %v sub_stripes %v\n", + textui.Fprintf(out, "\t\tnum_stripes %v sub_stripes %v\n", body.Head.NumStripes, body.Head.SubStripes) for i, stripe := range body.Stripes { - fmt.Fprintf(out, "\t\t\tstripe %v devid %d offset %d\n", + textui.Fprintf(out, "\t\t\tstripe %v devid %d offset %d\n", i, stripe.DeviceID, stripe.Offset) - fmt.Fprintf(out, "\t\t\tdev_uuid %v\n", + textui.Fprintf(out, "\t\t\tdev_uuid %v\n", stripe.DeviceUUID) } case btrfsitem.Dev: - fmt.Fprintf(out, ""+ + textui.Fprintf(out, ""+ "\t\tdevid %d total_bytes %v bytes_used %v\n"+ "\t\tio_align %v io_width %v sector_size %v type %v\n"+ "\t\tgeneration %v start_offset %v dev_group %v\n"+ @@ -285,7 +286,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri body.DevUUID, body.FSUUID) case btrfsitem.DevExtent: - fmt.Fprintf(out, ""+ + textui.Fprintf(out, ""+ "\t\tdev extent chunk_tree %v\n"+ "\t\tchunk_objectid %v chunk_offset %d length %d\n"+ "\t\tchunk_tree_uuid %v\n", @@ -298,49 +299,49 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri //case btrfsitem.QGROUP_LIMIT_KEY: // // TODO case btrfsitem.UUIDMap: - fmt.Fprintf(out, "\t\tsubvol_id %d\n", body.ObjID) + textui.Fprintf(out, "\t\tsubvol_id %d\n", body.ObjID) //case btrfsitem.STRING_ITEM_KEY: // // TODO case btrfsitem.DevStats: - fmt.Fprintf(out, "\t\tpersistent item objectid %v offset %v\n", + textui.Fprintf(out, "\t\tpersistent item objectid %v offset %v\n", item.Key.ObjectID.Format(item.Key.ItemType), item.Key.Offset) switch item.Key.ObjectID { case btrfsprim.DEV_STATS_OBJECTID: - fmt.Fprintf(out, "\t\tdevice stats\n") - fmt.Fprintf(out, "\t\twrite_errs %v read_errs %v flush_errs %v corruption_errs %v generation %v\n", + textui.Fprintf(out, "\t\tdevice stats\n") + textui.Fprintf(out, "\t\twrite_errs %v read_errs %v flush_errs %v corruption_errs %v generation %v\n", body.Values[btrfsitem.DEV_STAT_WRITE_ERRS], body.Values[btrfsitem.DEV_STAT_READ_ERRS], body.Values[btrfsitem.DEV_STAT_FLUSH_ERRS], body.Values[btrfsitem.DEV_STAT_CORRUPTION_ERRS], body.Values[btrfsitem.DEV_STAT_GENERATION_ERRS]) default: - fmt.Fprintf(out, "\t\tunknown persistent item objectid %v\n", item.Key.ObjectID) + textui.Fprintf(out, "\t\tunknown persistent item objectid %v\n", item.Key.ObjectID) } //case btrfsitem.TEMPORARY_ITEM_KEY: // // TODO case btrfsitem.Empty: switch item.Key.ItemType { case btrfsitem.ORPHAN_ITEM_KEY: // 48 - fmt.Fprintf(out, "\t\torphan item\n") + textui.Fprintf(out, "\t\torphan item\n") case btrfsitem.TREE_BLOCK_REF_KEY: // 176 - fmt.Fprintf(out, "\t\ttree block backref\n") + textui.Fprintf(out, "\t\ttree block backref\n") case btrfsitem.SHARED_BLOCK_REF_KEY: // 182 - fmt.Fprintf(out, "\t\tshared block backref\n") + textui.Fprintf(out, "\t\tshared block backref\n") case btrfsitem.FREE_SPACE_EXTENT_KEY: // 199 - fmt.Fprintf(out, "\t\tfree space extent\n") + textui.Fprintf(out, "\t\tfree space extent\n") case btrfsitem.QGROUP_RELATION_KEY: // 246 // do nothing //case btrfsitem.EXTENT_REF_V0_KEY: - // fmt.Fprintf(out, "\t\textent ref v0 (deprecated)\n") + // textui.Fprintf(out, "\t\textent ref v0 (deprecated)\n") //case btrfsitem.CSUM_ITEM_KEY: - // fmt.Fprintf(out, "\t\tcsum item\n") + // textui.Fprintf(out, "\t\tcsum item\n") default: - fmt.Fprintf(out, "\t\t(error) unhandled empty item type: %v\n", item.Key.ItemType) + textui.Fprintf(out, "\t\t(error) unhandled empty item type: %v\n", item.Key.ItemType) } case btrfsitem.Error: - fmt.Fprintf(out, "\t\t(error) error item: %v\n", body.Err) + textui.Fprintf(out, "\t\t(error) error item: %v\n", body.Err) default: - fmt.Fprintf(out, "\t\t(error) unhandled item type: %T\n", body) + textui.Fprintf(out, "\t\t(error) unhandled item type: %T\n", body) } return nil }, @@ -361,37 +362,37 @@ func printHeaderInfo(out io.Writer, node btrfstree.Node) { var typename string if node.Head.Level > 0 { // internal node typename = "node" - fmt.Fprintf(out, "node %v level %v items %v free space %v", + textui.Fprintf(out, "node %v level %v items %v free space %v", node.Head.Addr, node.Head.Level, node.Head.NumItems, node.MaxItems()-node.Head.NumItems) } else { // leaf node typename = "leaf" - fmt.Fprintf(out, "leaf %d items %v free space %v", + textui.Fprintf(out, "leaf %d items %v free space %v", node.Head.Addr, node.Head.NumItems, node.LeafFreeSpace()) } - fmt.Fprintf(out, " generation %v owner %v\n", + textui.Fprintf(out, " generation %v owner %v\n", node.Head.Generation, node.Head.Owner) - fmt.Fprintf(out, "%v %d flags %v backref revision %v\n", + textui.Fprintf(out, "%v %d flags %v backref revision %v\n", typename, node.Head.Addr, node.Head.Flags, node.Head.BackrefRev) - fmt.Fprintf(out, "checksum stored %v\n", node.Head.Checksum.Fmt(node.ChecksumType)) + textui.Fprintf(out, "checksum stored %v\n", node.Head.Checksum.Fmt(node.ChecksumType)) if calcSum, err := node.CalculateChecksum(); err != nil { - fmt.Fprintf(out, "checksum calced %v\n", err) + textui.Fprintf(out, "checksum calced %v\n", err) } else { - fmt.Fprintf(out, "checksum calced %v\n", calcSum.Fmt(node.ChecksumType)) + textui.Fprintf(out, "checksum calced %v\n", calcSum.Fmt(node.ChecksumType)) } - fmt.Fprintf(out, "fs uuid %v\n", node.Head.MetadataUUID) - fmt.Fprintf(out, "chunk uuid %v\n", node.Head.ChunkTreeUUID) + textui.Fprintf(out, "fs uuid %v\n", node.Head.MetadataUUID) + textui.Fprintf(out, "chunk uuid %v\n", node.Head.ChunkTreeUUID) } // printExtentInlineRefs mimics part of btrfs-progs kernel-shared/print-tree.c:print_extent_item() @@ -401,22 +402,22 @@ func printExtentInlineRefs(out io.Writer, refs []btrfsitem.ExtentInlineRef) { case nil: switch ref.Type { case btrfsitem.TREE_BLOCK_REF_KEY: - fmt.Fprintf(out, "\t\ttree block backref root %v\n", + textui.Fprintf(out, "\t\ttree block backref root %v\n", btrfsprim.ObjID(ref.Offset)) case btrfsitem.SHARED_BLOCK_REF_KEY: - fmt.Fprintf(out, "\t\tshared block backref parent %v\n", + textui.Fprintf(out, "\t\tshared block backref parent %v\n", ref.Offset) default: - fmt.Fprintf(out, "\t\t(error) unexpected empty sub-item type: %v\n", ref.Type) + textui.Fprintf(out, "\t\t(error) unexpected empty sub-item type: %v\n", ref.Type) } case btrfsitem.ExtentDataRef: - fmt.Fprintf(out, "\t\textent data backref root %v objectid %v offset %v count %v\n", + textui.Fprintf(out, "\t\textent data backref root %v objectid %v offset %v count %v\n", subitem.Root, subitem.ObjectID, subitem.Offset, subitem.Count) case btrfsitem.SharedDataRef: - fmt.Fprintf(out, "\t\tshared data backref parent %v count %v\n", + textui.Fprintf(out, "\t\tshared data backref parent %v count %v\n", ref.Offset, subitem.Count) default: - fmt.Fprintf(out, "\t\t(error) unexpected sub-item type: %T\n", subitem) + textui.Fprintf(out, "\t\t(error) unexpected sub-item type: %T\n", subitem) } } } @@ -424,19 +425,19 @@ func printExtentInlineRefs(out io.Writer, refs []btrfsitem.ExtentInlineRef) { // mimics print-tree.c:btrfs_print_key() func fmtKey(key btrfsprim.Key) string { var out strings.Builder - fmt.Fprintf(&out, "key (%v %v", key.ObjectID.Format(key.ItemType), key.ItemType) + textui.Fprintf(&out, "key (%v %v", key.ObjectID.Format(key.ItemType), key.ItemType) switch key.ItemType { case btrfsitem.QGROUP_RELATION_KEY: //TODO, btrfsitem.QGROUP_INFO_KEY, btrfsitem.QGROUP_LIMIT_KEY: panic("not implemented") case btrfsitem.UUID_SUBVOL_KEY, btrfsitem.UUID_RECEIVED_SUBVOL_KEY: - fmt.Fprintf(&out, " %#08x)", key.Offset) + textui.Fprintf(&out, " %#08x)", key.Offset) case btrfsitem.ROOT_ITEM_KEY: - fmt.Fprintf(&out, " %v)", btrfsprim.ObjID(key.Offset)) + textui.Fprintf(&out, " %v)", btrfsprim.ObjID(key.Offset)) default: if key.Offset == math.MaxUint64 { - fmt.Fprintf(&out, " -1)") + textui.Fprintf(&out, " -1)") } else { - fmt.Fprintf(&out, " %v)", key.Offset) + textui.Fprintf(&out, " %v)", key.Offset) } } return out.String() -- cgit v1.2.3-54-g00ecf From d5737a0e71b17a97b82ae68e49acc41a08fcc0ad Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 26 Dec 2022 22:02:13 -0700 Subject: cmd/btrfs-rec: Add a utility function for reading JSON files with progress --- cmd/btrfs-rec/inspect_lstrees.go | 12 ++--- cmd/btrfs-rec/inspect_rebuildmappings.go | 3 +- cmd/btrfs-rec/inspect_rebuildnodes.go | 3 +- cmd/btrfs-rec/inspect_scandevices.go | 14 ------ cmd/btrfs-rec/main.go | 7 +-- cmd/btrfs-rec/util.go | 83 ++++++++++++++++++++++++++++++++ lib/textui/log.go | 4 ++ 7 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 cmd/btrfs-rec/util.go (limited to 'cmd/btrfs-rec/inspect_lstrees.go') diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index 7f59eaa..e92c544 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -5,7 +5,6 @@ package main import ( - "encoding/json" "os" "strconv" "text/tabwriter" @@ -36,15 +35,14 @@ func init() { Args: cliutil.WrapPositionalArgs(cobra.NoArgs), }, RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { - var scanResults map[btrfsvol.DeviceID]btrfsinspect.ScanOneDeviceResult + ctx := cmd.Context() + var scanResults btrfsinspect.ScanDevicesResult if scandevicesFilename != "" { - scanResultsBytes, err := os.ReadFile(scandevicesFilename) + var err error + scanResults, err = readJSONFile[btrfsinspect.ScanDevicesResult](ctx, scandevicesFilename) if err != nil { return err } - if err := json.Unmarshal(scanResultsBytes, &scanResults); err != nil { - return err - } } var treeErrCnt int @@ -65,7 +63,7 @@ func init() { table.Flush() } visitedNodes := make(containers.Set[btrfsvol.LogicalAddr]) - btrfsutil.WalkAllTrees(cmd.Context(), fs, btrfsutil.WalkAllTreesHandler{ + btrfsutil.WalkAllTrees(ctx, fs, btrfsutil.WalkAllTreesHandler{ PreTree: func(name string, treeID btrfsprim.ObjID) { treeErrCnt = 0 treeItemCnt = make(map[btrfsitem.Type]int) diff --git a/cmd/btrfs-rec/inspect_rebuildmappings.go b/cmd/btrfs-rec/inspect_rebuildmappings.go index 54535ec..da7d12e 100644 --- a/cmd/btrfs-rec/inspect_rebuildmappings.go +++ b/cmd/btrfs-rec/inspect_rebuildmappings.go @@ -15,6 +15,7 @@ import ( "github.com/spf13/cobra" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" + "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect/rebuildmappings" ) @@ -37,7 +38,7 @@ func init() { ctx := cmd.Context() dlog.Infof(ctx, "Reading %q...", args[0]) - scanResults, err := readScanResults(args[0]) + scanResults, err := readJSONFile[btrfsinspect.ScanDevicesResult](ctx, args[0]) if err != nil { return err } diff --git a/cmd/btrfs-rec/inspect_rebuildnodes.go b/cmd/btrfs-rec/inspect_rebuildnodes.go index 5f6d9b5..0f3d60e 100644 --- a/cmd/btrfs-rec/inspect_rebuildnodes.go +++ b/cmd/btrfs-rec/inspect_rebuildnodes.go @@ -17,6 +17,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" + "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect/rebuildnodes" "git.lukeshu.com/btrfs-progs-ng/lib/containers" ) @@ -31,7 +32,7 @@ func init() { ctx := cmd.Context() dlog.Infof(ctx, "Reading %q...", args[0]) - nodeScanResults, err := readScanResults(args[0]) + nodeScanResults, err := readJSONFile[btrfsinspect.ScanDevicesResult](ctx, args[0]) if err != nil { return err } diff --git a/cmd/btrfs-rec/inspect_scandevices.go b/cmd/btrfs-rec/inspect_scandevices.go index 5c8b2b0..7235e45 100644 --- a/cmd/btrfs-rec/inspect_scandevices.go +++ b/cmd/btrfs-rec/inspect_scandevices.go @@ -58,17 +58,3 @@ func writeScanResults(w io.Writer, results btrfsinspect.ScanDevicesResult) (err CompactIfUnder: 16, }, results) } - -func readScanResults(filename string) (btrfsinspect.ScanDevicesResult, error) { - fh, err := os.Open(filename) - if err != nil { - return nil, err - } - var scanResults btrfsinspect.ScanDevicesResult - buf := bufio.NewReader(fh) - if err := lowmemjson.DecodeThenEOF(buf, &scanResults); err != nil { - return nil, err - } - _ = fh.Close() - return scanResults, nil -} diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index 3a00544..87e8696 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -6,7 +6,6 @@ package main import ( "context" - "encoding/json" "os" "github.com/datawire/dlib/dgroup" @@ -122,14 +121,10 @@ func main() { }() if mappingsFlag != "" { - bs, err := os.ReadFile(mappingsFlag) + mappingsJSON, err := readJSONFile[[]btrfsvol.Mapping](ctx, mappingsFlag) if err != nil { return err } - var mappingsJSON []btrfsvol.Mapping - if err := json.Unmarshal(bs, &mappingsJSON); err != nil { - return err - } for _, mapping := range mappingsJSON { if err := fs.LV.AddMapping(mapping); err != nil { return err diff --git a/cmd/btrfs-rec/util.go b/cmd/btrfs-rec/util.go new file mode 100644 index 0000000..adfe97e --- /dev/null +++ b/cmd/btrfs-rec/util.go @@ -0,0 +1,83 @@ +// Copyright (C) 2022 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package main + +import ( + "bufio" + "context" + "io" + "os" + "time" + + "git.lukeshu.com/go/lowmemjson" + "github.com/datawire/dlib/dlog" + + "git.lukeshu.com/btrfs-progs-ng/lib/textui" +) + +type runeScanner struct { + progress textui.Portion[int64] + progressWriter *textui.Progress[textui.Portion[int64]] + unreadCnt uint64 + reader *bufio.Reader + closer io.Closer +} + +func newRuneScanner(ctx context.Context, fh *os.File) (*runeScanner, error) { + fi, err := fh.Stat() + if err != nil { + return nil, err + } + ret := &runeScanner{ + progress: textui.Portion[int64]{ + D: fi.Size(), + }, + progressWriter: textui.NewProgress[textui.Portion[int64]](ctx, dlog.LogLevelInfo, 1*time.Second), + reader: bufio.NewReader(fh), + closer: fh, + } + return ret, nil +} + +func (rs *runeScanner) ReadRune() (r rune, size int, err error) { + r, size, err = rs.reader.ReadRune() + if rs.unreadCnt > 0 { + rs.unreadCnt-- + } else { + rs.progress.N += int64(size) + rs.progressWriter.Set(rs.progress) + } + return +} + +func (rs *runeScanner) UnreadRune() error { + rs.unreadCnt++ + return rs.reader.UnreadRune() +} + +func (rs *runeScanner) Close() error { + rs.progressWriter.Done() + return rs.closer.Close() +} + +func readJSONFile[T any](ctx context.Context, filename string) (T, error) { + fh, err := os.Open(filename) + if err != nil { + var zero T + return zero, err + } + buf, err := newRuneScanner(dlog.WithField(ctx, "btrfs.read-json-file", filename), fh) + if err != nil { + var zero T + return zero, err + } + var ret T + if err := lowmemjson.DecodeThenEOF(buf, &ret); err != nil { + var zero T + return zero, err + } + _ = buf.Close() + return ret, nil +} diff --git a/lib/textui/log.go b/lib/textui/log.go index 4421074..e94a24f 100644 --- a/lib/textui/log.go +++ b/lib/textui/log.go @@ -288,6 +288,8 @@ func fieldOrd(key string) int { case "btrfsinspect.rebuild-mappings.substep": return -1 + case "btrfs.read-json-file": + return -1 default: return 1 } @@ -303,6 +305,8 @@ func fieldName(key string) string { return strings.TrimPrefix(key, "btrfsinspect.scandevices.") case strings.HasPrefix(key, "btrfsinspect.rebuild-mappings."): return strings.TrimPrefix(key, "btrfsinspect.rebuild-mappings.") + case strings.HasPrefix(key, "btrfs."): + return strings.TrimPrefix(key, "btrfs.") default: return key } -- cgit v1.2.3-54-g00ecf