| package homedir // import "github.com/docker/docker/pkg/homedir" |
| |
| import ( |
| "errors" |
| "os" |
| "path/filepath" |
| "strings" |
| |
| "github.com/docker/docker/pkg/idtools" |
| ) |
| |
| // GetStatic returns the home directory for the current user without calling |
| // os/user.Current(). This is useful for static-linked binary on glibc-based |
| // system, because a call to os/user.Current() in a static binary leads to |
| // segfault due to a glibc issue that won't be fixed in a short term. |
| // (#29344, golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341) |
| func GetStatic() (string, error) { |
| uid := os.Getuid() |
| usr, err := idtools.LookupUID(uid) |
| if err != nil { |
| return "", err |
| } |
| return usr.Home, nil |
| } |
| |
| // GetRuntimeDir returns XDG_RUNTIME_DIR. |
| // XDG_RUNTIME_DIR is typically configured via pam_systemd. |
| // GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set. |
| // |
| // See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html |
| func GetRuntimeDir() (string, error) { |
| if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" { |
| return xdgRuntimeDir, nil |
| } |
| return "", errors.New("could not get XDG_RUNTIME_DIR") |
| } |
| |
| // StickRuntimeDirContents sets the sticky bit on files that are under |
| // XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system. |
| // |
| // StickyRuntimeDir returns slice of sticked files. |
| // StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set. |
| // |
| // See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html |
| func StickRuntimeDirContents(files []string) ([]string, error) { |
| runtimeDir, err := GetRuntimeDir() |
| if err != nil { |
| // ignore error if runtimeDir is empty |
| return nil, nil |
| } |
| runtimeDir, err = filepath.Abs(runtimeDir) |
| if err != nil { |
| return nil, err |
| } |
| var sticked []string |
| for _, f := range files { |
| f, err = filepath.Abs(f) |
| if err != nil { |
| return sticked, err |
| } |
| if strings.HasPrefix(f, runtimeDir+"/") { |
| if err = stick(f); err != nil { |
| return sticked, err |
| } |
| sticked = append(sticked, f) |
| } |
| } |
| return sticked, nil |
| } |
| |
| func stick(f string) error { |
| st, err := os.Stat(f) |
| if err != nil { |
| return err |
| } |
| m := st.Mode() |
| m |= os.ModeSticky |
| return os.Chmod(f, m) |
| } |
| |
| // GetDataHome returns XDG_DATA_HOME. |
| // GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set. |
| // |
| // See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html |
| func GetDataHome() (string, error) { |
| if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" { |
| return xdgDataHome, nil |
| } |
| home := os.Getenv("HOME") |
| if home == "" { |
| return "", errors.New("could not get either XDG_DATA_HOME or HOME") |
| } |
| return filepath.Join(home, ".local", "share"), nil |
| } |
| |
| // GetConfigHome returns XDG_CONFIG_HOME. |
| // GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set. |
| // |
| // See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html |
| func GetConfigHome() (string, error) { |
| if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" { |
| return xdgConfigHome, nil |
| } |
| home := os.Getenv("HOME") |
| if home == "" { |
| return "", errors.New("could not get either XDG_CONFIG_HOME or HOME") |
| } |
| return filepath.Join(home, ".config"), nil |
| } |