From f19d908439b3537cc6ae7a21eb926763e90d44ee Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 6 Mar 2023 10:34:49 -0700 Subject: cmd/btrfs-rec: Factor out a `runWithRawFS` function --- cmd/btrfs-rec/main.go | 154 ++++++++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 66 deletions(-) (limited to 'cmd/btrfs-rec/main.go') diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index bf89fbc..372dee6 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -6,6 +6,7 @@ package main import ( "context" + "fmt" "os" "github.com/datawire/dlib/dgroup" @@ -27,12 +28,24 @@ type subcommand struct { var inspectors, repairers []subcommand -func main() { - logLevelFlag := textui.LogLevelFlag{ - Level: dlog.LogLevelInfo, +var globalFlags struct { + logLevel textui.LogLevelFlag + pvs []string + mappings string + + stopProfiling profile.StopFunc + + openFlag int +} + +func noError(err error) { + if err != nil { + panic(fmt.Errorf("should not happen: %w", err)) } - var pvsFlag []string - var mappingsFlag string +} + +func main() { + // Base argparser argparser := &cobra.Command{ Use: "btrfs-rec {[flags]|SUBCOMMAND}", @@ -50,21 +63,24 @@ func main() { } argparser.SetFlagErrorFunc(cliutil.FlagErrorFunc) argparser.SetHelpTemplate(cliutil.HelpTemplate) - argparser.PersistentFlags().Var(&logLevelFlag, "verbosity", "set the verbosity") - argparser.PersistentFlags().StringArrayVar(&pvsFlag, "pv", nil, "open the file `physical_volume` as part of the filesystem") - if err := argparser.MarkPersistentFlagFilename("pv"); err != nil { - panic(err) - } - if err := argparser.MarkPersistentFlagRequired("pv"); err != nil { - panic(err) - } - argparser.PersistentFlags().StringVar(&mappingsFlag, "mappings", "", "load chunk/dev-extent/blockgroup data from external JSON file `mappings.json`") - if err := argparser.MarkPersistentFlagFilename("mappings"); err != nil { - panic(err) - } - stopProfiling := profile.AddProfileFlags(argparser.PersistentFlags(), "profile.") - openFlag := os.O_RDONLY + // Global flags + + globalFlags.logLevel.Level = dlog.LogLevelInfo + argparser.PersistentFlags().Var(&globalFlags.logLevel, "verbosity", "set the verbosity") + + argparser.PersistentFlags().StringArrayVar(&globalFlags.pvs, "pv", nil, "open the file `physical_volume` as part of the filesystem") + noError(argparser.MarkPersistentFlagFilename("pv")) + noError(argparser.MarkPersistentFlagRequired("pv")) + + argparser.PersistentFlags().StringVar(&globalFlags.mappings, "mappings", "", "load chunk/dev-extent/blockgroup data from external JSON file `mappings.json`") + noError(argparser.MarkPersistentFlagFilename("mappings")) + + globalFlags.stopProfiling = profile.AddProfileFlags(argparser.PersistentFlags(), "profile.") + + globalFlags.openFlag = os.O_RDONLY + + // Sub-commands argparserInspect := &cobra.Command{ Use: "inspect {[flags]|SUBCOMMAND}", @@ -83,7 +99,7 @@ func main() { RunE: cliutil.RunSubcommands, PersistentPreRunE: func(_ *cobra.Command, _ []string) error { - openFlag = os.O_RDWR + globalFlags.openFlag = os.O_RDWR return nil }, } @@ -99,58 +115,64 @@ func main() { for _, child := range cmdgrp.children { cmd := child.Command runE := child.RunE - cmd.RunE = func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - logger := textui.NewLogger(os.Stderr, logLevelFlag.Level) - ctx = dlog.WithLogger(ctx, logger) - if logLevelFlag.Level >= dlog.LogLevelDebug { - 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, - }) - grp.Go("main", func(ctx context.Context) (err error) { - maybeSetErr := func(_err error) { - if _err != nil && err == nil { - err = _err - } - } - defer func() { - maybeSetErr(stopProfiling()) - }() - fs, err := btrfsutil.Open(ctx, openFlag, pvsFlag...) - if err != nil { - return err - } - defer func() { - maybeSetErr(fs.Close()) - }() - - if mappingsFlag != "" { - mappingsJSON, err := readJSONFile[[]btrfsvol.Mapping](ctx, mappingsFlag) - if err != nil { - return err - } - for _, mapping := range mappingsJSON { - if err := fs.LV.AddMapping(mapping); err != nil { - return err - } - } - } - - cmd.SetContext(ctx) - return runE(fs, cmd, args) - }) - return grp.Wait() - } + cmd.RunE = runWithRawFS(runE) cmdgrp.parent.AddCommand(&cmd) } } + // Run + if err := argparser.ExecuteContext(context.Background()); err != nil { textui.Fprintf(os.Stderr, "%v: error: %v\n", argparser.CommandPath(), err) os.Exit(1) } } + +func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + logger := textui.NewLogger(os.Stderr, globalFlags.logLevel.Level) + ctx = dlog.WithLogger(ctx, logger) + if globalFlags.logLevel.Level >= dlog.LogLevelDebug { + 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, + }) + grp.Go("main", func(ctx context.Context) (err error) { + maybeSetErr := func(_err error) { + if _err != nil && err == nil { + err = _err + } + } + defer func() { + maybeSetErr(globalFlags.stopProfiling()) + }() + fs, err := btrfsutil.Open(ctx, globalFlags.openFlag, globalFlags.pvs...) + if err != nil { + return err + } + defer func() { + maybeSetErr(fs.Close()) + }() + + if globalFlags.mappings != "" { + mappingsJSON, err := readJSONFile[[]btrfsvol.Mapping](ctx, globalFlags.mappings) + if err != nil { + return err + } + for _, mapping := range mappingsJSON { + if err := fs.LV.AddMapping(mapping); err != nil { + return err + } + } + } + + cmd.SetContext(ctx) + return runE(fs, cmd, args) + }) + return grp.Wait() + } +} -- cgit v1.2.3-54-g00ecf From 058f8c36f6bf9ae2600bf7da33d680ced41eae9a Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 6 Mar 2023 10:42:51 -0700 Subject: cmd/btrfs-rec: Have each subcommand call runWithRawFS itself --- cmd/btrfs-rec/inspect_dumptrees.go | 14 +++---- cmd/btrfs-rec/inspect_lsfiles.go | 14 +++---- cmd/btrfs-rec/inspect_lstrees.go | 23 +++++------- cmd/btrfs-rec/inspect_mount.go | 19 +++++----- cmd/btrfs-rec/inspect_rebuildmappings.go | 30 +++++++-------- cmd/btrfs-rec/inspect_rebuildtrees.go | 12 +++--- cmd/btrfs-rec/inspect_scandevices.go | 12 +++--- cmd/btrfs-rec/inspect_spewitems.go | 14 +++---- cmd/btrfs-rec/main.go | 64 +++++++++++--------------------- 9 files changed, 83 insertions(+), 119 deletions(-) (limited to 'cmd/btrfs-rec/main.go') diff --git a/cmd/btrfs-rec/inspect_dumptrees.go b/cmd/btrfs-rec/inspect_dumptrees.go index efdc380..fd152d3 100644 --- a/cmd/btrfs-rec/inspect_dumptrees.go +++ b/cmd/btrfs-rec/inspect_dumptrees.go @@ -16,18 +16,16 @@ import ( ) func init() { - inspectors = append(inspectors, subcommand{ - Command: cobra.Command{ - Use: "dump-trees", - Short: "A clone of `btrfs inspect-internal dump-tree`", - Args: cliutil.WrapPositionalArgs(cobra.NoArgs), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { + inspectors.AddCommand(&cobra.Command{ + Use: "dump-trees", + Short: "A clone of `btrfs inspect-internal dump-tree`", + Args: cliutil.WrapPositionalArgs(cobra.NoArgs), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { const version = "6.1.3" out := os.Stdout textui.Fprintf(out, "btrfs-progs v%v\n", version) dumptrees.DumpTrees(cmd.Context(), out, fs) return nil - }, + }), }) } diff --git a/cmd/btrfs-rec/inspect_lsfiles.go b/cmd/btrfs-rec/inspect_lsfiles.go index 4f985ff..a2b46ab 100644 --- a/cmd/btrfs-rec/inspect_lsfiles.go +++ b/cmd/btrfs-rec/inspect_lsfiles.go @@ -26,13 +26,11 @@ import ( ) func init() { - inspectors = append(inspectors, subcommand{ - Command: cobra.Command{ - Use: "ls-files", - Short: "A listing of all files in the filesystem", - Args: cliutil.WrapPositionalArgs(cobra.NoArgs), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) { + inspectors.AddCommand(&cobra.Command{ + Use: "ls-files", + Short: "A listing of all files in the filesystem", + Args: cliutil.WrapPositionalArgs(cobra.NoArgs), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) { out := bufio.NewWriter(os.Stdout) defer func() { if _err := out.Flush(); _err != nil && err == nil { @@ -53,7 +51,7 @@ func init() { }) return nil - }, + }), }) } diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index 0c82fe0..be72860 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -27,13 +27,11 @@ import ( func init() { var scandevicesFilename string - cmd := subcommand{ - Command: cobra.Command{ - Use: "ls-trees", - Short: "A brief view what types of items are in each tree", - Args: cliutil.WrapPositionalArgs(cobra.NoArgs), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { + cmd := &cobra.Command{ + Use: "ls-trees", + Short: "A brief view what types of items are in each tree", + Args: cliutil.WrapPositionalArgs(cobra.NoArgs), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { ctx := cmd.Context() nodeList, err := readNodeList(ctx, scandevicesFilename) if err != nil { @@ -114,11 +112,10 @@ func init() { } return nil - }, + }), } - cmd.Command.Flags().StringVar(&scandevicesFilename, "scandevices", "", "Output of 'scandevices' to use for a lost+found tree") - if err := cmd.Command.MarkFlagFilename("scandevices"); err != nil { - panic(err) - } - inspectors = append(inspectors, cmd) + cmd.Flags().StringVar(&scandevicesFilename, "scandevices", "", "Output of 'scandevices' to use for a lost+found tree") + noError(cmd.MarkFlagFilename("scandevices")) + + inspectors.AddCommand(cmd) } diff --git a/cmd/btrfs-rec/inspect_mount.go b/cmd/btrfs-rec/inspect_mount.go index f3fda34..4582f9f 100644 --- a/cmd/btrfs-rec/inspect_mount.go +++ b/cmd/btrfs-rec/inspect_mount.go @@ -14,17 +14,16 @@ import ( func init() { var skipFileSums bool - cmd := subcommand{ - Command: cobra.Command{ - Use: "mount MOUNTPOINT", - Short: "Mount the filesystem read-only", - Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { + cmd := &cobra.Command{ + Use: "mount MOUNTPOINT", + Short: "Mount the filesystem read-only", + Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { return mount.MountRO(cmd.Context(), fs, args[0], skipFileSums) - }, + }), } - cmd.Command.Flags().BoolVar(&skipFileSums, "skip-filesums", false, + cmd.Flags().BoolVar(&skipFileSums, "skip-filesums", false, "ignore checksum failures on file contents; allow such files to be read") - inspectors = append(inspectors, cmd) + + inspectors.AddCommand(cmd) } diff --git a/cmd/btrfs-rec/inspect_rebuildmappings.go b/cmd/btrfs-rec/inspect_rebuildmappings.go index 005fd5d..81660b0 100644 --- a/cmd/btrfs-rec/inspect_rebuildmappings.go +++ b/cmd/btrfs-rec/inspect_rebuildmappings.go @@ -17,21 +17,19 @@ import ( ) func init() { - inspectors = append(inspectors, subcommand{ - Command: cobra.Command{ - Use: "rebuild-mappings SCAN_RESULT.json", - 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.ExactArgs(1)), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { + inspectors.AddCommand(&cobra.Command{ + Use: "rebuild-mappings SCAN_RESULT.json", + 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.ExactArgs(1)), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { ctx := cmd.Context() dlog.Infof(ctx, "Reading %q...", args[0]) @@ -56,6 +54,6 @@ func init() { dlog.Info(ctx, "... done writing") return nil - }, + }), }) } diff --git a/cmd/btrfs-rec/inspect_rebuildtrees.go b/cmd/btrfs-rec/inspect_rebuildtrees.go index 5d782cf..8c6fc92 100644 --- a/cmd/btrfs-rec/inspect_rebuildtrees.go +++ b/cmd/btrfs-rec/inspect_rebuildtrees.go @@ -21,12 +21,10 @@ import ( ) func init() { - inspectors = append(inspectors, subcommand{ - Command: cobra.Command{ - Use: "rebuild-nodes NODESCAN.json", - Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { + inspectors.AddCommand(&cobra.Command{ + Use: "rebuild-nodes NODESCAN.json", + Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { ctx := cmd.Context() // This is wrapped in a func in order to *ensure* that `nodeList` goes out of scope once @@ -66,6 +64,6 @@ func init() { dlog.Info(ctx, "... done writing") return rebuildErr - }, + }), }) } diff --git a/cmd/btrfs-rec/inspect_scandevices.go b/cmd/btrfs-rec/inspect_scandevices.go index f93d99d..4172c7c 100644 --- a/cmd/btrfs-rec/inspect_scandevices.go +++ b/cmd/btrfs-rec/inspect_scandevices.go @@ -21,12 +21,10 @@ import ( ) func init() { - inspectors = append(inspectors, subcommand{ - Command: cobra.Command{ - Use: "scandevices", - Args: cliutil.WrapPositionalArgs(cobra.NoArgs), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) { + inspectors.AddCommand(&cobra.Command{ + Use: "scandevices", + Args: cliutil.WrapPositionalArgs(cobra.NoArgs), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) { ctx := cmd.Context() results, err := rebuildmappings.ScanDevices(ctx, fs) @@ -45,7 +43,7 @@ func init() { dlog.Info(ctx, "... done writing") return nil - }, + }), }) } diff --git a/cmd/btrfs-rec/inspect_spewitems.go b/cmd/btrfs-rec/inspect_spewitems.go index 4abb2b0..d8a65ae 100644 --- a/cmd/btrfs-rec/inspect_spewitems.go +++ b/cmd/btrfs-rec/inspect_spewitems.go @@ -19,13 +19,11 @@ import ( ) func init() { - inspectors = append(inspectors, subcommand{ - Command: cobra.Command{ - Use: "spew-items", - Short: "Spew all items as parsed", - Args: cliutil.WrapPositionalArgs(cobra.NoArgs), - }, - RunE: func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { + inspectors.AddCommand(&cobra.Command{ + Use: "spew-items", + Short: "Spew all items as parsed", + Args: cliutil.WrapPositionalArgs(cobra.NoArgs), + RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error { ctx := cmd.Context() spew := spew.NewDefaultConfig() @@ -51,6 +49,6 @@ func init() { }, }) return nil - }, + }), }) } diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index 372dee6..5da8f52 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -21,12 +21,27 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) -type subcommand struct { - cobra.Command - RunE func(*btrfs.FS, *cobra.Command, []string) error -} +var ( + inspectors = &cobra.Command{ + Use: "inspect {[flags]|SUBCOMMAND}", + Short: "Inspect (but don't modify) a broken btrfs filesystem", -var inspectors, repairers []subcommand + Args: cliutil.WrapPositionalArgs(cliutil.OnlySubcommands), + RunE: cliutil.RunSubcommands, + } + repairers = &cobra.Command{ + Use: "repair {[flags]|SUBCOMMAND}", + Short: "Repair a broken btrfs filesystem", + + Args: cliutil.WrapPositionalArgs(cliutil.OnlySubcommands), + RunE: cliutil.RunSubcommands, + + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + globalFlags.openFlag = os.O_RDWR + return nil + }, + } +) var globalFlags struct { logLevel textui.LogLevelFlag @@ -82,43 +97,8 @@ func main() { // Sub-commands - argparserInspect := &cobra.Command{ - Use: "inspect {[flags]|SUBCOMMAND}", - Short: "Inspect (but don't modify) a broken btrfs filesystem", - - Args: cliutil.WrapPositionalArgs(cliutil.OnlySubcommands), - RunE: cliutil.RunSubcommands, - } - argparser.AddCommand(argparserInspect) - - argparserRepair := &cobra.Command{ - Use: "repair {[flags]|SUBCOMMAND}", - Short: "Repair a broken btrfs filesystem", - - Args: cliutil.WrapPositionalArgs(cliutil.OnlySubcommands), - RunE: cliutil.RunSubcommands, - - PersistentPreRunE: func(_ *cobra.Command, _ []string) error { - globalFlags.openFlag = os.O_RDWR - return nil - }, - } - argparser.AddCommand(argparserRepair) - - for _, cmdgrp := range []struct { - parent *cobra.Command - children []subcommand - }{ - {argparserInspect, inspectors}, - {argparserRepair, repairers}, - } { - for _, child := range cmdgrp.children { - cmd := child.Command - runE := child.RunE - cmd.RunE = runWithRawFS(runE) - cmdgrp.parent.AddCommand(&cmd) - } - } + argparser.AddCommand(inspectors) + argparser.AddCommand(repairers) // Run -- cgit v1.2.3-54-g00ecf From 7c9ea276ac69130229f4ae35547288fe8429f6f1 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Mar 2023 01:45:05 -0700 Subject: cmd/btrfs-rec: Don't require --pv for `help` --- cmd/btrfs-rec/main.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'cmd/btrfs-rec/main.go') diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index 5da8f52..343a41f 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -86,7 +86,6 @@ func main() { argparser.PersistentFlags().StringArrayVar(&globalFlags.pvs, "pv", nil, "open the file `physical_volume` as part of the filesystem") noError(argparser.MarkPersistentFlagFilename("pv")) - noError(argparser.MarkPersistentFlagRequired("pv")) argparser.PersistentFlags().StringVar(&globalFlags.mappings, "mappings", "", "load chunk/dev-extent/blockgroup data from external JSON file `mappings.json`") noError(argparser.MarkPersistentFlagFilename("mappings")) @@ -130,6 +129,11 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co defer func() { maybeSetErr(globalFlags.stopProfiling()) }() + if len(globalFlags.pvs) == 0 { + // We do this here instead of calling argparser.MarkPersistentFlagRequired("pv") so that + // it doesn't interfere with the `help` sub-command. + return cliutil.FlagErrorFunc(cmd, fmt.Errorf("must specify 1 or more physical volumes with --pv")) + } fs, err := btrfsutil.Open(ctx, globalFlags.openFlag, globalFlags.pvs...) if err != nil { return err -- cgit v1.2.3-54-g00ecf From afd2fe91ec604491bd8978b1880c6482e7394240 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 10 Mar 2023 22:02:23 -0700 Subject: cmd/btrfs-rec: inspect rebuild-mappings list-nodes: Set up logging and stuff --- cmd/btrfs-rec/inspect_rebuildmappings.go | 4 +-- cmd/btrfs-rec/main.go | 59 +++++++++++++++++++------------- 2 files changed, 38 insertions(+), 25 deletions(-) (limited to 'cmd/btrfs-rec/main.go') diff --git a/cmd/btrfs-rec/inspect_rebuildmappings.go b/cmd/btrfs-rec/inspect_rebuildmappings.go index b215e7a..43c45b1 100644 --- a/cmd/btrfs-rec/inspect_rebuildmappings.go +++ b/cmd/btrfs-rec/inspect_rebuildmappings.go @@ -129,7 +129,7 @@ func init() { "advantage of using previously read data from " + "`btrfs-rec inspect rebuild-nodes scan`.", Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: run(func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() scanResults, err := readJSONFile[rebuildmappings.ScanDevicesResult](ctx, args[0]) @@ -159,7 +159,7 @@ func init() { dlog.Info(ctx, "... done writing") return nil - }, + }), }) inspectors.AddCommand(cmd) diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index 343a41f..15f1964 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -107,7 +107,7 @@ func main() { } } -func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*cobra.Command, []string) error { +func run(runE func(*cobra.Command, []string) error) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() logger := textui.NewLogger(os.Stderr, globalFlags.logLevel.Level) @@ -126,37 +126,50 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co err = _err } } + defer func() { maybeSetErr(globalFlags.stopProfiling()) }() - if len(globalFlags.pvs) == 0 { - // We do this here instead of calling argparser.MarkPersistentFlagRequired("pv") so that - // it doesn't interfere with the `help` sub-command. - return cliutil.FlagErrorFunc(cmd, fmt.Errorf("must specify 1 or more physical volumes with --pv")) + cmd.SetContext(ctx) + return runE(cmd, args) + }) + return grp.Wait() + } +} + +func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*cobra.Command, []string) error { + return run(func(cmd *cobra.Command, args []string) (err error) { + maybeSetErr := func(_err error) { + if _err != nil && err == nil { + err = _err } - fs, err := btrfsutil.Open(ctx, globalFlags.openFlag, globalFlags.pvs...) + } + + if len(globalFlags.pvs) == 0 { + // We do this here instead of calling argparser.MarkPersistentFlagRequired("pv") so that + // it doesn't interfere with the `help` sub-command. + return cliutil.FlagErrorFunc(cmd, fmt.Errorf("must specify 1 or more physical volumes with --pv")) + } + fs, err := btrfsutil.Open(cmd.Context(), globalFlags.openFlag, globalFlags.pvs...) + if err != nil { + return err + } + defer func() { + maybeSetErr(fs.Close()) + }() + + if globalFlags.mappings != "" { + mappingsJSON, err := readJSONFile[[]btrfsvol.Mapping](cmd.Context(), globalFlags.mappings) if err != nil { return err } - defer func() { - maybeSetErr(fs.Close()) - }() - - if globalFlags.mappings != "" { - mappingsJSON, err := readJSONFile[[]btrfsvol.Mapping](ctx, globalFlags.mappings) - if err != nil { + for _, mapping := range mappingsJSON { + if err := fs.LV.AddMapping(mapping); err != nil { return err } - for _, mapping := range mappingsJSON { - if err := fs.LV.AddMapping(mapping); err != nil { - return err - } - } } + } - cmd.SetContext(ctx) - return runE(fs, cmd, args) - }) - return grp.Wait() - } + return runE(fs, cmd, args) + }) } -- cgit v1.2.3-54-g00ecf