bwrap 1.1.1 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +21 -0
- data/README.md +9 -0
- data/lib/bwrap/args/args.rb +33 -4
- data/lib/bwrap/args/bind/device.rb +48 -0
- data/lib/bwrap/args/bind/library.rb +63 -47
- data/lib/bwrap/args/bind.rb +39 -41
- data/lib/bwrap/args/construct.rb +27 -36
- data/lib/bwrap/args/environment.rb +5 -1
- data/lib/bwrap/args/features/ruby_binds.rb +3 -1
- data/lib/bwrap/args/features.rb +3 -4
- data/lib/bwrap/args/mount.rb +1 -7
- data/lib/bwrap/args/namespace.rb +25 -0
- data/lib/bwrap/args/network.rb +7 -2
- data/lib/bwrap/args/user.rb +36 -0
- data/lib/bwrap/bwrap.rb +58 -26
- data/lib/bwrap/config.rb +52 -9
- data/lib/bwrap/exceptions.rb +1 -0
- data/lib/bwrap/execution/exec.rb +78 -0
- data/lib/bwrap/execution/execute.rb +25 -43
- data/lib/bwrap/execution/execution.rb +77 -50
- data/lib/bwrap/execution/logging.rb +49 -0
- data/lib/bwrap/execution/popen2e.rb +84 -12
- data/lib/bwrap/execution.rb +1 -0
- data/lib/bwrap/resolvers/executable.rb +70 -0
- data/lib/bwrap/resolvers/library/base.rb +22 -0
- data/lib/bwrap/resolvers/library/library.rb +74 -0
- data/lib/bwrap/resolvers/library/llvm_readelf.rb +133 -0
- data/lib/bwrap/resolvers/library/musl.rb +54 -0
- data/lib/bwrap/resolvers/library.rb +12 -0
- data/lib/bwrap/resolvers/mime.rb +75 -0
- data/lib/bwrap/resolvers/resolvers.rb +7 -0
- data/lib/bwrap/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +29 -18
- metadata.gz.sig +0 -0
- data/lib/bwrap/args/bind/mime.rb +0 -65
- data/lib/bwrap/args/library.rb +0 -135
data/lib/bwrap/args/features.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "bwrap/output"
|
4
4
|
require_relative "args"
|
5
|
-
require_relative "library"
|
6
5
|
|
7
6
|
# Feature parameter construction.
|
8
7
|
#
|
@@ -68,7 +67,7 @@ class Bwrap::Args::Features < Hash
|
|
68
67
|
end
|
69
68
|
|
70
69
|
private def bash_binds
|
71
|
-
return unless @config.features.bash.enabled?
|
70
|
+
return unless @config and @config.features.bash.enabled?
|
72
71
|
|
73
72
|
binds = BashBinds.new
|
74
73
|
|
@@ -76,7 +75,7 @@ class Bwrap::Args::Features < Hash
|
|
76
75
|
end
|
77
76
|
|
78
77
|
private def nscd_binds
|
79
|
-
return unless @config.features.nscd.enabled?
|
78
|
+
return unless @config and @config.features.nscd.enabled?
|
80
79
|
|
81
80
|
binds = NscdBinds.new
|
82
81
|
|
@@ -86,7 +85,7 @@ class Bwrap::Args::Features < Hash
|
|
86
85
|
# @note This does not allow development headers needed for compilation for now.
|
87
86
|
# I’ll look at it after I have an use for it.
|
88
87
|
private def ruby_binds
|
89
|
-
return unless @config.features.ruby.enabled?
|
88
|
+
return unless @config and @config.features.ruby.enabled?
|
90
89
|
|
91
90
|
binds = RubyBinds.new @config
|
92
91
|
|
data/lib/bwrap/args/mount.rb
CHANGED
@@ -6,19 +6,13 @@ require_relative "args"
|
|
6
6
|
module Bwrap::Args::Mount
|
7
7
|
# Arguments for readwrite-binding {Config#root} as /.
|
8
8
|
private def root_mount
|
9
|
-
return unless @config
|
9
|
+
return unless @config&.root
|
10
10
|
|
11
11
|
debug "Binding #{@config.root} as /"
|
12
12
|
@args.add :root_mount, "--bind", @config.root, "/"
|
13
13
|
@args.add :root_mount, "--chdir", "/"
|
14
14
|
end
|
15
15
|
|
16
|
-
# Arguments for mounting devtmpfs to /dev.
|
17
|
-
private def dev_mount
|
18
|
-
debug "Mounting new devtmpfs to /dev"
|
19
|
-
@args.add :dev_mounts, "--dev", "/dev"
|
20
|
-
end
|
21
|
-
|
22
16
|
# Arguments for mounting procfs to /proc.
|
23
17
|
private def proc_mount
|
24
18
|
debug "Mounting new procfs to /proc"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
|
6
|
+
# Namespace related arguments.
|
7
|
+
#
|
8
|
+
# Mostly for handling --unshare-*
|
9
|
+
class Bwrap::Args::Namespace
|
10
|
+
include Bwrap::Output
|
11
|
+
|
12
|
+
# Instance of {Config}.
|
13
|
+
attr_writer :config
|
14
|
+
|
15
|
+
# @param args [Bwrap::Args::Args] Arguments to be passed to bwrap.
|
16
|
+
def initialize args
|
17
|
+
@args = args
|
18
|
+
end
|
19
|
+
|
20
|
+
def shares
|
21
|
+
return unless @config&.unshare_all
|
22
|
+
|
23
|
+
@args.add :unshare_all, "--unshare-all" # Practically means that there would be nothing in the sandbox by default.
|
24
|
+
end
|
25
|
+
end
|
data/lib/bwrap/args/network.rb
CHANGED
@@ -17,14 +17,19 @@ class Bwrap::Args::Network
|
|
17
17
|
|
18
18
|
# Arguments to set hostname to whatever is configured.
|
19
19
|
def hostname
|
20
|
-
return unless @config
|
20
|
+
return unless @config&.hostname
|
21
21
|
|
22
22
|
debug "Setting hostname to #{@config.hostname}"
|
23
23
|
@args.add :hostname, %W{ --hostname #{@config.hostname} }
|
24
24
|
end
|
25
25
|
|
26
26
|
# Arguments to read-only bind /etc/resolv.conf.
|
27
|
+
#
|
28
|
+
# TODO: Probably it should be checked if target will have the symlink present before
|
29
|
+
# doing this automatically. For that reason, now this will need a flag.
|
27
30
|
def resolv_conf
|
31
|
+
return unless @config&.resolv_conf
|
32
|
+
|
28
33
|
# We can’t really bind symlinks, so let’s resolve real path to resolv.conf, in case it is symlinked.
|
29
34
|
source_resolv_conf = Pathname.new "/etc/resolv.conf"
|
30
35
|
source_resolv_conf = source_resolv_conf.realpath
|
@@ -35,7 +40,7 @@ class Bwrap::Args::Network
|
|
35
40
|
|
36
41
|
# Arguments to allow network connection inside sandbox.
|
37
42
|
def share_net
|
38
|
-
return unless @config
|
43
|
+
return unless @config&.share_net
|
39
44
|
|
40
45
|
verb "Sharing network"
|
41
46
|
@args.add :network, %w{ --share-net }
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
|
6
|
+
# User related arguments.
|
7
|
+
class Bwrap::Args::User
|
8
|
+
include Bwrap::Output
|
9
|
+
|
10
|
+
# Instance of {Config}.
|
11
|
+
attr_writer :config
|
12
|
+
|
13
|
+
# @param args [Args] Args created by {Construct}
|
14
|
+
def initialize args
|
15
|
+
@args = args
|
16
|
+
end
|
17
|
+
|
18
|
+
# Arguments to create `/run/user/#{uid}`.
|
19
|
+
def create_user_dir
|
20
|
+
trace "Creating directory /run/user/#{uid}"
|
21
|
+
@args.add :user_dir, %W{ --dir /run/user/#{uid} }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Arguments to bind necessary pulseaudio data for audio support.
|
25
|
+
def read_only_pulseaudio
|
26
|
+
return unless @config&.audio&.include? :pulseaudio
|
27
|
+
|
28
|
+
debug "Binding pulseaudio"
|
29
|
+
@args.add :audio, %W{ --ro-bind /run/user/#{uid}/pulse /run/user/#{uid}/pulse }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns current user id.
|
33
|
+
private def uid
|
34
|
+
Process.uid
|
35
|
+
end
|
36
|
+
end
|
data/lib/bwrap/bwrap.rb
CHANGED
@@ -12,14 +12,27 @@ require "bwrap/execution"
|
|
12
12
|
# using given configuration.
|
13
13
|
#
|
14
14
|
# @see ::Bwrap Bwrap module for usage example
|
15
|
+
#
|
16
|
+
# TODO: Add some means to validate what a command would actually bind.
|
17
|
+
# Like, create a method like Bwrap#wrapped_command which would just return the command instead of executing it.
|
18
|
+
# Then add some instructions about this feature, as for security it is important to know what a thing actually does.
|
19
|
+
#
|
20
|
+
# TODO: There should be a proper shell feature, which binds some always necessary things for shells.
|
21
|
+
# Maybe by default only enough to run a command using a shell, i.e. running “true” would work,
|
22
|
+
# instead of needing to specify its path.
|
15
23
|
class Bwrap::Bwrap
|
16
24
|
include Bwrap::Execution
|
17
25
|
|
26
|
+
# @note When config is not given, alternative root directory can be specified
|
27
|
+
# with {#run_inside_root}.
|
28
|
+
#
|
18
29
|
# @param config [Bwrap::Config] Configuration used to tailor bwrap
|
19
|
-
def initialize config
|
30
|
+
def initialize config = nil
|
20
31
|
# TODO: Ensure that costruct.rb and utilities it uses does not enforce Config to be valid object.
|
21
32
|
# Create a test for that also. Well, as long as that makes sense. If it doesn’t work, validate
|
22
33
|
# Config object to be valid here.
|
34
|
+
#
|
35
|
+
# Related to above, it is now optional, but a test still needs to be done.
|
23
36
|
@config = config
|
24
37
|
end
|
25
38
|
|
@@ -38,35 +51,58 @@ class Bwrap::Bwrap
|
|
38
51
|
Bwrap::Output.handle_output_options options
|
39
52
|
end
|
40
53
|
|
54
|
+
# @todo Proper documentation.
|
55
|
+
#
|
56
|
+
# @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
|
57
|
+
# @param config [Bwrap::Config|nil] Configuration to tailor bwrap sandbox.
|
58
|
+
# Defaults to config given to {#initialize}
|
59
|
+
def build_bwrap_arguments command, config: nil
|
60
|
+
construct = Bwrap::Args::Construct.new
|
61
|
+
construct.command = command
|
62
|
+
construct.config = (config || @config)
|
63
|
+
|
64
|
+
construct.calculate
|
65
|
+
bwrap_args = construct.bwrap_arguments
|
66
|
+
@construct = construct
|
67
|
+
|
68
|
+
exec_command = [ "bwrap" ]
|
69
|
+
exec_command += bwrap_args
|
70
|
+
exec_command.append command
|
71
|
+
exec_command += @cli_args if @cli_args
|
72
|
+
|
73
|
+
exec_command
|
74
|
+
end
|
75
|
+
|
41
76
|
# Binds and executes given command available on running system inside bwrap.
|
42
77
|
#
|
43
78
|
# If {Config#root} has been set, given executable is scanned for necessary
|
44
79
|
# libraries and they are bound inside sandbox. This often reduces amount of
|
45
80
|
# global binds, but some miscellaneous things may need custom handling.
|
46
81
|
#
|
82
|
+
# `kwargs` are passed to {#execute}.
|
83
|
+
#
|
47
84
|
# @see Config#features about binding bigger feature sets to sandbox.
|
48
85
|
#
|
49
86
|
# Executed command is constructed using configuration passed to constructor.
|
50
87
|
# After execution has completed, bwrap will also shut down.
|
51
88
|
#
|
52
89
|
# @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
|
90
|
+
# @option kwargs [Integer]
|
91
|
+
# log_callback (1)
|
92
|
+
# Semi-internal variable used to tailor caller in debug messages
|
53
93
|
# @see #run_inside_root to execute a command that already is inside sandbox.
|
54
|
-
def run command
|
55
|
-
|
56
|
-
construct.command = command
|
57
|
-
construct.config = @config
|
94
|
+
def run command, **kwargs
|
95
|
+
exec_command = build_bwrap_arguments command
|
58
96
|
|
59
|
-
|
60
|
-
|
97
|
+
# add 1 to log_callback so executing is shown to where this method is called at.
|
98
|
+
kwargs[:log_callback] ||= 1
|
99
|
+
kwargs[:log_callback] += 1
|
61
100
|
|
62
|
-
|
63
|
-
exec_command += bwrap_args
|
64
|
-
exec_command.append command
|
65
|
-
exec_command += @cli_args if @cli_args
|
101
|
+
result = execute exec_command, **kwargs
|
66
102
|
|
67
|
-
|
103
|
+
@construct.cleanup
|
68
104
|
|
69
|
-
|
105
|
+
result
|
70
106
|
end
|
71
107
|
|
72
108
|
# Convenience method to executes a command that is inside bwrap.
|
@@ -75,12 +111,14 @@ class Bwrap::Bwrap
|
|
75
111
|
#
|
76
112
|
# Calling this method is equivalent to setting {Config#command_inside_root} to `true`.
|
77
113
|
#
|
114
|
+
# `kwargs` are passed to {#execute}.
|
115
|
+
#
|
78
116
|
# @note This may have a bit unintuitive usage, as most things are checked anyway, so this is not
|
79
117
|
# akin to running something inside a chroot, but rather for convenience.
|
80
118
|
#
|
81
119
|
# @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
|
82
120
|
# @see #run to execute a command that needs to be bound to the sandbox.
|
83
|
-
def run_inside_root command
|
121
|
+
def run_inside_root command, **kwargs
|
84
122
|
if @config
|
85
123
|
config = @config.dup
|
86
124
|
config.command_inside_root = true
|
@@ -88,21 +126,15 @@ class Bwrap::Bwrap
|
|
88
126
|
config = nil
|
89
127
|
end
|
90
128
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
construct.calculate
|
96
|
-
bwrap_args = construct.bwrap_arguments
|
129
|
+
# add 1 to log_callback so executing is shown to where this method is called at.
|
130
|
+
kwargs[:log_callback] ||= 1
|
131
|
+
kwargs[:log_callback] += 1
|
97
132
|
|
98
|
-
exec_command =
|
99
|
-
exec_command += bwrap_args
|
100
|
-
exec_command.append command
|
101
|
-
exec_command += @cli_args if @cli_args
|
133
|
+
exec_command = build_bwrap_arguments command, config: config
|
102
134
|
|
103
|
-
execute exec_command
|
135
|
+
execute exec_command, **kwargs
|
104
136
|
|
105
|
-
construct.cleanup
|
137
|
+
@construct.cleanup
|
106
138
|
end
|
107
139
|
|
108
140
|
# Parses global bwrap flags using Optimist.
|
data/lib/bwrap/config.rb
CHANGED
@@ -17,6 +17,15 @@ require_relative "config/features"
|
|
17
17
|
# Note that all attributes also have writers, even though they are not documented.
|
18
18
|
#
|
19
19
|
# @todo Add some documentation about syntax where necessary, like for #binaries_from.
|
20
|
+
#
|
21
|
+
# TODO: I don’t remember if I made bash feature, but maybe it should be done.
|
22
|
+
# It should automatically bind /bin and /usr/bin, with a flag to bind relevant sbin dirs.
|
23
|
+
# That is because most scripts needs stuff from there. Maybe my fish profile would give some
|
24
|
+
# useful basic stuff?
|
25
|
+
#
|
26
|
+
# TODO: Maybe I should have something like second-level configuration in variable “advanced” or similar,
|
27
|
+
# which allows controlling features that more directly maps to bwrap cli args? That way it would be easier
|
28
|
+
# to use only high-level features.
|
20
29
|
class Bwrap::Config
|
21
30
|
# Array of audio schemes usable inside chroot.
|
22
31
|
#
|
@@ -31,10 +40,19 @@ class Bwrap::Config
|
|
31
40
|
# @return [Boolean] `true` if executed command is inside sandbox
|
32
41
|
attr_accessor :command_inside_root
|
33
42
|
|
34
|
-
|
43
|
+
# @return [Boolean] `true` if dummy devtmpfs should be mounted inside sandbox
|
44
|
+
attr_accessor :dev_mount
|
35
45
|
|
36
|
-
#
|
46
|
+
# Additional executables to bind to target.
|
47
|
+
#
|
48
|
+
# TODO: Implement this paragraph:
|
49
|
+
# If an executable given here is found from directory given to
|
50
|
+
# {#binaries_from=}, it is not bound to target, but only
|
51
|
+
# dependent libraries.
|
37
52
|
#
|
53
|
+
# @return [#each] Array of executables to bind
|
54
|
+
attr_accessor :extra_executables
|
55
|
+
|
38
56
|
# Causes libraries required by the executable given to {Bwrap#run} to be
|
39
57
|
# mounted inside sandbox.
|
40
58
|
#
|
@@ -42,8 +60,16 @@ class Bwrap::Config
|
|
42
60
|
# using {#libdir_mounts=}
|
43
61
|
#
|
44
62
|
# @return [Boolean] true if Linux library loaders are mounted inside chroot
|
63
|
+
#
|
64
|
+
# TODO: Since this only causes given executable be scanned for dependencies,
|
65
|
+
# and not ”--bind / /”, this one should be deprecated and something like
|
66
|
+
# ”@config.bind_dependents = true” should be added as alias of this.
|
45
67
|
attr_accessor :full_system_mounts
|
46
68
|
|
69
|
+
# If set to `true`, things like /dev/dri is bound to sandbox to enable usage
|
70
|
+
# of hardware video acceleration, for example.
|
71
|
+
attr_accessor :graphics_acceleration
|
72
|
+
|
47
73
|
attr_accessor :hostname
|
48
74
|
|
49
75
|
# Set to true if basic system directories, like /usr/lib and /usr/lib64,
|
@@ -54,6 +80,9 @@ class Bwrap::Config
|
|
54
80
|
# Often it is enough to use {#full_system_mounts=} instead of binding all
|
55
81
|
# system libraries using this flag.
|
56
82
|
#
|
83
|
+
# It may also make sense to bind specific library directories
|
84
|
+
# using {#ro_binds=}.
|
85
|
+
#
|
57
86
|
# @return [Boolean] true if libdirs are mounted to the chroot
|
58
87
|
attr_accessor :libdir_mounts
|
59
88
|
|
@@ -71,9 +100,22 @@ class Bwrap::Config
|
|
71
100
|
# Given file as bound as /etc/machine_id.
|
72
101
|
attr_accessor :machine_id
|
73
102
|
|
103
|
+
# If set to truthy, /etc/resolv.conf will be bound to target.
|
104
|
+
attr_accessor :resolv_conf
|
105
|
+
|
74
106
|
# @return [Boolean] true if network should be shared from host.
|
75
107
|
attr_accessor :share_net
|
76
108
|
|
109
|
+
# Set to truthy to remove (see bwrap’s --unshare-all) all namespaces from
|
110
|
+
# target chroot.
|
111
|
+
#
|
112
|
+
# Defaults to true.
|
113
|
+
#
|
114
|
+
# TODO: Create more fine grained control for sharing logic than this one.
|
115
|
+
#
|
116
|
+
# @return [Boolean] true if all namespaces are tried to be removed from target.
|
117
|
+
attr_accessor :unshare_all
|
118
|
+
|
77
119
|
# Name of the user inside chroot.
|
78
120
|
#
|
79
121
|
# This is optional and defaults to no user.
|
@@ -89,11 +131,11 @@ class Bwrap::Config
|
|
89
131
|
#
|
90
132
|
# Given paths are also added to PATH environment variable inside sandbox.
|
91
133
|
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
134
|
+
# Hint: At least on SUSE, many executables are symlinks to /etc/alternatives/*,
|
135
|
+
# which in turn symlinks to versioned executable under the same bindir.
|
136
|
+
# To use these executables, /etc/alternatives should also be bound:
|
95
137
|
#
|
96
|
-
#
|
138
|
+
# config.ro_binds["/etc/alternatives"] = "/etc/alternatives"
|
97
139
|
#
|
98
140
|
# @return [Array] Paths to directories where binaries are looked from.
|
99
141
|
attr_reader :binaries_from
|
@@ -113,10 +155,10 @@ class Bwrap::Config
|
|
113
155
|
|
114
156
|
# @overload ro_binds
|
115
157
|
# `Hash`[`Pathname`] => `Pathname` containing custom read-only binds.
|
116
|
-
# @overload ro_binds=
|
117
|
-
# Set given
|
158
|
+
# @overload ro_binds= binds
|
159
|
+
# Set given Hash of paths to be bound with --ro-bind.
|
118
160
|
#
|
119
|
-
# Key is source path, value is destination path.
|
161
|
+
# Key of `binds` is source path, value is destination path.
|
120
162
|
#
|
121
163
|
# Given source paths must exist.
|
122
164
|
attr_reader :ro_binds
|
@@ -139,6 +181,7 @@ class Bwrap::Config
|
|
139
181
|
@env_paths = []
|
140
182
|
@ro_binds = {}
|
141
183
|
@tmpdir = Dir.tmpdir
|
184
|
+
@unshare_all = true
|
142
185
|
end
|
143
186
|
|
144
187
|
def binaries_from= array
|
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "execute"
|
4
|
+
|
5
|
+
# Actually performs the execution.
|
6
|
+
class Bwrap::Execution::Exec
|
7
|
+
# @param value [Boolean] True if execution should be skipped
|
8
|
+
attr_writer :dry_run
|
9
|
+
|
10
|
+
attr_writer :clear_env
|
11
|
+
attr_writer :config
|
12
|
+
attr_writer :direct_output
|
13
|
+
attr_writer :env
|
14
|
+
attr_writer :error
|
15
|
+
attr_writer :fail
|
16
|
+
attr_writer :log
|
17
|
+
attr_writer :rootcmd
|
18
|
+
attr_writer :wait
|
19
|
+
|
20
|
+
attr_reader :last_status
|
21
|
+
|
22
|
+
# @see Bwrap::Execution.do_execute
|
23
|
+
def initialize command
|
24
|
+
@command = command
|
25
|
+
|
26
|
+
@fail = true
|
27
|
+
@wait = true
|
28
|
+
@log = true
|
29
|
+
@direct_output = false
|
30
|
+
@env = nil
|
31
|
+
@clear_env = false
|
32
|
+
@error = nil
|
33
|
+
@config = nil
|
34
|
+
@rootcmd = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def log_callback= value
|
38
|
+
# Adds one since this is another method in the chain.
|
39
|
+
@log_callback = value + 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute
|
43
|
+
# Default to two steps back in history. Hopefully this is correct amount...
|
44
|
+
log_callback = @log_callback || 1
|
45
|
+
|
46
|
+
command = Bwrap::Execution::Execute.format_command @command, rootcmd: @rootcmd, config: @config
|
47
|
+
Bwrap::Execution::Logging.handle_logging command, log_callback: log_callback, log: @log, dry_run: @dry_run
|
48
|
+
return if @dry_run || Bwrap::Execution::Execute.dry_run
|
49
|
+
|
50
|
+
Bwrap::Execution::Execute.open_pipes @direct_output
|
51
|
+
|
52
|
+
# If command is an array, there can’t be arrays inside the array.
|
53
|
+
# For convenience, the array is flattened here, so callers can construct commands more easily.
|
54
|
+
if command.respond_to? :flatten!
|
55
|
+
command.flatten!
|
56
|
+
end
|
57
|
+
|
58
|
+
env = @env || {}
|
59
|
+
|
60
|
+
# If command is string, splat operator (the *) does not do anything. If array, it expand the arguments.
|
61
|
+
# This causes spawning work correctly, as that’s how spawn() expects to have the arguments.
|
62
|
+
pid = spawn(env, *command, err: [ :child, :out ], out: Bwrap::Execution::Execute.w, unsetenv_others: @clear_env)
|
63
|
+
|
64
|
+
output = Bwrap::Execution::Execute.finish_execution(log: @log, wait: @wait, direct_output: @direct_output)
|
65
|
+
return pid unless @wait
|
66
|
+
|
67
|
+
# This is instant return, but allows us to have $?/$CHILD_STATUS set.
|
68
|
+
Process.wait pid
|
69
|
+
@last_status = $CHILD_STATUS
|
70
|
+
|
71
|
+
output = Bwrap::Execution::Execute.process_output output: output
|
72
|
+
Bwrap::Execution::Execute.handle_execution_fail fail: @fail, error: @error, output: output, command: command
|
73
|
+
|
74
|
+
output
|
75
|
+
ensure
|
76
|
+
Bwrap::Execution::Execute.clean_variables
|
77
|
+
end
|
78
|
+
end
|
@@ -22,24 +22,10 @@ class Bwrap::Execution::Execute
|
|
22
22
|
attr_accessor :dry_run
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if dry_run || Bwrap::Execution::Execute.dry_run
|
31
|
-
puts "Would execute “#{log_command.force_encoding("UTF-8")}” at #{caller_locations(log_callback, 1)[0]}"
|
32
|
-
return
|
33
|
-
end
|
34
|
-
|
35
|
-
return unless log
|
36
|
-
|
37
|
-
msg = "Executing “#{log_command.force_encoding("UTF-8")}” at #{caller_locations(log_callback, 1)[0]}"
|
38
|
-
Bwrap::Output.debug_output msg
|
39
|
-
end
|
40
|
-
|
41
|
-
# @return formatted command.
|
42
|
-
def self.format_command command, rootcmd:
|
25
|
+
# @param rootcmd [Array|Symbol|nil] Flags used to construct bubblewrap environment
|
26
|
+
# @param config [Bwrap::Config|nil] Configuration used to launch the command inside bubblewrap
|
27
|
+
# @return formatted command
|
28
|
+
def self.format_command command, rootcmd: nil, config: nil
|
43
29
|
# Flatten the command if required, so nils can be converted in more of cases.
|
44
30
|
# Flattenization is also done in executions, but they also take in account
|
45
31
|
# for example rootcmd, so they probably should be done in addition to this one.
|
@@ -47,10 +33,16 @@ class Bwrap::Execution::Execute
|
|
47
33
|
command.flatten!
|
48
34
|
end
|
49
35
|
|
50
|
-
|
51
|
-
return command if rootcmd.nil?
|
36
|
+
prepare_for_execution command
|
52
37
|
|
53
|
-
|
38
|
+
if config
|
39
|
+
bwrap = Bwrap::Bwrap.new config
|
40
|
+
bwrap.build_bwrap_arguments command
|
41
|
+
elsif rootcmd
|
42
|
+
prepend_rootcmd command, rootcmd: rootcmd
|
43
|
+
else
|
44
|
+
command
|
45
|
+
end
|
54
46
|
end
|
55
47
|
|
56
48
|
# Opens pipes for command output handling.
|
@@ -80,7 +72,8 @@ class Bwrap::Execution::Execute
|
|
80
72
|
exception = Bwrap::Execution::ExecutionFailed.new "Command execution failed",
|
81
73
|
command: command,
|
82
74
|
output: output
|
83
|
-
|
75
|
+
|
76
|
+
raise exception, exception.message, caller
|
84
77
|
end
|
85
78
|
|
86
79
|
# @note It makes sense for caller to just return if wait has been set and not check output.
|
@@ -119,31 +112,20 @@ class Bwrap::Execution::Execute
|
|
119
112
|
$CHILD_STATUS.success?
|
120
113
|
end
|
121
114
|
|
122
|
-
# Used by `#handle_logging`.
|
123
|
-
private_class_method def self.calculate_log_command command
|
124
|
-
return command.dup unless command.respond_to?(:join)
|
125
|
-
|
126
|
-
temp = command.dup
|
127
|
-
|
128
|
-
# Wrap multi word arguments to quotes, for convenience.
|
129
|
-
# NOTE: This is not exactly safe, but this is only a debugging aid anyway.
|
130
|
-
temp.map! do |argument|
|
131
|
-
if argument.include? " "
|
132
|
-
escaped = argument.gsub '"', '\"'
|
133
|
-
argument = %["#{escaped}"]
|
134
|
-
end
|
135
|
-
argument
|
136
|
-
end
|
137
|
-
|
138
|
-
temp.join(" ")
|
139
|
-
end
|
140
|
-
|
141
115
|
# If command is an `Array`, Replaces nil values with "".
|
142
|
-
|
116
|
+
#
|
117
|
+
# Also converts Pathnames to strings.
|
118
|
+
private_class_method def self.prepare_for_execution command
|
143
119
|
return unless command.respond_to? :map!
|
144
120
|
|
145
121
|
command.map! do |argument|
|
146
|
-
argument.
|
122
|
+
if argument.is_a? Pathname
|
123
|
+
argument.to_s
|
124
|
+
elsif argument.nil?
|
125
|
+
""
|
126
|
+
else
|
127
|
+
argument
|
128
|
+
end
|
147
129
|
end
|
148
130
|
end
|
149
131
|
|