forked from cisco-app-networking/networkservicemesh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fsutils.go
111 lines (100 loc) · 2.59 KB
/
fsutils.go
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
102
103
104
105
106
107
108
109
110
111
package fs
import (
"io/ioutil"
"os"
"path"
"strconv"
"strings"
"syscall"
"unicode"
"github.com/pkg/errors"
"github.com/vishvananda/netns"
"github.com/sirupsen/logrus"
)
func isDigits(s string) bool {
for _, c := range s {
if !unicode.IsDigit(c) {
return false
}
}
return true
}
// GetInode returns Inode for file
func GetInode(file string) (uint64, error) {
fileinfo, err := os.Stat(file)
if err != nil {
return 0, errors.Wrap(err, "error stat file")
}
stat, ok := fileinfo.Sys().(*syscall.Stat_t)
if !ok {
return 0, errors.New("not a stat_t")
}
return stat.Ino, nil
}
// ResolvePodNsByInode Traverse /proc/<pid>/<suffix> files,
// compare their inodes with inode parameter and returns file if inode matches
func ResolvePodNsByInode(inode uint64) (string, error) {
files, err := ioutil.ReadDir("/proc")
if err != nil {
return "", errors.Wrap(err, "can't read /proc directory")
}
for _, f := range files {
name := f.Name()
if isDigits(name) {
filename := path.Join("/proc", name, "/ns/net")
tryInode, err := GetInode(filename)
if err != nil {
// Just report into log, do not exit
logrus.Errorf("Can't find %s Error: %v", filename, err)
continue
}
if tryInode == inode {
if cmdline, err := GetCmdline(name); err == nil && strings.Contains(cmdline, "pause") {
return filename, nil
}
}
}
}
return "", errors.New("not found")
}
func GetAllNetNs() ([]uint64, error) {
files, err := ioutil.ReadDir("/proc")
if err != nil {
return nil, errors.Wrap(err, "can't read /proc directory")
}
inodes := make([]uint64, 0, len(files))
for _, f := range files {
name := f.Name()
if isDigits(name) {
filename := path.Join("/proc", name, "/ns/net")
inode, err := GetInode(filename)
if err != nil {
continue
}
inodes = append(inodes, inode)
}
}
return inodes, nil
}
func GetCmdline(pid string) (string, error) {
data, err := ioutil.ReadFile(path.Join("/proc/", pid, "cmdline"))
if err != nil {
return "", err
}
return string(data), nil
}
// GetNsHandleFromInode return namespace handler from inode
func GetNsHandleFromInode(inode string) (netns.NsHandle, error) {
/* Parse the string to an integer */
inodeNum, err := strconv.ParseUint(inode, 10, 64)
if err != nil {
return -1, errors.Errorf("failed parsing inode, must be an unsigned int, instead was: %s", inode)
}
/* Get filepath from inode */
path, err := ResolvePodNsByInode(inodeNum)
if err != nil {
return -1, errors.Wrapf(err, "failed to find file in /proc/*/ns/net with inode %d", inodeNum)
}
/* Get namespace handler from path */
return netns.GetFromPath(path)
}