Commit 5b5cd6fb authored by Filipe Brandenburger's avatar Filipe Brandenburger

Update libcontainer to include PRs with fixes to systemd cgroup driver

PR opencontainers/runc#1754 works around an issue in manager.Apply(-1) that makes Kubelet startup hang when using systemd cgroup driver (by adding a timeout) and further PR opencontainers/runc#1772 fixes that bug by checking the proper error status before waiting on the channel. PR opencontainers/runc#1776 checks whether Delegate works in slices, which keeps libcontainer systemd cgroup driver working on systemd v237+. PR opencontainers/runc#1781 makes the channel buffered, so if we time out waiting on the channel, the updater will not block trying to it since there are no longer any consumers.
parent 2ba765ae
...@@ -2350,83 +2350,83 @@ ...@@ -2350,83 +2350,83 @@
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer", "ImportPath": "github.com/opencontainers/runc/libcontainer",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/apparmor", "ImportPath": "github.com/opencontainers/runc/libcontainer/apparmor",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups", "ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/fs", "ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/fs",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/systemd", "ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/systemd",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs", "ImportPath": "github.com/opencontainers/runc/libcontainer/configs",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs/validate", "ImportPath": "github.com/opencontainers/runc/libcontainer/configs/validate",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/criurpc", "ImportPath": "github.com/opencontainers/runc/libcontainer/criurpc",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/intelrdt", "ImportPath": "github.com/opencontainers/runc/libcontainer/intelrdt",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/keys", "ImportPath": "github.com/opencontainers/runc/libcontainer/keys",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/mount", "ImportPath": "github.com/opencontainers/runc/libcontainer/mount",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/seccomp", "ImportPath": "github.com/opencontainers/runc/libcontainer/seccomp",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/stacktrace", "ImportPath": "github.com/opencontainers/runc/libcontainer/stacktrace",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/system", "ImportPath": "github.com/opencontainers/runc/libcontainer/system",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/user", "ImportPath": "github.com/opencontainers/runc/libcontainer/user",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runc/libcontainer/utils", "ImportPath": "github.com/opencontainers/runc/libcontainer/utils",
"Comment": "v1.0.0-rc4-221-g595bea02", "Comment": "v1.0.0-rc5-46-g871ba2e5",
"Rev": "595bea022f077a9e17d7473b34fbaf1adaed9e43" "Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
}, },
{ {
"ImportPath": "github.com/opencontainers/runtime-spec/specs-go", "ImportPath": "github.com/opencontainers/runtime-spec/specs-go",
......
...@@ -161,7 +161,7 @@ func (m *Manager) Apply(pid int) (err error) { ...@@ -161,7 +161,7 @@ func (m *Manager) Apply(pid int) (err error) {
} }
func (m *Manager) Destroy() error { func (m *Manager) Destroy() error {
if m.Cgroups.Paths != nil { if m.Cgroups == nil || m.Cgroups.Paths != nil {
return nil return nil
} }
m.mu.Lock() m.mu.Lock()
......
...@@ -64,6 +64,7 @@ go_library( ...@@ -64,6 +64,7 @@ go_library(
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library",
"//vendor/github.com/sirupsen/logrus:go_default_library",
], ],
"@io_bazel_rules_go//go/platform:nacl": [ "@io_bazel_rules_go//go/platform:nacl": [
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library",
......
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/cgroups/fs"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
"github.com/sirupsen/logrus"
) )
type Manager struct { type Manager struct {
...@@ -74,7 +75,8 @@ var ( ...@@ -74,7 +75,8 @@ var (
hasStartTransientUnit bool hasStartTransientUnit bool
hasStartTransientSliceUnit bool hasStartTransientSliceUnit bool
hasTransientDefaultDependencies bool hasTransientDefaultDependencies bool
hasDelegate bool hasDelegateScope bool
hasDelegateSlice bool
) )
func newProp(name string, units interface{}) systemdDbus.Property { func newProp(name string, units interface{}) systemdDbus.Property {
...@@ -149,12 +151,12 @@ func UseSystemd() bool { ...@@ -149,12 +151,12 @@ func UseSystemd() bool {
theConn.StopUnit(scope, "replace", nil) theConn.StopUnit(scope, "replace", nil)
// Assume StartTransientUnit on a scope allows Delegate // Assume StartTransientUnit on a scope allows Delegate
hasDelegate = true hasDelegateScope = true
dl := newProp("Delegate", true) dlScope := newProp("Delegate", true)
if _, err := theConn.StartTransientUnit(scope, "replace", []systemdDbus.Property{dl}, nil); err != nil { if _, err := theConn.StartTransientUnit(scope, "replace", []systemdDbus.Property{dlScope}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok { if dbusError, ok := err.(dbus.Error); ok {
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") { if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
hasDelegate = false hasDelegateScope = false
} }
} }
} }
...@@ -187,6 +189,22 @@ func UseSystemd() bool { ...@@ -187,6 +189,22 @@ func UseSystemd() bool {
} }
// Not critical because of the stop unit logic above. // Not critical because of the stop unit logic above.
theConn.StopUnit(slice, "replace", nil)
// Assume StartTransientUnit on a slice allows Delegate
hasDelegateSlice = true
dlSlice := newProp("Delegate", true)
if _, err := theConn.StartTransientUnit(slice, "replace", []systemdDbus.Property{dlSlice}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
// Starting with systemd v237, Delegate is not even a property of slices anymore,
// so the D-Bus call fails with "InvalidArgs" error.
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
hasDelegateSlice = false
}
}
}
// Not critical because of the stop unit logic above.
theConn.StopUnit(scope, "replace", nil) theConn.StopUnit(scope, "replace", nil)
theConn.StopUnit(slice, "replace", nil) theConn.StopUnit(slice, "replace", nil)
} }
...@@ -241,9 +259,16 @@ func (m *Manager) Apply(pid int) error { ...@@ -241,9 +259,16 @@ func (m *Manager) Apply(pid int) error {
properties = append(properties, newProp("PIDs", []uint32{uint32(pid)})) properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
} }
if hasDelegate { // Check if we can delegate. This is only supported on systemd versions 218 and above.
// This is only supported on systemd versions 218 and above. if strings.HasSuffix(unitName, ".slice") {
properties = append(properties, newProp("Delegate", true)) if hasDelegateSlice {
// systemd 237 and above no longer allows delegation on a slice
properties = append(properties, newProp("Delegate", true))
}
} else {
if hasDelegateScope {
properties = append(properties, newProp("Delegate", true))
}
} }
// Always enable accounting, this gets us the same behaviour as the fs implementation, // Always enable accounting, this gets us the same behaviour as the fs implementation,
...@@ -295,13 +320,17 @@ func (m *Manager) Apply(pid int) error { ...@@ -295,13 +320,17 @@ func (m *Manager) Apply(pid int) error {
} }
} }
statusChan := make(chan string) statusChan := make(chan string, 1)
if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err != nil && !isUnitExists(err) { if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
select {
case <-statusChan:
case <-time.After(time.Second):
logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName)
}
} else if !isUnitExists(err) {
return err return err
} }
<-statusChan
if err := joinCgroups(c, pid); err != nil { if err := joinCgroups(c, pid); err != nil {
return err return err
} }
......
...@@ -49,7 +49,7 @@ func rootlessMappings(config *configs.Config) error { ...@@ -49,7 +49,7 @@ func rootlessMappings(config *configs.Config) error {
return fmt.Errorf("rootless containers requires at least one UID mapping") return fmt.Errorf("rootless containers requires at least one UID mapping")
} }
if len(config.GidMappings) == 0 { if len(config.GidMappings) == 0 {
return fmt.Errorf("rootless containers requires at least one UID mapping") return fmt.Errorf("rootless containers requires at least one GID mapping")
} }
return nil return nil
......
...@@ -377,10 +377,6 @@ func (c *linuxContainer) start(process *Process, isInit bool) error { ...@@ -377,10 +377,6 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
} }
} }
} }
} else {
c.state = &runningState{
c: c,
}
} }
return nil return nil
} }
...@@ -1801,8 +1797,7 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na ...@@ -1801,8 +1797,7 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na
Value: []byte(c.newgidmapPath), Value: []byte(c.newgidmapPath),
}) })
} }
// The following only applies if we are root. if requiresRootOrMappingTool(c.config) {
if !c.config.Rootless {
// check if we have CAP_SETGID to setgroup properly // check if we have CAP_SETGID to setgroup properly
pid, err := capability.NewPid(0) pid, err := capability.NewPid(0)
if err != nil { if err != nil {
...@@ -1847,3 +1842,10 @@ func ignoreTerminateErrors(err error) error { ...@@ -1847,3 +1842,10 @@ func ignoreTerminateErrors(err error) error {
} }
return err return err
} }
func requiresRootOrMappingTool(c *configs.Config) bool {
gidMap := []configs.IDMap{
{ContainerID: 0, HostID: os.Getegid(), Size: 1},
}
return !reflect.DeepEqual(c.GidMappings, gidMap)
}
...@@ -77,13 +77,13 @@ func (msg *Boolmsg) Serialize() []byte { ...@@ -77,13 +77,13 @@ func (msg *Boolmsg) Serialize() []byte {
native.PutUint16(buf[0:2], uint16(msg.Len())) native.PutUint16(buf[0:2], uint16(msg.Len()))
native.PutUint16(buf[2:4], msg.Type) native.PutUint16(buf[2:4], msg.Type)
if msg.Value { if msg.Value {
buf[4] = 1 native.PutUint32(buf[4:8], uint32(1))
} else { } else {
buf[4] = 0 native.PutUint32(buf[4:8], uint32(0))
} }
return buf return buf
} }
func (msg *Boolmsg) Len() int { func (msg *Boolmsg) Len() int {
return unix.NLA_HDRLEN + 1 return unix.NLA_HDRLEN + 4 // alignment
} }
...@@ -46,7 +46,6 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { ...@@ -46,7 +46,6 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
return newSystemErrorWithCause(err, "preparing rootfs") return newSystemErrorWithCause(err, "preparing rootfs")
} }
setupDev := needsSetupDev(config)
for _, m := range config.Mounts { for _, m := range config.Mounts {
for _, precmd := range m.PremountCmds { for _, precmd := range m.PremountCmds {
if err := mountCmd(precmd); err != nil { if err := mountCmd(precmd); err != nil {
...@@ -65,6 +64,8 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { ...@@ -65,6 +64,8 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
} }
} }
setupDev := needsSetupDev(config)
if setupDev { if setupDev {
if err := createDevices(config); err != nil { if err := createDevices(config); err != nil {
return newSystemErrorWithCause(err, "creating device nodes") return newSystemErrorWithCause(err, "creating device nodes")
...@@ -778,10 +779,10 @@ func remountReadonly(m *configs.Mount) error { ...@@ -778,10 +779,10 @@ func remountReadonly(m *configs.Mount) error {
// mounts ( proc/kcore ). // mounts ( proc/kcore ).
// For files, maskPath bind mounts /dev/null over the top of the specified path. // For files, maskPath bind mounts /dev/null over the top of the specified path.
// For directories, maskPath mounts read-only tmpfs over the top of the specified path. // For directories, maskPath mounts read-only tmpfs over the top of the specified path.
func maskPath(path string) error { func maskPath(path string, mountLabel string) error {
if err := unix.Mount("/dev/null", path, "", unix.MS_BIND, ""); err != nil && !os.IsNotExist(err) { if err := unix.Mount("/dev/null", path, "", unix.MS_BIND, ""); err != nil && !os.IsNotExist(err) {
if err == unix.ENOTDIR { if err == unix.ENOTDIR {
return unix.Mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, "") return unix.Mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("", mountLabel))
} }
return err return err
} }
......
...@@ -110,7 +110,7 @@ func (l *linuxStandardInit) Init() error { ...@@ -110,7 +110,7 @@ func (l *linuxStandardInit) Init() error {
} }
} }
for _, path := range l.config.Config.MaskPaths { for _, path := range l.config.Config.MaskPaths {
if err := maskPath(path); err != nil { if err := maskPath(path, l.config.Config.MountLabel); err != nil {
return err return err
} }
} }
......
...@@ -27,6 +27,9 @@ go_library( ...@@ -27,6 +27,9 @@ go_library(
"@io_bazel_rules_go//go/platform:solaris": [ "@io_bazel_rules_go//go/platform:solaris": [
"lookup_unix.go", "lookup_unix.go",
], ],
"@io_bazel_rules_go//go/platform:windows": [
"lookup_windows.go",
],
"//conditions:default": [], "//conditions:default": [],
}), }),
importpath = "github.com/opencontainers/runc/libcontainer/user", importpath = "github.com/opencontainers/runc/libcontainer/user",
......
...@@ -12,84 +12,30 @@ var ( ...@@ -12,84 +12,30 @@ var (
ErrNoGroupEntries = errors.New("no matching entries in group file") ErrNoGroupEntries = errors.New("no matching entries in group file")
) )
func lookupUser(filter func(u User) bool) (User, error) {
// Get operating system-specific passwd reader-closer.
passwd, err := GetPasswd()
if err != nil {
return User{}, err
}
defer passwd.Close()
// Get the users.
users, err := ParsePasswdFilter(passwd, filter)
if err != nil {
return User{}, err
}
// No user entries found.
if len(users) == 0 {
return User{}, ErrNoPasswdEntries
}
// Assume the first entry is the "correct" one.
return users[0], nil
}
// LookupUser looks up a user by their username in /etc/passwd. If the user // LookupUser looks up a user by their username in /etc/passwd. If the user
// cannot be found (or there is no /etc/passwd file on the filesystem), then // cannot be found (or there is no /etc/passwd file on the filesystem), then
// LookupUser returns an error. // LookupUser returns an error.
func LookupUser(username string) (User, error) { func LookupUser(username string) (User, error) {
return lookupUser(func(u User) bool { return lookupUser(username)
return u.Name == username
})
} }
// LookupUid looks up a user by their user id in /etc/passwd. If the user cannot // LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
// be found (or there is no /etc/passwd file on the filesystem), then LookupId // be found (or there is no /etc/passwd file on the filesystem), then LookupId
// returns an error. // returns an error.
func LookupUid(uid int) (User, error) { func LookupUid(uid int) (User, error) {
return lookupUser(func(u User) bool { return lookupUid(uid)
return u.Uid == uid
})
}
func lookupGroup(filter func(g Group) bool) (Group, error) {
// Get operating system-specific group reader-closer.
group, err := GetGroup()
if err != nil {
return Group{}, err
}
defer group.Close()
// Get the users.
groups, err := ParseGroupFilter(group, filter)
if err != nil {
return Group{}, err
}
// No user entries found.
if len(groups) == 0 {
return Group{}, ErrNoGroupEntries
}
// Assume the first entry is the "correct" one.
return groups[0], nil
} }
// LookupGroup looks up a group by its name in /etc/group. If the group cannot // LookupGroup looks up a group by its name in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGroup // be found (or there is no /etc/group file on the filesystem), then LookupGroup
// returns an error. // returns an error.
func LookupGroup(groupname string) (Group, error) { func LookupGroup(groupname string) (Group, error) {
return lookupGroup(func(g Group) bool { return lookupGroup(groupname)
return g.Name == groupname
})
} }
// LookupGid looks up a group by its group id in /etc/group. If the group cannot // LookupGid looks up a group by its group id in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGid // be found (or there is no /etc/group file on the filesystem), then LookupGid
// returns an error. // returns an error.
func LookupGid(gid int) (Group, error) { func LookupGid(gid int) (Group, error) {
return lookupGroup(func(g Group) bool { return lookupGid(gid)
return g.Gid == gid
})
} }
...@@ -15,6 +15,76 @@ const ( ...@@ -15,6 +15,76 @@ const (
unixGroupPath = "/etc/group" unixGroupPath = "/etc/group"
) )
func lookupUser(username string) (User, error) {
return lookupUserFunc(func(u User) bool {
return u.Name == username
})
}
func lookupUid(uid int) (User, error) {
return lookupUserFunc(func(u User) bool {
return u.Uid == uid
})
}
func lookupUserFunc(filter func(u User) bool) (User, error) {
// Get operating system-specific passwd reader-closer.
passwd, err := GetPasswd()
if err != nil {
return User{}, err
}
defer passwd.Close()
// Get the users.
users, err := ParsePasswdFilter(passwd, filter)
if err != nil {
return User{}, err
}
// No user entries found.
if len(users) == 0 {
return User{}, ErrNoPasswdEntries
}
// Assume the first entry is the "correct" one.
return users[0], nil
}
func lookupGroup(groupname string) (Group, error) {
return lookupGroupFunc(func(g Group) bool {
return g.Name == groupname
})
}
func lookupGid(gid int) (Group, error) {
return lookupGroupFunc(func(g Group) bool {
return g.Gid == gid
})
}
func lookupGroupFunc(filter func(g Group) bool) (Group, error) {
// Get operating system-specific group reader-closer.
group, err := GetGroup()
if err != nil {
return Group{}, err
}
defer group.Close()
// Get the users.
groups, err := ParseGroupFilter(group, filter)
if err != nil {
return Group{}, err
}
// No user entries found.
if len(groups) == 0 {
return Group{}, ErrNoGroupEntries
}
// Assume the first entry is the "correct" one.
return groups[0], nil
}
func GetPasswdPath() (string, error) { func GetPasswdPath() (string, error) {
return unixPasswdPath, nil return unixPasswdPath, nil
} }
......
// +build windows
package user
import (
"fmt"
"os/user"
)
func lookupUser(username string) (User, error) {
u, err := user.Lookup(username)
if err != nil {
return User{}, err
}
return userFromOS(u)
}
func lookupUid(uid int) (User, error) {
u, err := user.LookupId(fmt.Sprintf("%d", uid))
if err != nil {
return User{}, err
}
return userFromOS(u)
}
func lookupGroup(groupname string) (Group, error) {
g, err := user.LookupGroup(groupname)
if err != nil {
return Group{}, err
}
return groupFromOS(g)
}
func lookupGid(gid int) (Group, error) {
g, err := user.LookupGroupId(fmt.Sprintf("%d", gid))
if err != nil {
return Group{}, err
}
return groupFromOS(g)
}
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"os/user"
"strconv" "strconv"
"strings" "strings"
) )
...@@ -28,6 +29,28 @@ type User struct { ...@@ -28,6 +29,28 @@ type User struct {
Shell string Shell string
} }
// userFromOS converts an os/user.(*User) to local User
//
// (This does not include Pass, Shell or Gecos)
func userFromOS(u *user.User) (User, error) {
newUser := User{
Name: u.Username,
Home: u.HomeDir,
}
id, err := strconv.Atoi(u.Uid)
if err != nil {
return newUser, err
}
newUser.Uid = id
id, err = strconv.Atoi(u.Gid)
if err != nil {
return newUser, err
}
newUser.Gid = id
return newUser, nil
}
type Group struct { type Group struct {
Name string Name string
Pass string Pass string
...@@ -35,6 +58,23 @@ type Group struct { ...@@ -35,6 +58,23 @@ type Group struct {
List []string List []string
} }
// groupFromOS converts an os/user.(*Group) to local Group
//
// (This does not include Pass, Shell or Gecos)
func groupFromOS(g *user.Group) (Group, error) {
newGroup := Group{
Name: g.Name,
}
id, err := strconv.Atoi(g.Gid)
if err != nil {
return newGroup, err
}
newGroup.Gid = id
return newGroup, nil
}
func parseLine(line string, v ...interface{}) { func parseLine(line string, v ...interface{}) {
if line == "" { if line == "" {
return return
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment