fix/step-umask a16908b

layout.go RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3package vm
4
5import (
6	"errors"
7	"fmt"
8	"io"
9	"os"
10	"path/filepath"
11	"syscall"
12)
13
14// layout is where the files of one VM live and how Firecracker names them.
15//
16// With the jailer, Firecracker sees only its chroot: <jailBase>/firecracker/<id>/root,
17// so shared files are hard-linked into it and named "/name"; per-job files are
18// created there and handed to the jailed uid. Without the jailer (development
19// and tests), Firecracker sees the real filesystem: shared files are used in
20// place and per-job files live in <stateDir>/vm/<id>.
21type layout struct {
22	jailed bool
23	root   string // host path of the VM's working directory
24	dir    string // the directory removed whole at cleanup
25	uid    int
26}
27
28// newLayout: execName is the base name of the Firecracker binary, which the
29// jailer uses as the first directory below its chroot base.
30func newLayout(stateDir, execName, id string, jailed bool, uid int) layout {
31	if jailed {
32		dir := filepath.Join(stateDir, "jail", execName, id)
33		return layout{jailed: true, root: filepath.Join(dir, "root"), dir: dir, uid: uid}
34	}
35	dir := filepath.Join(stateDir, "vm", id)
36	return layout{root: dir, dir: dir, uid: uid}
37}
38
39// jailBase is the --chroot-base-dir given to the jailer.
40func jailBase(stateDir string) string { return filepath.Join(stateDir, "jail") }
41
42// host returns the host path of a per-job file called name.
43func (l layout) host(name string) string { return filepath.Join(l.root, name) }
44
45// fc returns the path Firecracker must be given for a per-job file.
46func (l layout) fc(name string) string {
47	if l.jailed {
48		return "/" + name
49	}
50	return l.host(name)
51}
52
53// share makes the read-only shared file src available to Firecracker and
54// returns its path for Firecracker. In a jail it is hard-linked, which requires
55// the same filesystem as the state directory, and src must be readable by the
56// jailed uid (the link shares the inode: it is never chowned).
57func (l layout) share(src, name string) (string, error) {
58	if !l.jailed {
59		return src, nil
60	}
61	dst := l.host(name)
62	if err := os.Link(src, dst); err != nil {
63		if errors.Is(err, syscall.EXDEV) {
64			return "", fmt.Errorf("cannot link %s into the jail: it must be on the same filesystem as the state directory (hard link across filesystems)", src)
65		}
66		return "", fmt.Errorf("link %s into the jail: %w", src, err)
67	}
68	return "/" + name, nil
69}
70
71// own hands a per-job file in the jail to the jailed uid; no-op without jailer.
72// It never follows a symlink (Lchown): the jail is writable by the jailed uid
73// once Firecracker runs, so a link planted there must not redirect the chown.
74func (l layout) own(name string) error {
75	if !l.jailed {
76		return nil
77	}
78	return os.Lchown(l.host(name), l.uid, l.uid)
79}
80
81// checkReadable verifies that other users can read the shared file, which the
82// jailed uid needs. Called once per file at driver start for jailed mode.
83func checkWorldReadable(path string) error {
84	st, err := os.Stat(path)
85	if err != nil {
86		return err
87	}
88	if st.Mode().Perm()&0o004 == 0 {
89		return fmt.Errorf("%s is not world-readable (mode %v): the jailed uid could not open it", path, st.Mode().Perm())
90	}
91	return nil
92}
93
94// copyFile copies src to dst (mode 0600) and fsyncs it.
95func copyFile(src, dst string) error {
96	in, err := os.Open(src)
97	if err != nil {
98		return err
99	}
100	defer func() { _ = in.Close() }()
101	out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
102	if err != nil {
103		return err
104	}
105	if _, err := io.Copy(out, in); err != nil {
106		_ = out.Close()
107		return err
108	}
109	if err := out.Sync(); err != nil {
110		_ = out.Close()
111		return err
112	}
113	return out.Close()
114}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 11

↑↓ moveenter openesc close