summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-07-11 00:43:59 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-07-11 00:48:10 -0600
commit0f853e1ead10347be8c5715d6bb797dd5e643e2f (patch)
tree688e9a9b2e57058906f3501a3d9bdc894b83c784
parentad9ac6d07ce1819260c2b7f090fd4fe742c80d9f (diff)
wip btrfs-rec
-rw-r--r--cmd/btrfs-rec/main.go145
-rw-r--r--go.mod10
-rw-r--r--go.sum20
3 files changed, 169 insertions, 6 deletions
diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go
new file mode 100644
index 0000000..9b285b1
--- /dev/null
+++ b/cmd/btrfs-rec/main.go
@@ -0,0 +1,145 @@
+// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package main
+
+import (
+ "context"
+ "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/btrfsprogs/btrfsutil"
+)
+
+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
+}
+
+var inspectors, repairers []subcommand
+
+func main() {
+ logLevelFlag := logLevelFlag{
+ Level: logrus.InfoLevel,
+ }
+ var pvsFlag []string
+
+ argparser := &cobra.Command{
+ Use: "btrfs-rec {[flags]|SUBCOMMAND}",
+ Short: "Recover (data from) a broken btrfs filesystem",
+
+ Args: cliutil.WrapPositionalArgs(cliutil.OnlySubcommands),
+ RunE: cliutil.RunSubcommands,
+
+ SilenceErrors: true, // main() will handle this after .ExecuteContext() returns
+ SilenceUsage: true, // our FlagErrorFunc will handle it
+
+ CompletionOptions: cobra.CompletionOptions{ //nolint:exhaustivestruct
+ DisableDefaultCmd: true,
+ },
+ }
+ 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)
+ }
+
+ var openFlag int = os.O_RDONLY
+
+ argparserInspect := &cobra.Command{
+ Use: "inpsect {[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 {
+ 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 = func(cmd *cobra.Command, args []string) error {
+ ctx := cmd.Context()
+ logger := logrus.New()
+ logger.SetLevel(logLevelFlag.Level)
+ ctx = dlog.WithLogger(ctx, dlog.WrapLogrus(logger))
+
+ 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
+ }
+ }
+ fs, err := btrfsutil.Open(openFlag, pvsFlag...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ maybeSetErr(fs.Close())
+ }()
+
+ cmd.SetContext(ctx)
+ return runE(fs, cmd, args)
+ })
+ return grp.Wait()
+ }
+ cmdgrp.parent.AddCommand(&cmd)
+ }
+ }
+
+ if err := argparser.ExecuteContext(context.Background()); err != nil {
+ fmt.Fprintf(os.Stderr, "%v: error: %v\n", argparser.CommandPath(), err)
+ os.Exit(1)
+ }
+}
diff --git a/go.mod b/go.mod
index d8b9435..06fba4f 100644
--- a/go.mod
+++ b/go.mod
@@ -8,9 +8,12 @@ go 1.18
require (
github.com/datawire/dlib v1.3.0
+ github.com/datawire/ocibuild v0.0.3-0.20220423003204-fc6a4e9f90dc
github.com/hashicorp/golang-lru v0.5.4
github.com/jacobsa/fuse v0.0.0-20220702091825-13117049f383
- github.com/sirupsen/logrus v1.6.0
+ github.com/sirupsen/logrus v1.8.1
+ github.com/spf13/cobra v1.5.0
+ github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.1
golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf
golang.org/x/text v0.3.7
@@ -18,11 +21,12 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
+ github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
- gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
+ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
replace github.com/jacobsa/fuse => github.com/lukeshu/jacobsa-fuse v0.0.0-20220706162300-f42bfdd0fc53
diff --git a/go.sum b/go.sum
index 6257be3..54ec6ae 100644
--- a/go.sum
+++ b/go.sum
@@ -1,11 +1,15 @@
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/datawire/dlib v1.3.0 h1:KkmyXU1kwm3oPBk1ypR70YbcOlEXWzEbx5RE0iRXTGk=
github.com/datawire/dlib v1.3.0/go.mod h1:NiGDmetmbkBvtznpWSx6C0vA0s0LK9aHna3LJDqjruk=
+github.com/datawire/ocibuild v0.0.3-0.20220423003204-fc6a4e9f90dc h1:KxDUPTmAaElhEBYke7Vlw9I/EM/a5zl8LT1yCHkm44I=
+github.com/datawire/ocibuild v0.0.3-0.20220423003204-fc6a4e9f90dc/go.mod h1:d10QlP0Pm/xTS9V9UP2AOJ99IlFvmQ4CLP/9bIggczo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -19,8 +23,14 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
+github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -31,9 +41,11 @@ golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf/go.mod h1:yh0Ynu2b5ZUe3MQfp2
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
@@ -42,5 +54,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=