forked from snapcore/snapd
/
dirs.go
428 lines (350 loc) · 13.9 KB
/
dirs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2014-2015 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package dirs
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/snapcore/snapd/release"
)
// the various file paths
var (
GlobalRootDir string
SnapMountDir string
DistroLibExecDir string
SnapBlobDir string
SnapDataDir string
SnapDataHomeGlob string
SnapDownloadCacheDir string
SnapAppArmorDir string
SnapAppArmorAdditionalDir string
SnapConfineAppArmorDir string
SnapSeccompBase string
SnapSeccompDir string
SnapMountPolicyDir string
SnapUdevRulesDir string
SnapKModModulesDir string
LocaleDir string
SnapMetaDir string
SnapdSocket string
SnapSocket string
SnapRunDir string
SnapRunNsDir string
SnapRunLockDir string
SnapBootstrapRunDir string
SnapdStoreSSLCertsDir string
SnapSeedDir string
SnapDeviceDir string
SnapAssertsDBDir string
SnapCookieDir string
SnapTrustedAccountKey string
SnapAssertsSpoolDir string
SnapSeqDir string
SnapStateFile string
SnapSystemKeyFile string
SnapRepairDir string
SnapRepairStateFile string
SnapRepairRunDir string
SnapRepairAssertsDir string
SnapRunRepairDir string
SnapRollbackDir string
SnapCacheDir string
SnapNamesFile string
SnapSectionsFile string
SnapCommandsDB string
SnapAuxStoreInfoDir string
SnapBinariesDir string
SnapServicesDir string
SnapUserServicesDir string
SnapSystemdConfDir string
SnapDesktopFilesDir string
SnapDesktopIconsDir string
SnapBusPolicyDir string
SnapBusSessionPolicyDir string
SnapDBusSessionServicesDir string
SnapDBusSystemServicesDir string
SnapModeenvFile string
CloudMetaDataFile string
CloudInstanceDataFile string
ClassicDir string
XdgRuntimeDirBase string
XdgRuntimeDirGlob string
CompletionHelperInCore string
CompletersDir string
SystemFontsDir string
SystemLocalFontsDir string
SystemFontconfigCacheDirs []string
FreezerCgroupDir string
PidsCgroupDir string
SnapshotsDir string
ErrtrackerDbDir string
SysfsDir string
FeaturesDir string
)
const (
defaultSnapMountDir = "/snap"
// These are directories which are static inside the core snap and
// can never be prefixed as they will be always absolute once we
// are in the snap confinement environment.
CoreLibExecDir = "/usr/lib/snapd"
CoreSnapMountDir = "/snap"
// Directory with snap data inside user's home
UserHomeSnapDir = "snap"
// LocalInstallBlobTempPrefix is used by local install code:
// * in daemon to spool the snap file to <SnapBlobDir>/<LocalInstallBlobTempPrefix>*
// * in snapstate to auto-cleans them up using the same prefix
LocalInstallBlobTempPrefix = ".local-install-"
)
var (
// not exported because it does not honor the global rootdir
snappyDir = filepath.Join("var", "lib", "snapd")
callbacks = []func(string){}
)
func init() {
// init the global directories at startup
root := os.Getenv("SNAPPY_GLOBAL_ROOT")
SetRootDir(root)
}
// StripRootDir strips the custom global root directory from the specified argument.
func StripRootDir(dir string) string {
if !filepath.IsAbs(dir) {
panic(fmt.Sprintf("supplied path is not absolute %q", dir))
}
if !strings.HasPrefix(dir, GlobalRootDir) {
panic(fmt.Sprintf("supplied path is not related to global root %q", dir))
}
result, err := filepath.Rel(GlobalRootDir, dir)
if err != nil {
panic(err)
}
return "/" + result
}
// SupportsClassicConfinement returns true if the current directory layout supports classic confinement.
func SupportsClassicConfinement() bool {
// Core systems don't support classic confinement as a policy decision.
if !release.OnClassic {
return false
}
// Classic systems support classic confinement if using the primary mount
// location for snaps, that is /snap or if using the alternate mount
// location, /var/lib/snapd/snap along with the /snap ->
// /var/lib/snapd/snap symlink in place.
smd := filepath.Join(GlobalRootDir, defaultSnapMountDir)
if SnapMountDir == smd {
return true
}
fi, err := os.Lstat(smd)
if err == nil && fi.Mode()&os.ModeSymlink != 0 {
if target, err := filepath.EvalSymlinks(smd); err == nil {
if target == SnapMountDir {
return true
}
}
}
return false
}
var metaSnapPath = "/meta/snap.yaml"
// isInsideBaseSnap returns true if the process is inside a base snap environment.
//
// The things that count as a base snap are:
// - any base snap mounted at /
// - any os snap mounted at /
func isInsideBaseSnap() (bool, error) {
_, err := os.Stat(metaSnapPath)
if err != nil && os.IsNotExist(err) {
return false, nil
}
return err == nil, err
}
// SnapBlobDirUnder returns the path to the snap blob dir under rootdir.
func SnapBlobDirUnder(rootdir string) string {
return filepath.Join(rootdir, snappyDir, "snaps")
}
// SnapSeedDirUnder returns the path to the snap seed dir under rootdir.
func SnapSeedDirUnder(rootdir string) string {
return filepath.Join(rootdir, snappyDir, "seed")
}
// SnapStateFileUnder returns the path to snapd state file under rootdir.
func SnapStateFileUnder(rootdir string) string {
return filepath.Join(rootdir, snappyDir, "state.json")
}
// SnapModeenvFileUnder returns the path to the modeenv file under rootdir.
func SnapModeenvFileUnder(rootdir string) string {
return filepath.Join(rootdir, snappyDir, "modeenv")
}
// FeaturesDirUnder returns the path to the features dir under rootdir.
func FeaturesDirUnder(rootdir string) string {
return filepath.Join(rootdir, snappyDir, "features")
}
// SnapSystemdConfDirUnder returns the path to the systemd conf dir under
// rootdir.
func SnapSystemdConfDirUnder(rootdir string) string {
return filepath.Join(rootdir, "/etc/systemd/system.conf.d")
}
// AddRootDirCallback registers a callback for whenever the global root
// directory (set by SetRootDir) is changed to enable updates to variables in
// other packages that depend on its location.
func AddRootDirCallback(c func(string)) {
callbacks = append(callbacks, c)
}
// SetRootDir allows settings a new global root directory, this is useful
// for e.g. chroot operations
func SetRootDir(rootdir string) {
if rootdir == "" {
rootdir = "/"
}
GlobalRootDir = rootdir
altDirDistros := []string{
"antergos",
"arch",
"archlinux",
"fedora",
"manjaro",
"manjaro-arm",
}
isInsideBase, _ := isInsideBaseSnap()
if !isInsideBase && release.DistroLike(altDirDistros...) {
SnapMountDir = filepath.Join(rootdir, "/var/lib/snapd/snap")
} else {
SnapMountDir = filepath.Join(rootdir, defaultSnapMountDir)
}
SnapDataDir = filepath.Join(rootdir, "/var/snap")
SnapDataHomeGlob = filepath.Join(rootdir, "/home/*/", UserHomeSnapDir)
SnapAppArmorDir = filepath.Join(rootdir, snappyDir, "apparmor", "profiles")
SnapConfineAppArmorDir = filepath.Join(rootdir, snappyDir, "apparmor", "snap-confine")
SnapAppArmorAdditionalDir = filepath.Join(rootdir, snappyDir, "apparmor", "additional")
SnapDownloadCacheDir = filepath.Join(rootdir, snappyDir, "cache")
SnapSeccompBase = filepath.Join(rootdir, snappyDir, "seccomp")
SnapSeccompDir = filepath.Join(SnapSeccompBase, "bpf")
SnapMountPolicyDir = filepath.Join(rootdir, snappyDir, "mount")
SnapMetaDir = filepath.Join(rootdir, snappyDir, "meta")
SnapBlobDir = SnapBlobDirUnder(rootdir)
// ${snappyDir}/desktop is added to $XDG_DATA_DIRS.
// Subdirectories are interpreted according to the relevant
// freedesktop.org specifications
SnapDesktopFilesDir = filepath.Join(rootdir, snappyDir, "desktop", "applications")
SnapDesktopIconsDir = filepath.Join(rootdir, snappyDir, "desktop", "icons")
// Use 'dbus/services' and `dbus/system-services' to mirror
// '/usr/share/dbus-1' hierarchy.
SnapDBusSessionServicesDir = filepath.Join(rootdir, snappyDir, "dbus", "services")
SnapDBusSystemServicesDir = filepath.Join(rootdir, snappyDir, "dbus", "system-services")
SnapRunDir = filepath.Join(rootdir, "/run/snapd")
SnapRunNsDir = filepath.Join(SnapRunDir, "/ns")
SnapRunLockDir = filepath.Join(SnapRunDir, "/lock")
SnapBootstrapRunDir = filepath.Join(SnapRunDir, "snap-bootstrap")
SnapdStoreSSLCertsDir = filepath.Join(rootdir, snappyDir, "ssl/store-certs")
// keep in sync with the debian/snapd.socket file:
SnapdSocket = filepath.Join(rootdir, "/run/snapd.socket")
SnapSocket = filepath.Join(rootdir, "/run/snapd-snap.socket")
SnapAssertsDBDir = filepath.Join(rootdir, snappyDir, "assertions")
SnapCookieDir = filepath.Join(rootdir, snappyDir, "cookie")
SnapAssertsSpoolDir = filepath.Join(rootdir, "run/snapd/auto-import")
SnapSeqDir = filepath.Join(rootdir, snappyDir, "sequence")
SnapStateFile = SnapStateFileUnder(rootdir)
SnapSystemKeyFile = filepath.Join(rootdir, snappyDir, "system-key")
SnapCacheDir = filepath.Join(rootdir, "/var/cache/snapd")
SnapNamesFile = filepath.Join(SnapCacheDir, "names")
SnapSectionsFile = filepath.Join(SnapCacheDir, "sections")
SnapCommandsDB = filepath.Join(SnapCacheDir, "commands.db")
SnapAuxStoreInfoDir = filepath.Join(SnapCacheDir, "aux")
SnapSeedDir = SnapSeedDirUnder(rootdir)
SnapDeviceDir = filepath.Join(rootdir, snappyDir, "device")
SnapModeenvFile = SnapModeenvFileUnder(rootdir)
SnapRepairDir = filepath.Join(rootdir, snappyDir, "repair")
SnapRepairStateFile = filepath.Join(SnapRepairDir, "repair.json")
SnapRepairRunDir = filepath.Join(SnapRepairDir, "run")
SnapRepairAssertsDir = filepath.Join(SnapRepairDir, "assertions")
SnapRunRepairDir = filepath.Join(SnapRunDir, "repair")
SnapRollbackDir = filepath.Join(rootdir, snappyDir, "rollback")
SnapBinariesDir = filepath.Join(SnapMountDir, "bin")
SnapServicesDir = filepath.Join(rootdir, "/etc/systemd/system")
SnapUserServicesDir = filepath.Join(rootdir, "/etc/systemd/user")
SnapSystemdConfDir = SnapSystemdConfDirUnder(rootdir)
SnapBusPolicyDir = filepath.Join(rootdir, "/etc/dbus-1/system.d")
SnapBusSessionPolicyDir = filepath.Join(rootdir, "/etc/dbus-1/session.d")
CloudMetaDataFile = filepath.Join(rootdir, "/var/lib/cloud/seed/nocloud-net/meta-data")
CloudInstanceDataFile = filepath.Join(rootdir, "/run/cloud-init/instance-data.json")
SnapUdevRulesDir = filepath.Join(rootdir, "/etc/udev/rules.d")
SnapKModModulesDir = filepath.Join(rootdir, "/etc/modules-load.d/")
LocaleDir = filepath.Join(rootdir, "/usr/share/locale")
ClassicDir = filepath.Join(rootdir, "/writable/classic")
if release.DistroLike("fedora") {
// rhel, centos, fedora and derivatives
// both rhel and centos list "fedora" in ID_LIKE
DistroLibExecDir = filepath.Join(rootdir, "/usr/libexec/snapd")
} else {
DistroLibExecDir = filepath.Join(rootdir, "/usr/lib/snapd")
}
XdgRuntimeDirBase = filepath.Join(rootdir, "/run/user")
XdgRuntimeDirGlob = filepath.Join(XdgRuntimeDirBase, "*/")
CompletionHelperInCore = filepath.Join(CoreLibExecDir, "etelpmoc.sh")
CompletersDir = filepath.Join(rootdir, "/usr/share/bash-completion/completions/")
// These paths agree across all supported distros
SystemFontsDir = filepath.Join(rootdir, "/usr/share/fonts")
SystemLocalFontsDir = filepath.Join(rootdir, "/usr/local/share/fonts")
// The cache path is true for Ubuntu, Debian, openSUSE, Arch
SystemFontconfigCacheDirs = []string{filepath.Join(rootdir, "/var/cache/fontconfig")}
if release.DistroLike("fedora") && !release.DistroLike("amzn") {
// Applies to Fedora and CentOS, Amazon Linux 2 is behind with
// updates to fontconfig and uses /var/cache/fontconfig instead,
// see:
// https://fedoraproject.org/wiki/Changes/FontconfigCacheDirChange
// https://bugzilla.redhat.com/show_bug.cgi?id=1416380
// https://bugzilla.redhat.com/show_bug.cgi?id=1377367
//
// However, snaps may still use older libfontconfig, which fails
// to parse the new config and defaults to
// /var/cache/fontconfig. In this case we need to make both
// locations available
SystemFontconfigCacheDirs = append(SystemFontconfigCacheDirs, filepath.Join(rootdir, "/usr/lib/fontconfig/cache"))
}
FreezerCgroupDir = filepath.Join(rootdir, "/sys/fs/cgroup/freezer/")
PidsCgroupDir = filepath.Join(rootdir, "/sys/fs/cgroup/pids/")
SnapshotsDir = filepath.Join(rootdir, snappyDir, "snapshots")
ErrtrackerDbDir = filepath.Join(rootdir, snappyDir, "errtracker.db")
SysfsDir = filepath.Join(rootdir, "/sys")
FeaturesDir = FeaturesDirUnder(rootdir)
// call the callbacks last so that the callbacks can just reference the
// global vars if they want, instead of using the new rootdir directly
for _, c := range callbacks {
c(rootdir)
}
}
// what inside a (non-classic) snap is /usr/lib/snapd, outside can come from different places
func libExecOutside(base string) string {
if base == "" {
// no explicit base; core is it
return filepath.Join(SnapMountDir, "core/current/usr/lib/snapd")
}
// if a base is set, libexec comes from the snapd snap if it's
// installed, and otherwise from the distro.
p := filepath.Join(SnapMountDir, "snapd/current/usr/lib/snapd")
if st, err := os.Stat(p); err == nil && st.IsDir() {
return p
}
return DistroLibExecDir
}
func CompleteShPath(base string) string {
return filepath.Join(libExecOutside(base), "complete.sh")
}
func IsCompleteShSymlink(compPath string) bool {
target, err := os.Readlink(compPath)
// check if the target paths ends with "/snapd/complete.sh"
return err == nil && filepath.Base(filepath.Dir(target)) == "snapd" && filepath.Base(target) == "complete.sh"
}