1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
package main
import (
"errors"
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/lxc/incus/v6/shared/idmap"
)
type cmdShift struct {
global *cmdGlobal
flagReverse bool
flagTestMode bool
}
func (c *cmdShift) Command() *cobra.Command {
cmd := &cobra.Command{}
cmd.Use = "fuidshift <directory> <range> [<range>...]"
cmd.Short = "UID/GID shifter"
cmd.Long = `Description:
UID/GID shifter
This tool lets you remap a filesystem tree, switching it from one
set of UID/GID ranges to another.
This is mostly useful when retrieving a wrongly shifted filesystem tree
from a backup or broken system and having to remap everything either to
the host UID/GID range (uid/gid 0 is root) or to an existing container's
range.
A range is represented as <u|b|g>:<first_container_id>:<first_host_id>:<size>.
Where "u" means shift uid, "g" means shift gid and "b" means shift uid and gid.
`
cmd.Example = ` fuidshift my-dir/ b:0:100000:65536 u:10000:1000:1`
cmd.RunE = c.Run
cmd.Flags().BoolVarP(&c.flagTestMode, "test", "t", false, "Test mode (no change to files)")
cmd.Flags().BoolVarP(&c.flagReverse, "reverse", "r", false, "Perform a reverse mapping")
return cmd
}
func (c *cmdShift) Run(cmd *cobra.Command, args []string) error {
// Help and usage
if len(args) == 0 {
return cmd.Help()
}
// Quick checks.
if !c.flagTestMode && os.Geteuid() != 0 {
return errors.New("This tool must be run as root")
}
// Handle mandatory arguments
if len(args) < 2 {
_ = cmd.Help()
return errors.New("Missing required arguments")
}
directory := args[0]
var skipper func(dir string, absPath string, fi os.FileInfo, newuid int64, newgid int64) error
if c.flagTestMode {
skipper = func(dir string, absPath string, fi os.FileInfo, newuid int64, newgid int64) error {
fmt.Printf("I would shift %q to %d %d\n", absPath, newuid, newgid)
return errors.New("dry run")
}
}
// Parse the maps
idmapSet := &idmap.Set{}
for _, arg := range args[1:] {
var err error
idmapSet, err = idmapSet.Append(arg)
if err != nil {
return err
}
}
// Reverse shifting
if c.flagReverse {
err := idmapSet.UnshiftPath(directory, skipper)
if err != nil {
return err
}
return nil
}
// Normal shifting
err := idmapSet.ShiftPath(directory, skipper)
if err != nil {
return err
}
return nil
}
|