@@ -7,15 +7,16 @@ package homedir
7
7
// NOTE: this package has originally been copied from github.com/docker/docker.
8
8
9
9
import (
10
- "errors"
11
10
"fmt"
12
11
"os"
13
12
"path/filepath"
13
+ "strconv"
14
14
"strings"
15
15
"sync"
16
16
"syscall"
17
17
18
18
"github.com/containers/storage/pkg/unshare"
19
+ "github.com/sirupsen/logrus"
19
20
)
20
21
21
22
// Key returns the env var name for the user's home dir based on
@@ -43,18 +44,6 @@ func GetShortcutString() string {
43
44
return "~"
44
45
}
45
46
46
- // GetRuntimeDir returns XDG_RUNTIME_DIR.
47
- // XDG_RUNTIME_DIR is typically configured via pam_systemd.
48
- // GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
49
- //
50
- // See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
51
- func GetRuntimeDir () (string , error ) {
52
- if xdgRuntimeDir := os .Getenv ("XDG_RUNTIME_DIR" ); xdgRuntimeDir != "" {
53
- return filepath .EvalSymlinks (xdgRuntimeDir )
54
- }
55
- return "" , errors .New ("could not get XDG_RUNTIME_DIR" )
56
- }
57
-
58
47
// StickRuntimeDirContents sets the sticky bit on files that are under
59
48
// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system.
60
49
//
102
91
rootlessConfigHomeDirError error
103
92
rootlessConfigHomeDirOnce sync.Once
104
93
rootlessConfigHomeDir string
94
+ rootlessRuntimeDirOnce sync.Once
95
+ rootlessRuntimeDir string
105
96
)
106
97
107
98
// isWriteableOnlyByOwner checks that the specified permission mask allows write
@@ -139,3 +130,51 @@ func GetConfigHome() (string, error) {
139
130
140
131
return rootlessConfigHomeDir , rootlessConfigHomeDirError
141
132
}
133
+
134
+ // GetRuntimeDir returns a directory suitable to store runtime files.
135
+ // The function will try to use the XDG_RUNTIME_DIR env variable if it is set.
136
+ // XDG_RUNTIME_DIR is typically configured via pam_systemd.
137
+ // If XDG_RUNTIME_DIR is not set, GetRuntimeDir will try to find a suitable
138
+ // directory for the current user.
139
+ //
140
+ // See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
141
+ func GetRuntimeDir () (string , error ) {
142
+ var rootlessRuntimeDirError error
143
+
144
+ rootlessRuntimeDirOnce .Do (func () {
145
+ runtimeDir := os .Getenv ("XDG_RUNTIME_DIR" )
146
+
147
+ if runtimeDir != "" {
148
+ rootlessRuntimeDir , rootlessRuntimeDirError = filepath .EvalSymlinks (runtimeDir )
149
+ return
150
+ }
151
+
152
+ uid := strconv .Itoa (unshare .GetRootlessUID ())
153
+ if runtimeDir == "" {
154
+ tmpDir := filepath .Join ("/run" , "user" , uid )
155
+ if err := os .MkdirAll (tmpDir , 0o700 ); err != nil {
156
+ logrus .Debug (err )
157
+ }
158
+ st , err := os .Lstat (tmpDir )
159
+ if err == nil && int (st .Sys ().(* syscall.Stat_t ).Uid ) == os .Geteuid () && isWriteableOnlyByOwner (st .Mode ().Perm ()) {
160
+ runtimeDir = tmpDir
161
+ }
162
+ }
163
+ if runtimeDir == "" {
164
+ tmpDir := filepath .Join (os .TempDir (), fmt .Sprintf ("storage-run-%s" , uid ))
165
+ if err := os .MkdirAll (tmpDir , 0o700 ); err != nil {
166
+ logrus .Debug (err )
167
+ }
168
+ st , err := os .Lstat (tmpDir )
169
+ if err == nil && int (st .Sys ().(* syscall.Stat_t ).Uid ) == os .Geteuid () && isWriteableOnlyByOwner (st .Mode ().Perm ()) {
170
+ runtimeDir = tmpDir
171
+ } else {
172
+ rootlessRuntimeDirError = fmt .Errorf ("path %q exists and it is not writeable only by the current user" , tmpDir )
173
+ return
174
+ }
175
+ }
176
+ rootlessRuntimeDir = runtimeDir
177
+ })
178
+
179
+ return rootlessRuntimeDir , rootlessRuntimeDirError
180
+ }
0 commit comments