2021-10-01 13:59:55 +00:00
|
|
|
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
2015-09-23 04:56:29 +00:00
|
|
|
|
|
|
|
package allocdir
|
|
|
|
|
|
|
|
import (
|
2015-09-25 23:49:14 +00:00
|
|
|
"fmt"
|
2015-09-23 04:56:29 +00:00
|
|
|
"os"
|
2015-09-25 23:49:14 +00:00
|
|
|
"os/user"
|
2016-06-19 20:56:09 +00:00
|
|
|
"path/filepath"
|
2015-09-25 23:49:14 +00:00
|
|
|
"strconv"
|
2017-04-17 19:29:34 +00:00
|
|
|
"syscall"
|
2016-05-07 17:43:02 +00:00
|
|
|
|
|
|
|
"golang.org/x/sys/unix"
|
2015-09-23 04:56:29 +00:00
|
|
|
)
|
|
|
|
|
2016-06-19 20:56:09 +00:00
|
|
|
var (
|
2016-09-02 19:44:05 +00:00
|
|
|
// SharedAllocContainerPath is the path inside container for mounted
|
|
|
|
// directory shared across tasks in a task group.
|
2016-06-19 20:56:09 +00:00
|
|
|
SharedAllocContainerPath = filepath.Join("/", SharedAllocName)
|
|
|
|
|
2016-09-02 19:44:05 +00:00
|
|
|
// TaskLocalContainer is the path inside a container for mounted directory
|
|
|
|
// for local storage.
|
2016-06-19 20:56:09 +00:00
|
|
|
TaskLocalContainerPath = filepath.Join("/", TaskLocal)
|
2016-09-02 19:44:05 +00:00
|
|
|
|
|
|
|
// TaskSecretsContainerPath is the path inside a container for mounted
|
|
|
|
// secrets directory
|
|
|
|
TaskSecretsContainerPath = filepath.Join("/", TaskSecrets)
|
2016-06-19 20:56:09 +00:00
|
|
|
)
|
|
|
|
|
2016-12-03 01:04:07 +00:00
|
|
|
// dropDirPermissions gives full access to a directory to all users and sets
|
|
|
|
// the owner to nobody.
|
2017-04-04 17:48:29 +00:00
|
|
|
func dropDirPermissions(path string, desired os.FileMode) error {
|
|
|
|
if err := os.Chmod(path, desired|0777); err != nil {
|
2016-10-28 23:52:38 +00:00
|
|
|
return fmt.Errorf("Chmod(%v) failed: %v", path, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can't change owner if not root.
|
2016-05-07 17:43:02 +00:00
|
|
|
if unix.Geteuid() != 0 {
|
2015-09-25 23:49:14 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-12-15 19:12:13 +00:00
|
|
|
u, err := user.Lookup("nobody")
|
2015-09-25 23:49:14 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
uid, err := getUid(u)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
gid, err := getGid(u)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := os.Chown(path, uid, gid); err != nil {
|
|
|
|
return fmt.Errorf("Couldn't change owner/group of %v to (uid: %v, gid: %v): %v", path, uid, gid, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-03 01:04:07 +00:00
|
|
|
// getUid for a user
|
2015-09-25 23:49:14 +00:00
|
|
|
func getUid(u *user.User) (int, error) {
|
|
|
|
uid, err := strconv.Atoi(u.Uid)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("Unable to convert Uid to an int: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return uid, nil
|
|
|
|
}
|
|
|
|
|
2016-12-03 01:04:07 +00:00
|
|
|
// getGid for a user
|
2015-09-25 23:49:14 +00:00
|
|
|
func getGid(u *user.User) (int, error) {
|
|
|
|
gid, err := strconv.Atoi(u.Gid)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("Unable to convert Gid to an int: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return gid, nil
|
|
|
|
}
|
2016-12-03 01:04:07 +00:00
|
|
|
|
|
|
|
// linkOrCopy attempts to hardlink dst to src and fallsback to copying if the
|
|
|
|
// hardlink fails.
|
2017-04-12 19:31:00 +00:00
|
|
|
func linkOrCopy(src, dst string, uid, gid int, perm os.FileMode) error {
|
2016-12-03 01:04:07 +00:00
|
|
|
// Avoid link/copy if the file already exists in the chroot
|
|
|
|
// TODO 0.6 clean this up. This was needed because chroot creation fails
|
|
|
|
// when a process restarts.
|
|
|
|
if fileInfo, _ := os.Stat(dst); fileInfo != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// Attempt to hardlink.
|
2017-04-12 20:58:50 +00:00
|
|
|
if err := os.Link(src, dst); err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2016-12-03 01:04:07 +00:00
|
|
|
|
2017-04-12 19:31:00 +00:00
|
|
|
return fileCopy(src, dst, uid, gid, perm)
|
2016-12-03 01:04:07 +00:00
|
|
|
}
|
2017-04-17 19:29:34 +00:00
|
|
|
|
|
|
|
func getOwner(fi os.FileInfo) (int, int) {
|
|
|
|
stat, ok := fi.Sys().(*syscall.Stat_t)
|
|
|
|
if !ok {
|
|
|
|
return -1, -1
|
|
|
|
}
|
|
|
|
return int(stat.Uid), int(stat.Gid)
|
|
|
|
}
|