File: main_shift.go

package info (click to toggle)
incus 6.0.5-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 25,788 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (101 lines) | stat: -rw-r--r-- 2,343 bytes parent folder | download | duplicates (3)
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
}