@@ -3,20 +3,38 @@ package runner
3
3
import (
4
4
"context"
5
5
"errors"
6
+ "fmt"
6
7
"os/exec"
7
8
"path/filepath"
9
+ "strings"
8
10
9
11
"github.com/buildbarn/bb-remote-execution/pkg/proto/runner"
10
12
"github.com/buildbarn/bb-storage/pkg/filesystem"
11
13
"github.com/buildbarn/bb-storage/pkg/filesystem/path"
12
14
"github.com/buildbarn/bb-storage/pkg/util"
15
+ "golang.org/x/sys/unix"
13
16
14
17
"google.golang.org/grpc/codes"
15
18
"google.golang.org/grpc/status"
16
19
"google.golang.org/protobuf/types/known/anypb"
17
20
"google.golang.org/protobuf/types/known/emptypb"
18
21
)
19
22
23
+ // Mount information for the special filesystems
24
+ // to mount in the input root when using 'chroot'.
25
+ var (
26
+ procMountpointComponent = path .MustNewComponent ("proc" )
27
+ sysMountpointComponent = path .MustNewComponent ("sys" )
28
+ mounts = []struct {
29
+ mountpoint path.Component
30
+ fstype string
31
+ source string
32
+ }{
33
+ {procMountpointComponent , "proc" , "/proc" },
34
+ {sysMountpointComponent , "sysfs" , "/sys" },
35
+ }
36
+ )
37
+
20
38
// logFileResolver is an implementation of path.ComponentWalker that is
21
39
// used by localRunner.Run() to traverse to the directory of stdout and
22
40
// stderr log files, so that they may be opened.
@@ -136,6 +154,44 @@ func (r *localRunner) Run(ctx context.Context, request *runner.RunRequest) (*run
136
154
}
137
155
cmd .Stdout = stdout
138
156
157
+ // Mount special filesystems.
158
+ requiresSpecialFilesystems := cmd .SysProcAttr != nil && cmd .SysProcAttr .Chroot != ""
159
+ var MountRootDirectory filesystem.Directory
160
+
161
+ if requiresSpecialFilesystems {
162
+ var dir filesystem.Directory
163
+ dir = r .buildDirectory
164
+ // TODO(nils): How to best open the input root `Directory`
165
+ // It must be a `localDirectory`, but outer directories can be `lazyDirectory`.
166
+ for _ , segment := range strings .Split (request .InputRootDirectory , "/" ) {
167
+ component := path .MustNewComponent (segment )
168
+ dircloser , err := dir .EnterDirectory (component )
169
+ // We want to keep the input root open so we can use its file descriptor.
170
+ if segment != "root" {
171
+ defer dircloser .Close ()
172
+ }
173
+
174
+ dir = dircloser .(filesystem.Directory )
175
+ if err != nil {
176
+ return nil , fmt .Errorf ("Could not enter directory component '%s' in '%#v'" , segment , inputRootDirectory )
177
+ }
178
+ }
179
+ MountRootDirectory = dir
180
+
181
+ for _ , mount := range mounts {
182
+ err := MountRootDirectory .Mkdir (mount .mountpoint , 0o555 )
183
+ if err != nil {
184
+ if err != unix .EEXIST {
185
+ return nil , util .StatusWrapf (err , "Failed to create mount point: '%#v' in the input root" , mount .mountpoint )
186
+ }
187
+ }
188
+
189
+ if err := MountRootDirectory .Mount (mount .mountpoint , mount .source , mount .fstype ); err != nil {
190
+ return nil , util .StatusWrapf (err , "Failed to mount '%#v' in the input root" , mount )
191
+ }
192
+ }
193
+ }
194
+
139
195
stderr , err := r .openLog (request .StderrPath )
140
196
if err != nil {
141
197
stdout .Close ()
@@ -166,6 +222,14 @@ func (r *localRunner) Run(ctx context.Context, request *runner.RunRequest) (*run
166
222
}
167
223
}
168
224
225
+ if requiresSpecialFilesystems {
226
+ for _ , mount := range mounts {
227
+ if err := MountRootDirectory .Unmount (mount .mountpoint ); err != nil {
228
+ return nil , util .StatusWrapf (err , "Failed to unmount '%#v' in the input root" , mount )
229
+ }
230
+ }
231
+ }
232
+
169
233
// Attach rusage information to the response.
170
234
posixResourceUsage , err := anypb .New (getPOSIXResourceUsage (cmd ))
171
235
if err != nil {
0 commit comments