From 2cd30019d12df780261998b4b653f285253778e9 Mon Sep 17 00:00:00 2001 From: Charlie Le <20309750+CharlieQLe@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:20:22 -0500 Subject: [PATCH 1/5] Initial work on Flatpak support --- dist/flatpak/org.gabmus.envision.json | 96 ++++++++++++++++++++++++ src/depcheck/mod.rs | 2 + src/file_builders/active_runtime_json.rs | 36 +++++---- src/file_builders/openvrpaths_vrpath.rs | 27 +++++-- src/is_flatpak.rs | 6 ++ src/main.rs | 1 + src/ui/app.rs | 77 +++++++++++-------- src/ui/job_worker/internal_worker.rs | 31 ++++---- src/ui/main_view.rs | 32 +++++++- src/util/file_utils.rs | 12 ++- 10 files changed, 249 insertions(+), 71 deletions(-) create mode 100644 dist/flatpak/org.gabmus.envision.json create mode 100644 src/is_flatpak.rs diff --git a/dist/flatpak/org.gabmus.envision.json b/dist/flatpak/org.gabmus.envision.json new file mode 100644 index 0000000..3cd171e --- /dev/null +++ b/dist/flatpak/org.gabmus.envision.json @@ -0,0 +1,96 @@ +{ + "id": "org.gabmus.envision", + "branch": "47", + "runtime": "org.gnome.Sdk", + "runtime-version": "47", + "sdk": "org.gnome.Sdk", + "sdk-extensions": [ + "org.freedesktop.Sdk.Extension.rust-stable", + "org.freedesktop.Sdk.Extension.llvm19" + ], + "command": "envision", + "build-options": { + "append-path": "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm19/bin", + "env": { + "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "clang", + "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold", + "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER": "clang", + "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold" + }, + "build-args": [ + "--share=network" + ] + }, + "cleanup": [ + "/share/doc", + "/share/man" + ], + "finish-args": [ + "--share=ipc", + "--share=network", + "--socket=wayland", + "--socket=fallback-x11", + "--socket=pulseaudio", + "--device=all", + "--filesystem=xdg-run/pipewire-0", + "--filesystem=xdg-run/monado_comp_ipc", + "--filesystem=~/.steam", + "--filesystem=~/.var/app/com.valvesoftware.Steam", + "--talk-name=org.freedesktop.Flatpak" + ], + "modules": [ + { + "name": "OpenXR-SDK", + "buildsystem": "cmake", + "sources": [ + { + "type": "git", + "url": "https://github.com/KhronosGroup/OpenXR-SDK-Source.git", + "tag": "release-1.1.42" + } + ] + }, + { + "name": "vte", + "buildsystem": "meson", + "config-opts": [ + "-Dgtk4=true", + "-Dgtk3=false" + ], + "sources": [ + { + "type": "archive", + "url": "https://gitlab.gnome.org/GNOME/vte/-/archive/0.78.0/vte-0.78.0.tar.gz", + "sha256": "82e19d11780fed4b66400f000829ce5ca113efbbfb7975815f26ed93e4c05f2d" + } + ] + }, + { + "name": "eigen", + "buildsystem": "cmake", + "builddir": true, + "build-options": { + "config-opts": [ + "-DEIGEN_BUILD_CMAKE_PACKAGE=NO" + ] + }, + "sources": [ + { + "type": "git", + "url": "https://gitlab.com/libeigen/eigen.git", + "tag": "3.4.0" + } + ] + }, + { + "name": "Envision", + "buildsystem": "meson", + "sources": [ + { + "type": "dir", + "path": "../../" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/depcheck/mod.rs b/src/depcheck/mod.rs index 54da91d..37424d6 100644 --- a/src/depcheck/mod.rs +++ b/src/depcheck/mod.rs @@ -125,6 +125,8 @@ fn include_paths() -> Vec { vec![ "/usr/include".into(), "/usr/local/include".into(), + // flatpak applications use /app + "/app/include".into(), // fedora puts avcodec here "/usr/include/ffmpeg".into(), "/usr/include/x86_64-linux-gnu".into(), diff --git a/src/file_builders/active_runtime_json.rs b/src/file_builders/active_runtime_json.rs index 3f5e73f..f490947 100644 --- a/src/file_builders/active_runtime_json.rs +++ b/src/file_builders/active_runtime_json.rs @@ -1,8 +1,5 @@ use crate::{ - paths::{get_backup_dir, SYSTEM_PREFIX}, - profile::Profile, - util::file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly}, - xdg::XDG, + is_flatpak::IS_FLATPAK, paths::{get_backup_dir, get_home_dir, SYSTEM_PREFIX}, profile::Profile, util::file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly}, xdg::XDG }; use serde::{Deserialize, Serialize}; use std::{ @@ -138,17 +135,28 @@ fn relativize_active_runtime_lib_path(ar: &ActiveRuntime, path: &Path) -> Active } pub fn set_current_active_runtime_to_profile(profile: &Profile) -> anyhow::Result<()> { - let dest = get_active_runtime_json_path(); - set_file_readonly(&dest, false)?; - backup_steam_active_runtime(); - let pfx = profile.clone().prefix; - let mut ar = build_profile_active_runtime(profile)?; - // hack: relativize libopenxr_monado.so path for system installs - if pfx == PathBuf::from(SYSTEM_PREFIX) { - ar = relativize_active_runtime_lib_path(&ar, &dest); + let mut dests = vec![ + get_active_runtime_json_path(), + get_home_dir().join(".var/app/com.valvesoftware.Steam/config/openxr/1/active_runtime.json"), + ]; + if *IS_FLATPAK { + dests.push(get_home_dir().join(".config/openxr/1/active_runtime.json")); + } + backup_steam_active_runtime(); + let pfx: PathBuf = profile.clone().prefix; + for dest in dests { + if !dest.is_file() { + continue; + } + let mut ar = build_profile_active_runtime(profile)?; + // hack: relativize libopenxr_monado.so path for system installs + if pfx == PathBuf::from(SYSTEM_PREFIX) { + ar = relativize_active_runtime_lib_path(&ar, &dest); + } + set_file_readonly(&dest, false)?; + dump_active_runtime_to_path(&ar, &dest)?; + set_file_readonly(&dest, true)?; } - dump_current_active_runtime(&ar)?; - set_file_readonly(&dest, true)?; Ok(()) } diff --git a/src/file_builders/openvrpaths_vrpath.rs b/src/file_builders/openvrpaths_vrpath.rs index 1108717..c4a3e54 100644 --- a/src/file_builders/openvrpaths_vrpath.rs +++ b/src/file_builders/openvrpaths_vrpath.rs @@ -1,10 +1,7 @@ use std::path::{Path, PathBuf}; use crate::{ - paths::get_backup_dir, - profile::Profile, - util::file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly}, - xdg::XDG, + is_flatpak::IS_FLATPAK, paths::{get_home_dir, get_backup_dir}, profile::Profile, util::file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly}, xdg::XDG }; use serde::{ser::Error, Deserialize, Serialize}; @@ -23,9 +20,19 @@ pub fn get_openvr_conf_dir() -> PathBuf { } fn get_openvrpaths_vrpath_path() -> PathBuf { + if *IS_FLATPAK { + return get_home_dir().join(".config/openvr/openvrpaths.vrpath") + } get_openvr_conf_dir().join("openvrpaths.vrpath") } +fn get_openvrpaths_vrpaths() -> Vec { + vec![ + get_openvrpaths_vrpath_path(), + get_home_dir().join(".var/app/com.valvesoftware.Steam/config/openvr/openvrpaths.vrpath"), + ] +} + pub fn is_steam(ovr_paths: &OpenVrPaths) -> bool { ovr_paths.runtime.iter().any(|rt| { rt.to_string_lossy() @@ -104,11 +111,15 @@ pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths { } pub fn set_current_openvrpaths_to_profile(profile: &Profile) -> anyhow::Result<()> { - let dest = get_openvrpaths_vrpath_path(); - set_file_readonly(&dest, false)?; backup_steam_openvrpaths(); - dump_current_openvrpaths(&build_profile_openvrpaths(profile))?; - set_file_readonly(&dest, true)?; + for dest in get_openvrpaths_vrpaths() { + if !dest.is_file() { + continue; + } + set_file_readonly(&dest, false)?; + dump_openvrpaths_to_path(&build_profile_openvrpaths(profile), &dest)?; + set_file_readonly(&dest, true)?; + } Ok(()) } diff --git a/src/is_flatpak.rs b/src/is_flatpak.rs new file mode 100644 index 0000000..195bd05 --- /dev/null +++ b/src/is_flatpak.rs @@ -0,0 +1,6 @@ +use lazy_static::lazy_static; +use std::path::Path; + +lazy_static! { + pub static ref IS_FLATPAK: bool = Path::new("/.flatpak-info").is_file(); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d22b860..0ec7269 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ pub mod env_var_descriptions; pub mod file_builders; pub mod gpu_profile; pub mod is_appimage; +pub mod is_flatpak; pub mod linux_distro; pub mod log_parser; pub mod openxr_prober; diff --git a/src/ui/app.rs b/src/ui/app.rs index 607597b..1a1d424 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -20,34 +20,21 @@ use crate::{ build_mercury::get_build_mercury_jobs, build_monado::get_build_monado_jobs, build_opencomposite::get_build_opencomposite_jobs, build_openhmd::get_build_openhmd_jobs, build_wivrn::get_build_wivrn_jobs, - }, - config::Config, - constants::APP_NAME, - depcheck::{ + }, config::Config, constants::APP_NAME, depcheck::{ basalt_deps::get_missing_basalt_deps, common::dep_pkexec, libsurvive_deps::get_missing_libsurvive_deps, mercury_deps::get_missing_mercury_deps, monado_deps::get_missing_monado_deps, openhmd_deps::get_missing_openhmd_deps, wivrn_deps::get_missing_wivrn_deps, - }, - file_builders::{ + }, file_builders::{ active_runtime_json::{ set_current_active_runtime_to_profile, set_current_active_runtime_to_steam, }, openvrpaths_vrpath::{ set_current_openvrpaths_to_profile, set_current_openvrpaths_to_steam, }, - }, - linux_distro::LinuxDistro, - openxr_prober::is_openxr_ready, - paths::get_data_dir, - profile::{Profile, XRServiceType}, - stateless_action, - steam_linux_runtime_injector::{ + }, is_flatpak::IS_FLATPAK, linux_distro::LinuxDistro, openxr_prober::is_openxr_ready, paths::get_data_dir, profile::{Profile, XRServiceType}, stateless_action, steam_linux_runtime_injector::{ restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile, - }, - util::file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd}, - vulkaninfo::VulkanInfo, - xr_devices::XRDevice, + }, util::file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd}, vulkaninfo::VulkanInfo, xr_devices::XRDevice }; use adw::{prelude::*, ResponseAppearance}; use gtk::glib::{self, clone}; @@ -56,7 +43,7 @@ use relm4::{ new_action_group, new_stateful_action, new_stateless_action, prelude::*, }; -use std::{collections::VecDeque, fs::remove_file, time::Duration}; +use std::{collections::{HashMap, VecDeque}, fs::remove_file, process::Command, time::Duration}; pub struct App { application: adw::Application, @@ -175,9 +162,20 @@ impl App { }; self.debug_view.sender().emit(DebugViewMsg::ClearLog); self.xr_devices = vec![]; - remove_file(prof.xrservice_type.ipc_file_path()) - .is_err() - .then(|| println!("Failed to remove xrservice IPC file")); + if *IS_FLATPAK { + Command::new("flatpak-spawn") + .args(vec![ + "--host", + "rm", + prof.xrservice_type.ipc_file_path().to_str().unwrap() + ]) + .output() + .expect("Failed to remove xrservice IPC file"); + } else { + remove_file(prof.xrservice_type.ipc_file_path()) + .is_err() + .then(|| println!("Failed to remove xrservice IPC file")); + } let worker = JobWorker::xrservice_worker_wrap_from_profile( &prof, sender.input_sender(), @@ -218,11 +216,28 @@ impl App { let prof = self.get_selected_profile(); if let Some(autostart_cmd) = &prof.autostart_command { let mut jobs = VecDeque::new(); - jobs.push_back(WorkerJob::new_cmd( - Some(prof.environment.clone()), - "sh".into(), - Some(vec!["-c".into(), autostart_cmd.clone()]), - )); + + if *IS_FLATPAK { + let mut args = vec![String::from("--host")]; + for (key, value) in &prof.environment { + args.push(format!("--env={}={}", key, value)); + } + args.push(String::from("sh")); + args.push(String::from("-c")); + args.push(autostart_cmd.clone()); + + jobs.push_back(WorkerJob::new_cmd( + Some(HashMap::new()), + "flatpak-spawn".into(), + Some(args), + )); + } else { + jobs.push_back(WorkerJob::new_cmd( + Some(prof.environment.clone()), + "sh".into(), + Some(vec!["-c".into(), autostart_cmd.clone()]), + )); + } let autostart_worker = JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(rows) => Msg::OnServiceLog(rows), JobWorkerOut::Exit(code) => Msg::OnAutostartExit(code), @@ -533,7 +548,7 @@ impl AsyncComponent for App { .sender() .emit(BuildWindowMsg::UpdateBuildStatus(BuildStatus::Done)); let profile = self.get_selected_profile(); - if dep_pkexec().check() { + if dep_pkexec().check() || *IS_FLATPAK { self.setcap_confirm_dialog.present(Some(&self.app_win)); } else { alert_w_widget( @@ -606,11 +621,11 @@ impl AsyncComponent for App { .emit(DebugViewMsg::UpdateSelectedProfile(prof.clone())); } Msg::RunSetCap => { - if !dep_pkexec().check() { - println!("pkexec not found, skipping setcap"); - } else { + if dep_pkexec().check() || *IS_FLATPAK { let profile = self.get_selected_profile(); setcap_cap_sys_nice_eip(&profile).await; + } else { + println!("pkexec not found, skipping setcap"); } } Msg::ProfileSelected(prof) => { @@ -698,7 +713,7 @@ impl AsyncComponent for App { let worker = JobWorker::new_with_timer( Duration::from_millis(500), WorkerJob::new_func(Box::new(move || { - let ready = is_openxr_ready(); + let ready = !*IS_FLATPAK && is_openxr_ready(); FuncWorkerOut { success: ready, ..Default::default() diff --git a/src/ui/job_worker/internal_worker.rs b/src/ui/job_worker/internal_worker.rs index 103c822..cf8ee5d 100644 --- a/src/ui/job_worker/internal_worker.rs +++ b/src/ui/job_worker/internal_worker.rs @@ -3,19 +3,12 @@ use super::{ state::JobWorkerState, }; use crate::{ - profile::{LighthouseDriver, Profile}, - ui::SENDER_IO_ERR_MSG, + is_flatpak::IS_FLATPAK, profile::{LighthouseDriver, Profile}, ui::SENDER_IO_ERR_MSG }; use nix::unistd::Pid; use relm4::{prelude::*, Worker}; use std::{ - collections::VecDeque, - io::{BufRead, BufReader}, - mem, - os::unix::process::ExitStatusExt, - process::{Command, Stdio}, - sync::{Arc, Mutex}, - thread, + collections::{HashMap, VecDeque}, io::{BufRead, BufReader}, mem, os::unix::process::ExitStatusExt, process::{Command, Stdio}, sync::{Arc, Mutex}, thread }; macro_rules! logger_thread { @@ -217,13 +210,23 @@ impl InternalJobWorker { vec![], ), }; - let data = CmdWorkerData { - environment: env, - command, - args, + let mut data = CmdWorkerData { + environment: env.clone(), + command: command.clone(), + args: args.clone(), }; + if *IS_FLATPAK { + data.environment = HashMap::new(); + data.command = String::from("flatpak-spawn"); + data.args = vec![String::from("--host")]; + for (key, value) in env { + data.args.push(format!("--env={}={}", key, value)); + } + data.args.push(command); + data.args.extend(args); + } let mut jobs = VecDeque::new(); - jobs.push_back(WorkerJob::Cmd(data)); + jobs.push_back(WorkerJob::Cmd(data)); Self::builder().detach_worker(JobWorkerInit { jobs, state }) } } diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index 43484e3..949b62f 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -17,6 +17,7 @@ use crate::{ config::Config, depcheck::common::dep_pkexec, gpu_profile::{get_amd_gpu_power_profile, GpuPowerProfile}, + is_flatpak::IS_FLATPAK, paths::{get_data_dir, get_home_dir}, profile::{LighthouseDriver, Profile, XRServiceType}, stateless_action, @@ -270,7 +271,7 @@ impl SimpleComponent for MainView { add_css_class: "card", add_css_class: "padded", #[track = "model.changed(Self::selected_profile())"] - set_visible: match mount_has_nosuid(&model.selected_profile.prefix) { + set_visible: !*IS_FLATPAK && match mount_has_nosuid(&model.selected_profile.prefix) { Ok(b) => b, Err(_) => { eprintln!( @@ -302,7 +303,34 @@ impl SimpleComponent for MainView { add_css_class: "card", add_css_class: "padded", #[track = "model.changed(Self::selected_profile())"] - set_visible: !dep_pkexec().check(), + set_visible: *IS_FLATPAK, + warning_heading(), + gtk::Label { + set_label: concat!( + "Envision is currently running as a Flatpak.\n", + "If Steam is running as a Flatpak, it will need to be granted certain ", + "permissions to run VR applications. Run the following command on your host ", + "terminal to grant the Steam Flatpak access to Envision's Monado socket:\n\n", + "flatpak --user override --filesystem=xdg-run/monado_comp_ipc com.valvesoftware.Steam\n\n", + "Run the following to also grant the Steam Flatpak access to Envision's data:\n\n", + "flatpak --user override --filesystem=~/.var/app/org.gabmus.envision com.valvesoftware.Steam\n\n", + ), + set_use_markup: true, + add_css_class: "warning", + set_xalign: 0.0, + set_wrap: true, + set_wrap_mode: gtk::pango::WrapMode::Word, + } + }, + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_hexpand: true, + set_vexpand: false, + set_spacing: 12, + add_css_class: "card", + add_css_class: "padded", + #[track = "model.changed(Self::selected_profile())"] + set_visible: !*IS_FLATPAK && !dep_pkexec().check(), warning_heading(), gtk::Label { set_label: &format!( diff --git a/src/util/file_utils.rs b/src/util/file_utils.rs index e05a7ac..eb6dffd 100644 --- a/src/util/file_utils.rs +++ b/src/util/file_utils.rs @@ -1,4 +1,4 @@ -use crate::{async_process::async_process, profile::Profile}; +use crate::{async_process::async_process, is_flatpak::IS_FLATPAK, profile::Profile}; use anyhow::bail; use nix::{ errno::Errno, @@ -81,7 +81,15 @@ pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec { } pub async fn setcap_cap_sys_nice_eip(profile: &Profile) { - if let Err(e) = async_process("pkexec", Some(&setcap_cap_sys_nice_eip_cmd(profile)), None).await + let setcap_cmd = setcap_cap_sys_nice_eip_cmd(profile); + if *IS_FLATPAK { + let mut flatpak_cmd = vec!["--host".into(), "pkexec".into()]; + flatpak_cmd.extend(setcap_cmd); + if let Err(e) = async_process("flatpak-spawn", Some(&flatpak_cmd), None).await + { + eprintln!("Error: failed running setcap: {e}"); + } + } else if let Err(e) = async_process("pkexec", Some(&setcap_cmd), None).await { eprintln!("Error: failed running setcap: {e}"); } From dd4db972158d610cdb9c92edbd11b3c21e76dc52 Mon Sep 17 00:00:00 2001 From: Charlie Le <20309750+CharlieQLe@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:14:12 -0500 Subject: [PATCH 2/5] Construct commands separately to support flatpak-spawn and update async_process for flatpak-spawn --- src/async_process.rs | 22 +++++++++++++--- src/build_tools/cmake.rs | 4 ++- src/build_tools/git.rs | 3 ++- src/builders/build_basalt.rs | 2 ++ src/builders/build_mercury.rs | 1 + src/builders/build_openhmd.rs | 3 +++ src/ui/app.rs | 39 +++++++--------------------- src/ui/install_wivrn_box.rs | 1 + src/ui/job_worker/internal_worker.rs | 21 ++++----------- src/ui/job_worker/job.rs | 3 +++ src/ui/steamvr_calibration_box.rs | 2 ++ src/ui/wivrn_wired_start_box.rs | 1 + src/util/cmd_utils.rs | 26 +++++++++++++++++++ src/util/file_utils.rs | 12 ++------- src/util/mod.rs | 1 + 15 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 src/util/cmd_utils.rs diff --git a/src/async_process.rs b/src/async_process.rs index 9bfa4ed..1f0ab4c 100644 --- a/src/async_process.rs +++ b/src/async_process.rs @@ -2,6 +2,7 @@ use std::ffi::OsStr; use std::process::Stdio; use std::{collections::HashMap, os::unix::process::ExitStatusExt}; use tokio::process::Command; +use crate::is_flatpak::IS_FLATPAK; pub struct AsyncProcessOut { pub exit_code: i32, @@ -13,10 +14,25 @@ pub async fn async_process, T: AsRef>( cmd: S, args: Option<&[T]>, env: Option>, + host_spawn: Option, ) -> anyhow::Result { - let cmd = Command::new(cmd) - .args(args.unwrap_or_default()) - .envs(env.unwrap_or_default()) + let mut command: Command; + if *IS_FLATPAK && host_spawn.unwrap_or_default() { + let mut flatpak_env = vec![]; + for (key, value) in env.unwrap_or_default() { + flatpak_env.push(format!("--env={}={}", key, value)); + } + command = Command::new("flatpak-spawn"); + command.arg("--host") + .args(flatpak_env) + .arg(cmd) + .args(args.unwrap_or_default()); + } else { + command = Command::new(cmd); + command.args(args.unwrap_or_default()).envs(env.unwrap_or_default()); + } + + let cmd = command .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) diff --git a/src/build_tools/cmake.rs b/src/build_tools/cmake.rs index 5946ec6..f2d3fc4 100644 --- a/src/build_tools/cmake.rs +++ b/src/build_tools/cmake.rs @@ -26,7 +26,7 @@ impl Cmake { } } args.push(self.source_dir.to_string_lossy().to_string()); - WorkerJob::new_cmd(self.env.clone(), "cmake".into(), Some(args)) + WorkerJob::new_cmd(self.env.clone(), "cmake".into(), Some(args), Some(false)) } pub fn get_build_job(&self) -> WorkerJob { @@ -37,6 +37,7 @@ impl Cmake { "--build".into(), self.build_dir.to_string_lossy().to_string(), ]), + Some(false), ) } @@ -48,6 +49,7 @@ impl Cmake { "--install".into(), self.build_dir.to_string_lossy().to_string(), ]), + Some(false), ) } } diff --git a/src/build_tools/git.rs b/src/build_tools/git.rs index eb5a90c..923b25b 100644 --- a/src/build_tools/git.rs +++ b/src/build_tools/git.rs @@ -13,7 +13,7 @@ impl Git { fn cmd(&self, args: Vec) -> WorkerJob { let mut nargs = vec!["-C".into(), self.dir.to_string_lossy().to_string()]; nargs.extend(args); - WorkerJob::new_cmd(None, "git".into(), Some(nargs)) + WorkerJob::new_cmd(None, "git".into(), Some(nargs), Some(false)) } fn get_repo(&self) -> String { @@ -84,6 +84,7 @@ impl Git { self.dir.to_string_lossy().to_string(), "--recurse-submodules".into(), ]), + Some(false), ) } diff --git a/src/builders/build_basalt.rs b/src/builders/build_basalt.rs index e67e081..cc1bd2e 100644 --- a/src/builders/build_basalt.rs +++ b/src/builders/build_basalt.rs @@ -79,6 +79,7 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque VecDeque VecDeque { profile.prefix.to_string_lossy().to_string(), get_cache_dir().to_string_lossy().to_string(), ]), + Some(false), )); jobs diff --git a/src/builders/build_openhmd.rs b/src/builders/build_openhmd.rs index 1157eca..3404bbd 100644 --- a/src/builders/build_openhmd.rs +++ b/src/builders/build_openhmd.rs @@ -62,6 +62,7 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque< .to_string_lossy() .to_string(), ]), + Some(false), )); } // build job @@ -69,6 +70,7 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque< None, "ninja".into(), Some(vec!["-C".into(), build_dir.to_string_lossy().to_string()]), + Some(false), )); // install job jobs.push_back(WorkerJob::new_cmd( @@ -79,6 +81,7 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque< build_dir.to_string_lossy().to_string(), "install".into(), ]), + Some(false), )); jobs diff --git a/src/ui/app.rs b/src/ui/app.rs index 1a1d424..d46a7ee 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -34,7 +34,7 @@ use crate::{ }, }, is_flatpak::IS_FLATPAK, linux_distro::LinuxDistro, openxr_prober::is_openxr_ready, paths::get_data_dir, profile::{Profile, XRServiceType}, stateless_action, steam_linux_runtime_injector::{ restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile, - }, util::file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd}, vulkaninfo::VulkanInfo, xr_devices::XRDevice + }, util::{cmd_utils::make_command, file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd}}, vulkaninfo::VulkanInfo, xr_devices::XRDevice }; use adw::{prelude::*, ResponseAppearance}; use gtk::glib::{self, clone}; @@ -43,7 +43,7 @@ use relm4::{ new_action_group, new_stateful_action, new_stateless_action, prelude::*, }; -use std::{collections::{HashMap, VecDeque}, fs::remove_file, process::Command, time::Duration}; +use std::{collections::VecDeque, fs::remove_file, time::Duration}; pub struct App { application: adw::Application, @@ -163,12 +163,7 @@ impl App { self.debug_view.sender().emit(DebugViewMsg::ClearLog); self.xr_devices = vec![]; if *IS_FLATPAK { - Command::new("flatpak-spawn") - .args(vec![ - "--host", - "rm", - prof.xrservice_type.ipc_file_path().to_str().unwrap() - ]) + make_command(String::from("rm"), Some(&[prof.xrservice_type.ipc_file_path().to_str().unwrap()]), None, Some(true)) .output() .expect("Failed to remove xrservice IPC file"); } else { @@ -216,28 +211,12 @@ impl App { let prof = self.get_selected_profile(); if let Some(autostart_cmd) = &prof.autostart_command { let mut jobs = VecDeque::new(); - - if *IS_FLATPAK { - let mut args = vec![String::from("--host")]; - for (key, value) in &prof.environment { - args.push(format!("--env={}={}", key, value)); - } - args.push(String::from("sh")); - args.push(String::from("-c")); - args.push(autostart_cmd.clone()); - - jobs.push_back(WorkerJob::new_cmd( - Some(HashMap::new()), - "flatpak-spawn".into(), - Some(args), - )); - } else { - jobs.push_back(WorkerJob::new_cmd( - Some(prof.environment.clone()), - "sh".into(), - Some(vec!["-c".into(), autostart_cmd.clone()]), - )); - } + jobs.push_back(WorkerJob::new_cmd( + Some(prof.environment.clone()), + "sh".into(), + Some(vec!["-c".into(), autostart_cmd.clone()]), + Some(true) + )); let autostart_worker = JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(rows) => Msg::OnServiceLog(rows), JobWorkerOut::Exit(code) => Msg::OnAutostartExit(code), diff --git a/src/ui/install_wivrn_box.rs b/src/ui/install_wivrn_box.rs index cf63f7c..af5b08a 100644 --- a/src/ui/install_wivrn_box.rs +++ b/src/ui/install_wivrn_box.rs @@ -218,6 +218,7 @@ impl AsyncComponent for InstallWivrnBox { "adb", Some(&["install", "-r", "-g", apk_path.to_string_lossy().to_string().as_str()]), None, + None ) .await { diff --git a/src/ui/job_worker/internal_worker.rs b/src/ui/job_worker/internal_worker.rs index cf8ee5d..3b6e35b 100644 --- a/src/ui/job_worker/internal_worker.rs +++ b/src/ui/job_worker/internal_worker.rs @@ -3,12 +3,12 @@ use super::{ state::JobWorkerState, }; use crate::{ - is_flatpak::IS_FLATPAK, profile::{LighthouseDriver, Profile}, ui::SENDER_IO_ERR_MSG + profile::{LighthouseDriver, Profile}, ui::SENDER_IO_ERR_MSG, util::cmd_utils::make_command }; use nix::unistd::Pid; use relm4::{prelude::*, Worker}; use std::{ - collections::{HashMap, VecDeque}, io::{BufRead, BufReader}, mem, os::unix::process::ExitStatusExt, process::{Command, Stdio}, sync::{Arc, Mutex}, thread + collections::VecDeque, io::{BufRead, BufReader}, mem, os::unix::process::ExitStatusExt, process::Stdio, sync::{Arc, Mutex}, thread }; macro_rules! logger_thread { @@ -85,9 +85,7 @@ impl Worker for InternalJobWorker { match &mut job { WorkerJob::Cmd(data) => { let data = data.clone(); - if let Ok(mut cmd) = Command::new(data.command) - .args(data.args) - .envs(data.environment) + if let Ok(mut cmd) = make_command(data.command, Some(&data.args), Some(data.environment), Some(data.host_spawn)) .stdin(Stdio::piped()) .stderr(Stdio::piped()) .stdout(Stdio::piped()) @@ -210,21 +208,12 @@ impl InternalJobWorker { vec![], ), }; - let mut data = CmdWorkerData { + let data = CmdWorkerData { environment: env.clone(), command: command.clone(), args: args.clone(), + host_spawn: true, }; - if *IS_FLATPAK { - data.environment = HashMap::new(); - data.command = String::from("flatpak-spawn"); - data.args = vec![String::from("--host")]; - for (key, value) in env { - data.args.push(format!("--env={}={}", key, value)); - } - data.args.push(command); - data.args.extend(args); - } let mut jobs = VecDeque::new(); jobs.push_back(WorkerJob::Cmd(data)); Self::builder().detach_worker(JobWorkerInit { jobs, state }) diff --git a/src/ui/job_worker/job.rs b/src/ui/job_worker/job.rs index 69c8c1d..39bcc9d 100644 --- a/src/ui/job_worker/job.rs +++ b/src/ui/job_worker/job.rs @@ -7,6 +7,7 @@ pub struct CmdWorkerData { pub environment: HashMap, pub command: String, pub args: Vec, + pub host_spawn: bool, } #[derive(Debug, Clone)] @@ -38,11 +39,13 @@ impl WorkerJob { env: Option>, cmd: String, args: Option>, + host_spawn: Option ) -> Self { Self::Cmd(CmdWorkerData { environment: env.unwrap_or_default(), command: cmd, args: args.unwrap_or_default(), + host_spawn: host_spawn.unwrap_or_default(), }) } diff --git a/src/ui/steamvr_calibration_box.rs b/src/ui/steamvr_calibration_box.rs index ff08b83..cb3ac77 100644 --- a/src/ui/steamvr_calibration_box.rs +++ b/src/ui/steamvr_calibration_box.rs @@ -159,6 +159,7 @@ impl SimpleComponent for SteamVrCalibrationBox { Some(env.clone()), vrcmd.clone(), Some(vec!["--pollposes".into()]), + Some(false), )); JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(_) => Self::Input::NoOp, @@ -178,6 +179,7 @@ impl SimpleComponent for SteamVrCalibrationBox { Some(env), vrcmd, Some(vec!["--resetroomsetup".into()]), + Some(false), )); JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(_) => Self::Input::NoOp, diff --git a/src/ui/wivrn_wired_start_box.rs b/src/ui/wivrn_wired_start_box.rs index 76b11e4..8736e79 100644 --- a/src/ui/wivrn_wired_start_box.rs +++ b/src/ui/wivrn_wired_start_box.rs @@ -136,6 +136,7 @@ impl AsyncComponent for WivrnWiredStartBox { "adb shell am start -a android.intent.action.VIEW -d \"wivrn+tcp://127.0.0.1\" $PACKAGE" ) ]), + None, None ).await { Ok(out) if out.exit_code == 0 => diff --git a/src/util/cmd_utils.rs b/src/util/cmd_utils.rs new file mode 100644 index 0000000..f7372bb --- /dev/null +++ b/src/util/cmd_utils.rs @@ -0,0 +1,26 @@ +use std::{collections::HashMap, ffi::OsStr, process::Command}; + +use crate::is_flatpak::IS_FLATPAK; + +pub fn make_command, T: AsRef>( + cmd: S, + args: Option<&[T]>, + env: Option>, + host_spawn: Option, +) -> Command { + if *IS_FLATPAK && host_spawn.unwrap_or_default() { + let mut flatpak_env = vec![]; + for (key, value) in env.unwrap_or_default() { + flatpak_env.push(format!("--env={}={}", key, value)); + } + let mut command = Command::new("flatpak-spawn"); + command.arg("--host") + .args(flatpak_env) + .arg(cmd) + .args(args.unwrap_or_default()); + return command; + } + let mut command = Command::new(cmd); + command.args(args.unwrap_or_default()).envs(env.unwrap_or_default()); + command +} \ No newline at end of file diff --git a/src/util/file_utils.rs b/src/util/file_utils.rs index eb6dffd..6bbddd0 100644 --- a/src/util/file_utils.rs +++ b/src/util/file_utils.rs @@ -1,4 +1,4 @@ -use crate::{async_process::async_process, is_flatpak::IS_FLATPAK, profile::Profile}; +use crate::{async_process::async_process, profile::Profile}; use anyhow::bail; use nix::{ errno::Errno, @@ -81,15 +81,7 @@ pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec { } pub async fn setcap_cap_sys_nice_eip(profile: &Profile) { - let setcap_cmd = setcap_cap_sys_nice_eip_cmd(profile); - if *IS_FLATPAK { - let mut flatpak_cmd = vec!["--host".into(), "pkexec".into()]; - flatpak_cmd.extend(setcap_cmd); - if let Err(e) = async_process("flatpak-spawn", Some(&flatpak_cmd), None).await - { - eprintln!("Error: failed running setcap: {e}"); - } - } else if let Err(e) = async_process("pkexec", Some(&setcap_cmd), None).await + if let Err(e) = async_process("pkexec", Some(&setcap_cap_sys_nice_eip_cmd(profile)), None, Some(true)).await { eprintln!("Error: failed running setcap: {e}"); } diff --git a/src/util/mod.rs b/src/util/mod.rs index 10902df..7a9a5bf 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,4 @@ pub mod file_utils; pub mod hash; pub mod steamvr_utils; +pub mod cmd_utils; From 1de20502778080a764687aaab4d30780b31b4696 Mon Sep 17 00:00:00 2001 From: Charlie Le <20309750+CharlieQLe@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:06:37 -0500 Subject: [PATCH 3/5] Make host_spawn not an option --- src/async_process.rs | 4 ++-- src/build_tools/cmake.rs | 6 +++--- src/build_tools/git.rs | 4 ++-- src/builders/build_basalt.rs | 4 ++-- src/builders/build_mercury.rs | 2 +- src/builders/build_openhmd.rs | 6 +++--- src/ui/app.rs | 4 ++-- src/ui/install_wivrn_box.rs | 2 +- src/ui/job_worker/internal_worker.rs | 2 +- src/ui/job_worker/job.rs | 4 ++-- src/ui/steamvr_calibration_box.rs | 4 ++-- src/ui/wivrn_wired_start_box.rs | 2 +- src/util/cmd_utils.rs | 4 ++-- src/util/file_utils.rs | 2 +- 14 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/async_process.rs b/src/async_process.rs index 1f0ab4c..c3cfc76 100644 --- a/src/async_process.rs +++ b/src/async_process.rs @@ -14,10 +14,10 @@ pub async fn async_process, T: AsRef>( cmd: S, args: Option<&[T]>, env: Option>, - host_spawn: Option, + host_spawn: bool, ) -> anyhow::Result { let mut command: Command; - if *IS_FLATPAK && host_spawn.unwrap_or_default() { + if *IS_FLATPAK && host_spawn { let mut flatpak_env = vec![]; for (key, value) in env.unwrap_or_default() { flatpak_env.push(format!("--env={}={}", key, value)); diff --git a/src/build_tools/cmake.rs b/src/build_tools/cmake.rs index f2d3fc4..0465e7c 100644 --- a/src/build_tools/cmake.rs +++ b/src/build_tools/cmake.rs @@ -26,7 +26,7 @@ impl Cmake { } } args.push(self.source_dir.to_string_lossy().to_string()); - WorkerJob::new_cmd(self.env.clone(), "cmake".into(), Some(args), Some(false)) + WorkerJob::new_cmd(self.env.clone(), "cmake".into(), Some(args), false) } pub fn get_build_job(&self) -> WorkerJob { @@ -37,7 +37,7 @@ impl Cmake { "--build".into(), self.build_dir.to_string_lossy().to_string(), ]), - Some(false), + false, ) } @@ -49,7 +49,7 @@ impl Cmake { "--install".into(), self.build_dir.to_string_lossy().to_string(), ]), - Some(false), + false, ) } } diff --git a/src/build_tools/git.rs b/src/build_tools/git.rs index 923b25b..0f03a0e 100644 --- a/src/build_tools/git.rs +++ b/src/build_tools/git.rs @@ -13,7 +13,7 @@ impl Git { fn cmd(&self, args: Vec) -> WorkerJob { let mut nargs = vec!["-C".into(), self.dir.to_string_lossy().to_string()]; nargs.extend(args); - WorkerJob::new_cmd(None, "git".into(), Some(nargs), Some(false)) + WorkerJob::new_cmd(None, "git".into(), Some(nargs), false) } fn get_repo(&self) -> String { @@ -84,7 +84,7 @@ impl Git { self.dir.to_string_lossy().to_string(), "--recurse-submodules".into(), ]), - Some(false), + false, ) } diff --git a/src/builders/build_basalt.rs b/src/builders/build_basalt.rs index cc1bd2e..5b46235 100644 --- a/src/builders/build_basalt.rs +++ b/src/builders/build_basalt.rs @@ -79,7 +79,7 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque VecDeque VecDeque { profile.prefix.to_string_lossy().to_string(), get_cache_dir().to_string_lossy().to_string(), ]), - Some(false), + false, )); jobs diff --git a/src/builders/build_openhmd.rs b/src/builders/build_openhmd.rs index 3404bbd..fa802cb 100644 --- a/src/builders/build_openhmd.rs +++ b/src/builders/build_openhmd.rs @@ -62,7 +62,7 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque< .to_string_lossy() .to_string(), ]), - Some(false), + false, )); } // build job @@ -70,7 +70,7 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque< None, "ninja".into(), Some(vec!["-C".into(), build_dir.to_string_lossy().to_string()]), - Some(false), + false, )); // install job jobs.push_back(WorkerJob::new_cmd( @@ -81,7 +81,7 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque< build_dir.to_string_lossy().to_string(), "install".into(), ]), - Some(false), + false, )); jobs diff --git a/src/ui/app.rs b/src/ui/app.rs index d46a7ee..33ff27e 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -163,7 +163,7 @@ impl App { self.debug_view.sender().emit(DebugViewMsg::ClearLog); self.xr_devices = vec![]; if *IS_FLATPAK { - make_command(String::from("rm"), Some(&[prof.xrservice_type.ipc_file_path().to_str().unwrap()]), None, Some(true)) + make_command(String::from("rm"), Some(&[prof.xrservice_type.ipc_file_path().to_str().unwrap()]), None, true) .output() .expect("Failed to remove xrservice IPC file"); } else { @@ -215,7 +215,7 @@ impl App { Some(prof.environment.clone()), "sh".into(), Some(vec!["-c".into(), autostart_cmd.clone()]), - Some(true) + true )); let autostart_worker = JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(rows) => Msg::OnServiceLog(rows), diff --git a/src/ui/install_wivrn_box.rs b/src/ui/install_wivrn_box.rs index af5b08a..0b456c6 100644 --- a/src/ui/install_wivrn_box.rs +++ b/src/ui/install_wivrn_box.rs @@ -218,7 +218,7 @@ impl AsyncComponent for InstallWivrnBox { "adb", Some(&["install", "-r", "-g", apk_path.to_string_lossy().to_string().as_str()]), None, - None + false, ) .await { diff --git a/src/ui/job_worker/internal_worker.rs b/src/ui/job_worker/internal_worker.rs index 3b6e35b..2d4e7a4 100644 --- a/src/ui/job_worker/internal_worker.rs +++ b/src/ui/job_worker/internal_worker.rs @@ -85,7 +85,7 @@ impl Worker for InternalJobWorker { match &mut job { WorkerJob::Cmd(data) => { let data = data.clone(); - if let Ok(mut cmd) = make_command(data.command, Some(&data.args), Some(data.environment), Some(data.host_spawn)) + if let Ok(mut cmd) = make_command(data.command, Some(&data.args), Some(data.environment), data.host_spawn) .stdin(Stdio::piped()) .stderr(Stdio::piped()) .stdout(Stdio::piped()) diff --git a/src/ui/job_worker/job.rs b/src/ui/job_worker/job.rs index 39bcc9d..adde61c 100644 --- a/src/ui/job_worker/job.rs +++ b/src/ui/job_worker/job.rs @@ -39,13 +39,13 @@ impl WorkerJob { env: Option>, cmd: String, args: Option>, - host_spawn: Option + host_spawn: bool ) -> Self { Self::Cmd(CmdWorkerData { environment: env.unwrap_or_default(), command: cmd, args: args.unwrap_or_default(), - host_spawn: host_spawn.unwrap_or_default(), + host_spawn, }) } diff --git a/src/ui/steamvr_calibration_box.rs b/src/ui/steamvr_calibration_box.rs index cb3ac77..1ea8230 100644 --- a/src/ui/steamvr_calibration_box.rs +++ b/src/ui/steamvr_calibration_box.rs @@ -159,7 +159,7 @@ impl SimpleComponent for SteamVrCalibrationBox { Some(env.clone()), vrcmd.clone(), Some(vec!["--pollposes".into()]), - Some(false), + false, )); JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(_) => Self::Input::NoOp, @@ -179,7 +179,7 @@ impl SimpleComponent for SteamVrCalibrationBox { Some(env), vrcmd, Some(vec!["--resetroomsetup".into()]), - Some(false), + false, )); JobWorker::new(jobs, sender.input_sender(), |msg| match msg { JobWorkerOut::Log(_) => Self::Input::NoOp, diff --git a/src/ui/wivrn_wired_start_box.rs b/src/ui/wivrn_wired_start_box.rs index 8736e79..89b384d 100644 --- a/src/ui/wivrn_wired_start_box.rs +++ b/src/ui/wivrn_wired_start_box.rs @@ -137,7 +137,7 @@ impl AsyncComponent for WivrnWiredStartBox { ) ]), None, - None + false, ).await { Ok(out) if out.exit_code == 0 => StartClientStatus::Success diff --git a/src/util/cmd_utils.rs b/src/util/cmd_utils.rs index f7372bb..e09295b 100644 --- a/src/util/cmd_utils.rs +++ b/src/util/cmd_utils.rs @@ -6,9 +6,9 @@ pub fn make_command, T: AsRef>( cmd: S, args: Option<&[T]>, env: Option>, - host_spawn: Option, + host_spawn: bool, ) -> Command { - if *IS_FLATPAK && host_spawn.unwrap_or_default() { + if *IS_FLATPAK && host_spawn { let mut flatpak_env = vec![]; for (key, value) in env.unwrap_or_default() { flatpak_env.push(format!("--env={}={}", key, value)); diff --git a/src/util/file_utils.rs b/src/util/file_utils.rs index 6bbddd0..cf7731f 100644 --- a/src/util/file_utils.rs +++ b/src/util/file_utils.rs @@ -81,7 +81,7 @@ pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec { } pub async fn setcap_cap_sys_nice_eip(profile: &Profile) { - if let Err(e) = async_process("pkexec", Some(&setcap_cap_sys_nice_eip_cmd(profile)), None, Some(true)).await + if let Err(e) = async_process("pkexec", Some(&setcap_cap_sys_nice_eip_cmd(profile)), None, true).await { eprintln!("Error: failed running setcap: {e}"); } From 2886b20971a77d84cadc1f44b72e1373a7df9993 Mon Sep 17 00:00:00 2001 From: Charlie Le <20309750+CharlieQLe@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:26:14 -0500 Subject: [PATCH 4/5] Do not create a new Vec in async_process for flatpak env args --- src/async_process.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/async_process.rs b/src/async_process.rs index c3cfc76..53ab9f5 100644 --- a/src/async_process.rs +++ b/src/async_process.rs @@ -18,15 +18,12 @@ pub async fn async_process, T: AsRef>( ) -> anyhow::Result { let mut command: Command; if *IS_FLATPAK && host_spawn { - let mut flatpak_env = vec![]; - for (key, value) in env.unwrap_or_default() { - flatpak_env.push(format!("--env={}={}", key, value)); - } command = Command::new("flatpak-spawn"); - command.arg("--host") - .args(flatpak_env) - .arg(cmd) - .args(args.unwrap_or_default()); + command.arg("--host"); + for (key, value) in env.unwrap_or_default() { + command.arg(format!("--env={}={}", key, value)); + } + command.arg(cmd).args(args.unwrap_or_default()); } else { command = Command::new(cmd); command.args(args.unwrap_or_default()).envs(env.unwrap_or_default()); From 1e6ed8fb2159c8b89a68d6fdeb7da83a6c10a154 Mon Sep 17 00:00:00 2001 From: Charlie Le <20309750+CharlieQLe@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:26:54 -0500 Subject: [PATCH 5/5] Use extension trait for making a Command that runs unsandboxed --- src/ui/app.rs | 7 ++--- src/ui/job_worker/internal_worker.rs | 14 +++++++--- src/util/cmd_utils.rs | 38 +++++++++++++--------------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/ui/app.rs b/src/ui/app.rs index 33ff27e..fb417a4 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -34,7 +34,7 @@ use crate::{ }, }, is_flatpak::IS_FLATPAK, linux_distro::LinuxDistro, openxr_prober::is_openxr_ready, paths::get_data_dir, profile::{Profile, XRServiceType}, stateless_action, steam_linux_runtime_injector::{ restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile, - }, util::{cmd_utils::make_command, file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd}}, vulkaninfo::VulkanInfo, xr_devices::XRDevice + }, util::{cmd_utils::CommandUnsandbox, file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd}}, vulkaninfo::VulkanInfo, xr_devices::XRDevice }; use adw::{prelude::*, ResponseAppearance}; use gtk::glib::{self, clone}; @@ -43,7 +43,7 @@ use relm4::{ new_action_group, new_stateful_action, new_stateless_action, prelude::*, }; -use std::{collections::VecDeque, fs::remove_file, time::Duration}; +use std::{collections::VecDeque, fs::remove_file, process::Command, time::Duration}; pub struct App { application: adw::Application, @@ -163,7 +163,8 @@ impl App { self.debug_view.sender().emit(DebugViewMsg::ClearLog); self.xr_devices = vec![]; if *IS_FLATPAK { - make_command(String::from("rm"), Some(&[prof.xrservice_type.ipc_file_path().to_str().unwrap()]), None, true) + Command::new_unsandboxed("rm", None) + .arg(prof.xrservice_type.ipc_file_path().to_str().unwrap()) .output() .expect("Failed to remove xrservice IPC file"); } else { diff --git a/src/ui/job_worker/internal_worker.rs b/src/ui/job_worker/internal_worker.rs index 2d4e7a4..38d8b18 100644 --- a/src/ui/job_worker/internal_worker.rs +++ b/src/ui/job_worker/internal_worker.rs @@ -3,12 +3,12 @@ use super::{ state::JobWorkerState, }; use crate::{ - profile::{LighthouseDriver, Profile}, ui::SENDER_IO_ERR_MSG, util::cmd_utils::make_command + profile::{LighthouseDriver, Profile}, ui::SENDER_IO_ERR_MSG, util::cmd_utils::CommandUnsandbox }; use nix::unistd::Pid; use relm4::{prelude::*, Worker}; use std::{ - collections::VecDeque, io::{BufRead, BufReader}, mem, os::unix::process::ExitStatusExt, process::Stdio, sync::{Arc, Mutex}, thread + collections::VecDeque, io::{BufRead, BufReader}, mem, os::unix::process::ExitStatusExt, process::{Command, Stdio}, sync::{Arc, Mutex}, thread }; macro_rules! logger_thread { @@ -85,7 +85,15 @@ impl Worker for InternalJobWorker { match &mut job { WorkerJob::Cmd(data) => { let data = data.clone(); - if let Ok(mut cmd) = make_command(data.command, Some(&data.args), Some(data.environment), data.host_spawn) + let mut cmd: Command; + if data.host_spawn { + cmd = Command::new_unsandboxed(&data.command, Some(data.environment)) + } else { + cmd = Command::new(&data.command); + cmd.envs(data.environment); + } + if let Ok(mut cmd) = cmd + .args(data.args) .stdin(Stdio::piped()) .stderr(Stdio::piped()) .stdout(Stdio::piped()) diff --git a/src/util/cmd_utils.rs b/src/util/cmd_utils.rs index e09295b..7296474 100644 --- a/src/util/cmd_utils.rs +++ b/src/util/cmd_utils.rs @@ -1,26 +1,24 @@ -use std::{collections::HashMap, ffi::OsStr, process::Command}; +use std::{collections::HashMap, process::Command}; use crate::is_flatpak::IS_FLATPAK; -pub fn make_command, T: AsRef>( - cmd: S, - args: Option<&[T]>, - env: Option>, - host_spawn: bool, -) -> Command { - if *IS_FLATPAK && host_spawn { - let mut flatpak_env = vec![]; - for (key, value) in env.unwrap_or_default() { - flatpak_env.push(format!("--env={}={}", key, value)); +pub trait CommandUnsandbox { + fn new_unsandboxed(program: &str, envs: Option>) -> Self; +} + +impl CommandUnsandbox for Command { + fn new_unsandboxed(program: &str, envs: Option>) -> Self { + if *IS_FLATPAK { + let mut cmd = Command::new("flatpak-spawn"); + cmd.arg("--host"); + for (key, value) in envs.unwrap_or_default() { + cmd.arg(format!("--env={}={}", key, value)); + } + cmd.arg(program); + return cmd; } - let mut command = Command::new("flatpak-spawn"); - command.arg("--host") - .args(flatpak_env) - .arg(cmd) - .args(args.unwrap_or_default()); - return command; + let mut cmd = Command::new(program); + cmd.envs(envs.unwrap_or_default()); + cmd } - let mut command = Command::new(cmd); - command.args(args.unwrap_or_default()).envs(env.unwrap_or_default()); - command } \ No newline at end of file