summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-03-06 10:34:49 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-03-14 21:31:45 -0600
commitf19d908439b3537cc6ae7a21eb926763e90d44ee (patch)
tree54fd9de19fbbfc35f3b75bcea5ba60adf1920beb
parent5f45fa7d378edae2fac73517384749fc73d24e89 (diff)
cmd/btrfs-rec: Factor out a `runWithRawFS` function
-rw-r--r--cmd/btrfs-rec/main.go154
1 files changed, 88 insertions, 66 deletions
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()
+ }
+}