1package homedir // import "github.com/docker/docker/pkg/homedir"
2
3import (
4	"errors"
5	"os"
6	"path/filepath"
7	"strings"
8)
9
10// GetRuntimeDir returns XDG_RUNTIME_DIR.
11// XDG_RUNTIME_DIR is typically configured via pam_systemd.
12// GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
13//
14// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
15func GetRuntimeDir() (string, error) {
16	if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" {
17		return xdgRuntimeDir, nil
18	}
19	return "", errors.New("could not get XDG_RUNTIME_DIR")
20}
21
22// StickRuntimeDirContents sets the sticky bit on files that are under
23// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system.
24//
25// StickyRuntimeDir returns slice of sticked files.
26// StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set.
27//
28// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
29func StickRuntimeDirContents(files []string) ([]string, error) {
30	runtimeDir, err := GetRuntimeDir()
31	if err != nil {
32		// ignore error if runtimeDir is empty
33		return nil, nil
34	}
35	runtimeDir, err = filepath.Abs(runtimeDir)
36	if err != nil {
37		return nil, err
38	}
39	var sticked []string
40	for _, f := range files {
41		f, err = filepath.Abs(f)
42		if err != nil {
43			return sticked, err
44		}
45		if strings.HasPrefix(f, runtimeDir+"/") {
46			if err = stick(f); err != nil {
47				return sticked, err
48			}
49			sticked = append(sticked, f)
50		}
51	}
52	return sticked, nil
53}
54
55func stick(f string) error {
56	st, err := os.Stat(f)
57	if err != nil {
58		return err
59	}
60	m := st.Mode()
61	m |= os.ModeSticky
62	return os.Chmod(f, m)
63}
64
65// GetDataHome returns XDG_DATA_HOME.
66// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set.
67//
68// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
69func GetDataHome() (string, error) {
70	if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
71		return xdgDataHome, nil
72	}
73	home := os.Getenv("HOME")
74	if home == "" {
75		return "", errors.New("could not get either XDG_DATA_HOME or HOME")
76	}
77	return filepath.Join(home, ".local", "share"), nil
78}
79
80// GetConfigHome returns XDG_CONFIG_HOME.
81// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
82//
83// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
84func GetConfigHome() (string, error) {
85	if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
86		return xdgConfigHome, nil
87	}
88	home := os.Getenv("HOME")
89	if home == "" {
90		return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
91	}
92	return filepath.Join(home, ".config"), nil
93}
94