@@ -11,11 +11,13 @@ import (
11
11
"fmt"
12
12
"os"
13
13
"path/filepath"
14
+ "strconv"
14
15
"strings"
15
16
"sync"
16
17
"syscall"
17
18
18
19
"github.com/containers/storage/pkg/unshare"
20
+ "github.com/sirupsen/logrus"
19
21
)
20
22
21
23
// Key returns the env var name for the user's home dir based on
@@ -101,6 +103,8 @@ func stick(f string) error {
101
103
var (
102
104
rootlessConfigHomeDirOnce sync.Once
103
105
rootlessConfigHomeDir string
106
+ rootlessRuntimeDirOnce sync.Once
107
+ rootlessRuntimeDir string
104
108
)
105
109
106
110
// GetConfigHome returns XDG_CONFIG_HOME.
@@ -134,3 +138,65 @@ func GetConfigHome() (string, error) {
134
138
135
139
return rootlessConfigHomeDir , nil
136
140
}
141
+
142
+ // GetRuntimeDirUser returns the runtime directory for the specified user.
143
+ // If the environment variable is not set, the function will attempt to use common locations.
144
+ // rootless: A boolean flag indicating whether rootless the process is running as rootless or not.
145
+ // rootlessUID: An integer representing the user ID for the rootless user.
146
+ func GetRuntimeDirUser (rootless bool , rootlessUID int ) (string , error ) {
147
+ var rootlessRuntimeDirError error
148
+
149
+ if ! rootless {
150
+ return "" , nil
151
+ }
152
+
153
+ rootlessRuntimeDirOnce .Do (func () {
154
+ runtimeDir := os .Getenv ("XDG_RUNTIME_DIR" )
155
+
156
+ if runtimeDir != "" {
157
+ rootlessRuntimeDir , rootlessRuntimeDirError = filepath .EvalSymlinks (runtimeDir )
158
+ return
159
+ }
160
+
161
+ uid := strconv .Itoa (rootlessUID )
162
+ if runtimeDir == "" {
163
+ tmpDir := filepath .Join ("/run" , "user" , uid )
164
+ if err := os .MkdirAll (tmpDir , 0o700 ); err != nil {
165
+ logrus .Debug (err )
166
+ }
167
+ st , err := os .Stat (tmpDir )
168
+ if err == nil && int (st .Sys ().(* syscall.Stat_t ).Uid ) == os .Geteuid () && (st .Mode ().Perm ()& 0o700 == 0o700 ) {
169
+ runtimeDir = tmpDir
170
+ }
171
+ }
172
+ if runtimeDir == "" {
173
+ tmpDir := filepath .Join (os .TempDir (), fmt .Sprintf ("storage-run-%s" , uid ))
174
+ if err := os .MkdirAll (tmpDir , 0o700 ); err != nil {
175
+ logrus .Debug (err )
176
+ }
177
+ st , err := os .Stat (tmpDir )
178
+ if err == nil && int (st .Sys ().(* syscall.Stat_t ).Uid ) == os .Geteuid () && (st .Mode ().Perm ()& 0o700 == 0o700 ) {
179
+ runtimeDir = tmpDir
180
+ }
181
+ }
182
+ if runtimeDir == "" {
183
+ home := os .Getenv ("HOME" )
184
+ if home == "" {
185
+ rootlessRuntimeDirError = errors .New ("neither XDG_RUNTIME_DIR nor HOME was set non-empty" )
186
+ return
187
+ }
188
+ resolvedHome , err := filepath .EvalSymlinks (home )
189
+ if err != nil {
190
+ rootlessRuntimeDirError = fmt .Errorf ("cannot resolve %s: %w" , home , err )
191
+ return
192
+ }
193
+ runtimeDir = filepath .Join (resolvedHome , "rundir" )
194
+ }
195
+ rootlessRuntimeDir = runtimeDir
196
+ })
197
+
198
+ if rootlessRuntimeDirError != nil {
199
+ return "" , rootlessRuntimeDirError
200
+ }
201
+ return rootlessRuntimeDir , nil
202
+ }
0 commit comments