Detect AppImage and update executable environment if required

If starting a process while running from within AppImage adjust
the LD_LIBRARY_PATH of the subprocess when the executable exists
outside of the AppImage. This prevents issues of invalid dynamic
library lookups when the AppImage contains common named libraries.
This commit is contained in:
Chris Roberts 2018-07-31 10:39:26 -07:00
parent 80edb39122
commit 6009492e73
2 changed files with 65 additions and 1 deletions

View File

@ -93,7 +93,7 @@ module Vagrant
# Special installer-related things
if Vagrant.in_installer?
installer_dir = ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"].to_s.downcase
installer_dir = Vagrant.installer_embedded_dir.to_s.downcase
# If we're in an installer on Mac and we're executing a command
# in the installer context, then force DYLD_LIBRARY_PATH to look
@ -123,6 +123,18 @@ module Vagrant
@logger.info("Command not in installer, restoring original environment...")
jailbreak(process.environment)
end
# If running within an AppImage and calling external executable. When
# executable is external set the LD_LIBRARY_PATH to host values.
if ENV["VAGRANT_APPIMAGE"]
embed_path = Pathname.new(Vagrant.installer_embedded_dir).expand_path.to_s
exec_path = Pathname.new(@command[0]).expand_path.to_s
if !exec_path.start_with?(embed_path) && ENV["VAGRANT_APPIMAGE_LD_LIBRARY_PATH"]
@logger.info("Detected AppImage environment and request to external binary. Updating library path.")
@logger.debug("Setting LD_LIBRARY_PATH to #{ENV["VAGRANT_APPIMAGE_LD_LIBRARY_PATH"]}")
process.environment["LD_LIBRARY_PATH"] = ENV["VAGRANT_APPIMAGE_LD_LIBRARY_PATH"].to_s
end
end
else
@logger.info("Vagrant not running in installer, restoring original environment...")
jailbreak(process.environment)

View File

@ -46,6 +46,58 @@ describe Vagrant::Util::Subprocess do
# we should see our data as the output from `cat`
expect(result.stdout).to eq(data)
end
context "running within AppImage" do
let(:appimage_ld_path) { nil }
let(:exec_path) { "/exec/path" }
let(:appimage_path) { "/appimage" }
let(:process) { double("process", io: process_io, environment: process_env) }
let(:process_io) { double("process_io") }
let(:process_env) { double("process_env") }
let(:subject) { described_class.new(exec_path) }
before do
allow(process).to receive(:start)
allow(process).to receive(:duplex=)
allow(process).to receive(:alive?).and_return(false)
allow(process).to receive(:exited?).and_return(true)
allow(process).to receive(:poll_for_exit).and_return(0)
allow(process).to receive(:exit_code).and_return(0)
allow(process_io).to receive(:stdout=)
allow(process_io).to receive(:stderr=)
allow(process_io).to receive(:stdin).and_return(double("io_stdin", "sync=" => true))
allow(process_env).to receive(:[]=)
allow(ENV).to receive(:[]).with("VAGRANT_INSTALLER_ENV").and_return("1")
allow(ENV).to receive(:[]).with("VAGRANT_APPIMAGE").and_return("1")
allow(ENV).to receive(:[]).with("VAGRANT_APPIMAGE_LD_LIBRARY_PATH").and_return(appimage_ld_path)
allow(File).to receive(:file?).with(exec_path).and_return(true)
allow(ChildProcess).to receive(:build).and_return(process)
allow(Vagrant).to receive(:installer_embedded_dir).and_return(appimage_path)
allow(Vagrant).to receive(:user_data_path).and_return("")
end
after { subject.execute }
it "should not update LD_LIBRARY_PATH when environment variable is not set" do
expect(process_env).not_to receive(:[]=).with("LD_LIBRARY_PATH", anything)
end
context "when APPIMAGE_LD_LIBRARY_PATH environment variable is set" do
let(:appimage_ld_path) { "APPIMAGE_SYSTEM_LIBS" }
it "should set LD_LIBRARY_PATH when executable is not within appimage" do
expect(process_env).to receive(:[]=).with("LD_LIBRARY_PATH", appimage_ld_path)
end
context "when executable is located within AppImage" do
let(:exec_path) { "#{appimage_path}/exec/path" }
it "should not set LD_LIBRARY_PATH" do
expect(process_env).not_to receive(:[]=).with("LD_LIBRARY_PATH", anything)
end
end
end
end
end
describe "#running?" do