summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/btrfs-rec/inspect_dumptrees.go7
-rw-r--r--cmd/btrfs-rec/inspect_lsfiles.go29
-rw-r--r--cmd/btrfs-rec/inspect_lstrees.go24
-rw-r--r--cmd/btrfs-rec/inspect_rebuildmappings.go3
-rw-r--r--cmd/btrfs-rec/inspect_rebuildnodes.go3
-rw-r--r--cmd/btrfs-rec/inspect_scandevices.go14
-rw-r--r--cmd/btrfs-rec/inspect_spewitems.go6
-rw-r--r--cmd/btrfs-rec/main.go37
-rw-r--r--cmd/btrfs-rec/util.go83
9 files changed, 129 insertions, 77 deletions
diff --git a/cmd/btrfs-rec/inspect_dumptrees.go b/cmd/btrfs-rec/inspect_dumptrees.go
index 4abeaba..610f502 100644
--- a/cmd/btrfs-rec/inspect_dumptrees.go
+++ b/cmd/btrfs-rec/inspect_dumptrees.go
@@ -5,7 +5,6 @@
package main
import (
- "fmt"
"os"
"github.com/datawire/ocibuild/pkg/cliutil"
@@ -13,6 +12,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect"
+ "git.lukeshu.com/btrfs-progs-ng/lib/textui"
)
func init() {
@@ -24,8 +24,9 @@ func init() {
},
RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error {
const version = "5.18.1"
- fmt.Printf("btrfs-progs v%v\n", version)
- btrfsinspect.DumpTrees(cmd.Context(), os.Stdout, fs)
+ out := os.Stdout
+ textui.Fprintf(out, "btrfs-progs v%v\n", version)
+ btrfsinspect.DumpTrees(cmd.Context(), out, fs)
return nil
},
})
diff --git a/cmd/btrfs-rec/inspect_lsfiles.go b/cmd/btrfs-rec/inspect_lsfiles.go
index 9267f77..502d91d 100644
--- a/cmd/btrfs-rec/inspect_lsfiles.go
+++ b/cmd/btrfs-rec/inspect_lsfiles.go
@@ -22,6 +22,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/maps"
+ "git.lukeshu.com/btrfs-progs-ng/lib/textui"
)
func init() {
@@ -32,20 +33,20 @@ func init() {
Args: cliutil.WrapPositionalArgs(cobra.NoArgs),
},
RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) {
+ out := bufio.NewWriter(os.Stdout)
+ defer out.Flush()
defer func() {
if r := derror.PanicToError(recover()); r != nil {
- fmt.Printf("\n\n%+v\n", r)
+ textui.Fprintf(out, "\n\n%+v\n", r)
err = fmt.Errorf("panicked")
}
}()
ctx := cmd.Context()
- out := bufio.NewWriter(os.Stdout)
printSubvol(out, "", true, "/", &btrfs.Subvolume{
FS: btrfsutil.NewBrokenTrees(ctx, fs),
TreeID: btrfsprim.FS_TREE_OBJECTID,
})
- out.Flush()
return nil
},
@@ -64,7 +65,7 @@ func printText(out io.Writer, prefix string, isLast bool, name, text string) {
if isLast {
first, rest = tL, tS
}
- for i, line := range strings.Split(fmt.Sprintf("%q %s", name, text), "\n") {
+ for i, line := range strings.Split(textui.Sprintf("%q %s", name, text), "\n") {
_, _ = io.WriteString(out, prefix)
if i == 0 {
_, _ = io.WriteString(out, first)
@@ -79,13 +80,13 @@ func printText(out io.Writer, prefix string, isLast bool, name, text string) {
func printSubvol(out io.Writer, prefix string, isLast bool, name string, subvol *btrfs.Subvolume) {
rootInode, err := subvol.GetRootInode()
if err != nil {
- printText(out, prefix, isLast, name+"/", fmt.Sprintf("subvol_id=%v err=%v",
+ printText(out, prefix, isLast, name+"/", textui.Sprintf("subvol_id=%v err=%v",
subvol.TreeID, fmtErr(err)))
return
}
dir, err := subvol.LoadDir(rootInode)
if err != nil {
- printText(out, prefix, isLast, name+"/", fmt.Sprintf("subvol_id=%v err=%v",
+ printText(out, prefix, isLast, name+"/", textui.Sprintf("subvol_id=%v err=%v",
subvol.TreeID, fmtErr(err)))
return
}
@@ -93,7 +94,7 @@ func printSubvol(out io.Writer, prefix string, isLast bool, name string, subvol
printDir(out, prefix, isLast, name, dir)
return
}
- printText(out, prefix, isLast, name+"/", fmt.Sprintf("subvol_id=%v", subvol.TreeID))
+ printText(out, prefix, isLast, name+"/", textui.Sprintf("subvol_id=%v", subvol.TreeID))
if isLast {
prefix += tS
} else {
@@ -117,7 +118,7 @@ func fmtInode(inode btrfs.BareInode) string {
} else {
mode = inode.InodeItem.Mode
}
- ret := fmt.Sprintf("ino=%v mode=%v", inode.Inode, mode)
+ ret := textui.Sprintf("ino=%v mode=%v", inode.Inode, mode)
if len(inode.Errs) > 0 {
ret += " err=" + fmtErr(inode.Errs)
}
@@ -152,7 +153,7 @@ func printDirEntry(out io.Writer, prefix string, isLast bool, subvol *btrfs.Subv
case btrfsitem.INODE_ITEM_KEY:
dir, err := subvol.LoadDir(entry.Location.ObjectID)
if err != nil {
- printText(out, prefix, isLast, name, fmt.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
+ printText(out, prefix, isLast, name, textui.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
return
}
printDir(out, prefix, isLast, name, dir)
@@ -172,7 +173,7 @@ func printDirEntry(out io.Writer, prefix string, isLast bool, subvol *btrfs.Subv
}
file, err := subvol.LoadFile(entry.Location.ObjectID)
if err != nil {
- printText(out, prefix, isLast, name, fmt.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
+ printText(out, prefix, isLast, name, textui.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
return
}
printSymlink(out, prefix, isLast, name, file)
@@ -183,7 +184,7 @@ func printDirEntry(out io.Writer, prefix string, isLast bool, subvol *btrfs.Subv
}
file, err := subvol.LoadFile(entry.Location.ObjectID)
if err != nil {
- printText(out, prefix, isLast, name, fmt.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
+ printText(out, prefix, isLast, name, textui.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
return
}
printFile(out, prefix, isLast, name, file)
@@ -194,7 +195,7 @@ func printDirEntry(out io.Writer, prefix string, isLast bool, subvol *btrfs.Subv
}
file, err := subvol.LoadFile(entry.Location.ObjectID)
if err != nil {
- printText(out, prefix, isLast, name, fmt.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
+ printText(out, prefix, isLast, name, textui.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
return
}
printSocket(out, prefix, isLast, name, file)
@@ -205,7 +206,7 @@ func printDirEntry(out io.Writer, prefix string, isLast bool, subvol *btrfs.Subv
}
file, err := subvol.LoadFile(entry.Location.ObjectID)
if err != nil {
- printText(out, prefix, isLast, name, fmt.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
+ printText(out, prefix, isLast, name, textui.Sprintf("%v err=%v", entry.Type, fmtErr(err)))
return
}
printPipe(out, prefix, isLast, name, file)
@@ -224,7 +225,7 @@ func printSymlink(out io.Writer, prefix string, isLast bool, name string, file *
file.Errs = append(file.Errs, err)
}
}
- printText(out, prefix, isLast, name, fmt.Sprintf(
+ printText(out, prefix, isLast, name, textui.Sprintf(
"-> %q : %s",
tgt,
fmtInode(file.BareInode)))
diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go
index 54c2074..e92c544 100644
--- a/cmd/btrfs-rec/inspect_lstrees.go
+++ b/cmd/btrfs-rec/inspect_lstrees.go
@@ -5,8 +5,6 @@
package main
import (
- "encoding/json"
- "fmt"
"os"
"strconv"
"text/tabwriter"
@@ -25,6 +23,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() {
@@ -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
@@ -57,19 +55,19 @@ 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])
- 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)
- 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 +96,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 {
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/inspect_spewitems.go b/cmd/btrfs-rec/inspect_spewitems.go
index a4e8d69..8d71797 100644
--- a/cmd/btrfs-rec/inspect_spewitems.go
+++ b/cmd/btrfs-rec/inspect_spewitems.go
@@ -5,7 +5,6 @@
package main
import (
- "fmt"
"os"
"github.com/datawire/dlib/dlog"
@@ -16,6 +15,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
+ "git.lukeshu.com/btrfs-progs-ng/lib/textui"
)
func init() {
@@ -37,13 +37,13 @@ func init() {
},
TreeWalkHandler: btrfstree.TreeWalkHandler{
Item: func(path btrfstree.TreePath, item btrfstree.Item) error {
- fmt.Printf("%s = ", path)
+ textui.Fprintf(os.Stdout, "%s = ", path)
spew.Dump(item)
os.Stdout.WriteString("\n")
return nil
},
BadItem: func(path btrfstree.TreePath, item btrfstree.Item) error {
- fmt.Printf("%s = ", path)
+ textui.Fprintf(os.Stdout, "%s = ", path)
spew.Dump(item)
os.Stdout.WriteString("\n")
return nil
diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go
index c808237..13ae886 100644
--- a/cmd/btrfs-rec/main.go
+++ b/cmd/btrfs-rec/main.go
@@ -6,35 +6,19 @@ package main
import (
"context"
- "encoding/json"
- "fmt"
"os"
"github.com/datawire/dlib/dgroup"
"github.com/datawire/dlib/dlog"
"github.com/datawire/ocibuild/pkg/cliutil"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "github.com/spf13/pflag"
"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 {
- logrus.Level
-}
-
-func (lvl *logLevelFlag) Type() string { return "loglevel" }
-func (lvl *logLevelFlag) Set(str string) error {
- var err error
- lvl.Level, err = logrus.ParseLevel(str)
- return err
-}
-
-var _ pflag.Value = (*logLevelFlag)(nil)
-
type subcommand struct {
cobra.Command
RunE func(*btrfs.FS, *cobra.Command, []string) error
@@ -43,8 +27,8 @@ type subcommand struct {
var inspectors, repairers []subcommand
func main() {
- logLevelFlag := logLevelFlag{
- Level: logrus.InfoLevel,
+ logLevelFlag := textui.LogLevelFlag{
+ Level: dlog.LogLevelInfo,
}
var pvsFlag []string
var mappingsFlag string
@@ -115,9 +99,10 @@ func main() {
runE := child.RunE
cmd.RunE = func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
- logger := logrus.New()
- logger.SetLevel(logLevelFlag.Level)
- ctx = dlog.WithLogger(ctx, dlog.WrapLogrus(logger))
+ logger := textui.NewLogger(os.Stderr, logLevelFlag.Level)
+ ctx = dlog.WithLogger(ctx, logger)
+ ctx = dlog.WithField(ctx, "mem", new(textui.LiveMemUse))
+ dlog.SetFallbackLogger(logger.WithField("btrfs-progs.THIS_IS_A_BUG", true))
grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{
EnableSignalHandling: true,
@@ -137,14 +122,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
@@ -162,7 +143,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/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 <lukeshu@lukeshu.com>
+//
+// 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
+}