1package configs
2
3import (
4	"fmt"
5	"os"
6	"sync"
7)
8
9const (
10	NEWNET    NamespaceType = "NEWNET"
11	NEWPID    NamespaceType = "NEWPID"
12	NEWNS     NamespaceType = "NEWNS"
13	NEWUTS    NamespaceType = "NEWUTS"
14	NEWIPC    NamespaceType = "NEWIPC"
15	NEWUSER   NamespaceType = "NEWUSER"
16	NEWCGROUP NamespaceType = "NEWCGROUP"
17)
18
19var (
20	nsLock              sync.Mutex
21	supportedNamespaces = make(map[NamespaceType]bool)
22)
23
24// NsName converts the namespace type to its filename
25func NsName(ns NamespaceType) string {
26	switch ns {
27	case NEWNET:
28		return "net"
29	case NEWNS:
30		return "mnt"
31	case NEWPID:
32		return "pid"
33	case NEWIPC:
34		return "ipc"
35	case NEWUSER:
36		return "user"
37	case NEWUTS:
38		return "uts"
39	case NEWCGROUP:
40		return "cgroup"
41	}
42	return ""
43}
44
45// IsNamespaceSupported returns whether a namespace is available or
46// not
47func IsNamespaceSupported(ns NamespaceType) bool {
48	nsLock.Lock()
49	defer nsLock.Unlock()
50	supported, ok := supportedNamespaces[ns]
51	if ok {
52		return supported
53	}
54	nsFile := NsName(ns)
55	// if the namespace type is unknown, just return false
56	if nsFile == "" {
57		return false
58	}
59	_, err := os.Stat(fmt.Sprintf("/proc/self/ns/%s", nsFile))
60	// a namespace is supported if it exists and we have permissions to read it
61	supported = err == nil
62	supportedNamespaces[ns] = supported
63	return supported
64}
65
66func NamespaceTypes() []NamespaceType {
67	return []NamespaceType{
68		NEWUSER, // Keep user NS always first, don't move it.
69		NEWIPC,
70		NEWUTS,
71		NEWNET,
72		NEWPID,
73		NEWNS,
74		NEWCGROUP,
75	}
76}
77
78// Namespace defines configuration for each namespace.  It specifies an
79// alternate path that is able to be joined via setns.
80type Namespace struct {
81	Type NamespaceType `json:"type"`
82	Path string        `json:"path"`
83}
84
85func (n *Namespace) GetPath(pid int) string {
86	return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type))
87}
88
89func (n *Namespaces) Remove(t NamespaceType) bool {
90	i := n.index(t)
91	if i == -1 {
92		return false
93	}
94	*n = append((*n)[:i], (*n)[i+1:]...)
95	return true
96}
97
98func (n *Namespaces) Add(t NamespaceType, path string) {
99	i := n.index(t)
100	if i == -1 {
101		*n = append(*n, Namespace{Type: t, Path: path})
102		return
103	}
104	(*n)[i].Path = path
105}
106
107func (n *Namespaces) index(t NamespaceType) int {
108	for i, ns := range *n {
109		if ns.Type == t {
110			return i
111		}
112	}
113	return -1
114}
115
116func (n *Namespaces) Contains(t NamespaceType) bool {
117	return n.index(t) != -1
118}
119
120func (n *Namespaces) PathOf(t NamespaceType) string {
121	i := n.index(t)
122	if i == -1 {
123		return ""
124	}
125	return (*n)[i].Path
126}
127