diff options
Diffstat (limited to 'cmd/btrfs-rec/inspect_recoverchunks.go')
-rw-r--r-- | cmd/btrfs-rec/inspect_recoverchunks.go | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/cmd/btrfs-rec/inspect_recoverchunks.go b/cmd/btrfs-rec/inspect_recoverchunks.go new file mode 100644 index 0000000..bc32248 --- /dev/null +++ b/cmd/btrfs-rec/inspect_recoverchunks.go @@ -0,0 +1,75 @@ +// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package main + +import ( + "encoding/json" + "fmt" + "io" + "os" + + "github.com/datawire/dlib/dlog" + "github.com/datawire/ocibuild/pkg/cliutil" + "github.com/spf13/cobra" + + "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" + "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect" +) + +func init() { + inspectors = append(inspectors, subcommand{ + Command: cobra.Command{ + Use: "recover-chunks", + Short: "Rebuild broken chunk/dev-extent/blockgroup trees", + Long: "" + + "The rebuilt information is printed as JSON on stdout, and can\n" + + "be loaded by the --mappings flag.\n" + + "\n" + + "This is very similar to `btrfs rescue chunk-recover`, but (1)\n" + + "does a better job, (2) is less buggy, and (3) doesn't actually\n" + + "write the info back to the filesystem; instead writing it\n" + + "out-of-band to stdout.", + Args: cliutil.WrapPositionalArgs(cobra.NoArgs), + }, + RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + + dlog.Info(ctx, "Reading superblock...") + superblock, err := fs.Superblock() + if err != nil { + return err + } + + for _, dev := range fs.LV.PhysicalVolumes() { + dlog.Infof(ctx, "dev[%q] Scanning for unreachable nodes...", dev.Name()) + devResult, err := btrfsinspect.ScanOneDev(ctx, dev, superblock.Data) + if err != nil { + return err + } + + dlog.Infof(ctx, "dev[%q] Re-inserting lost+found mappings...", dev.Name()) + devResult.AddToLV(ctx, fs, dev) + } + + dlog.Infof(ctx, "Writing reconstructed mappings to stdout...") + + mappings := fs.LV.Mappings() + _, _ = io.WriteString(os.Stdout, "{\n \"Mappings\": [\n") + for i, mapping := range mappings { + suffix := "," + if i == len(mappings)-1 { + suffix = "" + } + bs, err := json.Marshal(mapping) + if err != nil { + return err + } + fmt.Printf(" %s%s\n", bs, suffix) + } + _, _ = io.WriteString(os.Stdout, " ]\n}\n") + return nil + }, + }) +} |