...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package helper
17
18 import (
19 "fmt"
20 "os"
21 "path/filepath"
22
23 "github.com/moby/sys/mountinfo"
24 "github.com/pkg/errors"
25 "github.com/spf13/cobra"
26 )
27
28 var NormalizeVolumeNameCmd = &cobra.Command{
29 Use: "normalize-volume-name [path]",
30 Short: "get the device name from the path",
31 Long: `Get the device name from the path.
32 The path could be a directory, a partition, or a block device.
33 The block device name will be printed out.`,
34 Run: func(cmd *cobra.Command, args []string) {
35 if len(args) != 1 {
36 cmd.Help()
37 os.Exit(1)
38 }
39
40 volumePath := args[0]
41 deviceName, err := normalizeVolumeName(volumePath)
42 if err != nil {
43 fmt.Fprintln(os.Stderr, err)
44 os.Exit(1)
45 }
46
47 fmt.Println(deviceName)
48 },
49 }
50
51 func normalizeVolumeName(volumePath string) (string, error) {
52
53
54
55
56
57
58
59
60
61
62 volumePath, err := filepath.EvalSymlinks(volumePath)
63 if err != nil {
64 return "", errors.Wrapf(err, "resolving symlink %s", volumePath)
65 }
66
67 stat, err := os.Stat(volumePath)
68 if err != nil {
69 return "", errors.Wrapf(err, "getting stat of %s", volumePath)
70 }
71
72 if stat.IsDir() {
73 parentMounts, err := mountinfo.GetMounts(mountinfo.ParentsFilter(volumePath))
74 if err != nil {
75 return "", errors.Wrap(err, "read mountinfo")
76 }
77
78 if len(parentMounts) == 0 {
79 return "", errors.Errorf("cannot find the mount point which contains the volume path %s", volumePath)
80 }
81
82 bestMatch := &mountinfo.Info{}
83 for _, mount := range parentMounts {
84 mount := mount
85 if len(mount.Mountpoint) > len(bestMatch.Mountpoint) {
86 bestMatch = mount
87 }
88 }
89
90 if bestMatch.Source == "none" || len(bestMatch.Source) == 0 {
91 return "", errors.Errorf("unknown source of the mount point %v", bestMatch)
92 }
93 volumePath = bestMatch.Source
94 }
95
96
97 volumeName := filepath.Base(volumePath)
98
99
100 if _, err := os.Stat("/sys/block/" + volumeName); errors.Is(err, os.ErrNotExist) {
101
102 partitionSysPath, err := filepath.EvalSymlinks("/sys/class/block/" + volumeName)
103 if err != nil {
104 return "", errors.Wrapf(err, "resolving symlink %s", "/sys/class/block/"+volumeName)
105 }
106
107 volumeName = filepath.Base(filepath.Dir(partitionSysPath))
108 }
109 return volumeName, nil
110 }
111
112
113
114
115
116