Skip to content

Commit 7365702

Browse files
authored
github/dev -> github/master
* Update icon * Make runner and prefix paths optional * Update version * Split sandbox constants and helper methods * Move constants * Split binary check to allow further improvements * Update README.md * Update description
2 parents 10a9dae + 5b89bb0 commit 7365702

File tree

10 files changed

+98
-80
lines changed

10 files changed

+98
-80
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "raptor-cage"
3-
version = "1.0.2"
3+
version = "1.0.3"
44
edition = "2021"
55
license = "CIL-1.0"
66

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<div align="center">
2+
<img src="assets/icon.png" />
23
<h1>
34
raptor-cage
45
</h1>
@@ -44,7 +45,7 @@ sudo install -Dm755 raptor-cage "/usr/local/bin/rcage"
4445
rcage run -r soda-9.0-1 -p my_prefix -d ~/games/some_game -b game.exe
4546

4647
# Run native binary, and pass custom parameters.
47-
rcage run -r soda-9.0-1 -p my_prefix -d ~/games/some_game -b native_binary -- --param1
48+
rcage run -d ~/games/some_game -b native_binary -- --param1
4849

4950
# Mount game path as read-write, mount installer path as read-only, then start interactive shell.
5051
rcage run -r soda-9.0-1 -p my_prefix -d ~/games/some_game:rw -v ~/installers:/installers:
@@ -114,7 +115,7 @@ cargo upgrade --dry-run
114115
* Native wayland support, see https://www.phoronix.com/news/Wine-9.22-Released and https://wiki.archlinux.org/title/Wine#Wayland. Also consider bringing back `--unshare-ipc` if using Wayland prevents the issue described in bwrap.rs#90.
115116
* Add `kill` sub-command to terminate all processes in a sandbox, need to connect to existing bwrap container.
116117
* When using the `integrate` sub-command to create a `.desktop` shortcut, extract executable icon and set it respectively. It can be done with a small windows executable calling a win32 API call or natively on Linux by using `wrestool`.
117-
* Add NTSYNC support, see also https://www.phoronix.com/news/Linux-6.14-NTSYNC-Driver-Ready.
118+
* Add NTSYNC support, see also https://www.phoronix.com/news/Linux-6.14-Char-Misc-NTSYNC.
118119

119120
#### Packaging
120121

assets/icon.png

6.37 KB
Loading

src/cli.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ pub enum Commands {
4444
sync_mode: SyncMode,
4545
/// Path of the Wine runner.
4646
#[arg(short, long = "runner", value_name = "PATH")]
47-
runner_path: PathBuf,
47+
runner_path: Option<PathBuf>,
4848
/// Path of the Wine prefix.
4949
#[arg(short, long = "prefix", value_name = "PATH")]
50-
prefix_path: PathBuf,
50+
prefix_path: Option<PathBuf>,
5151
/// Path that contains the application files.
5252
#[arg(short = 'd', long = "appdir", value_name = "PATH")]
5353
app_dir: Option<String>,
@@ -65,7 +65,7 @@ pub enum Commands {
6565
}
6666

6767
#[derive(Debug, Parser)]
68-
#[command(about = "Run and manage games inside of a sandbox", long_about = None)]
68+
#[command(about = "Run games in a secure sandbox", long_about = None)]
6969
pub struct Cli {
7070
#[command(subcommand)]
7171
pub command: Commands,

src/invoker.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@ pub fn run(
2727
verbose: bool,
2828
upscale_mode: UpscaleMode,
2929
sync_mode: SyncMode,
30-
runner_path: PathBuf,
31-
prefix_path: PathBuf,
30+
runner_path: Option<PathBuf>,
31+
prefix_path: Option<PathBuf>,
3232
app_dir: Option<String>,
3333
app_bin: Option<String>,
3434
app_args: Option<Vec<String>>,
3535
) -> anyhow::Result<()> {
36+
if runner_path.as_ref().xor(prefix_path.as_ref()).is_some() {
37+
anyhow::bail!("either both runner and prefix paths are required, or neither");
38+
}
3639
let sandbox_config = SandboxConfig {
3740
namespace_isolation: !no_namespace_isolation,
3841
user_mapping,

src/sandbox/bwrap.rs

Lines changed: 21 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,16 @@ use super::mount::MountMapping;
33
use super::sandbox::{
44
DeviceAccess, LaunchConfig, LaunchParams, NetworkMode, RuntimeEnv, SandboxConfig,
55
};
6+
use super::sandbox_config::{
7+
current_timestamp_hex, find_nvidia_devices, INNER_APP_DIR, INNER_WINE_PREFIX, INNER_WINE_ROOT,
8+
};
69
use super::wine::{SyncMode, UpscaleMode};
710
use anyhow::Context;
811
use std::env;
912
use std::path::PathBuf;
10-
use std::time::{SystemTime, UNIX_EPOCH};
11-
use std::{
12-
fs,
13-
os::unix::fs::FileTypeExt,
14-
process::{Command, Stdio},
15-
};
13+
use std::process::{Command, Stdio};
1614
use tempfile::NamedTempFile;
1715

18-
fn current_timestamp_hex() -> String {
19-
let start = SystemTime::now();
20-
let since_epoch = start.duration_since(UNIX_EPOCH).unwrap();
21-
let seconds = since_epoch.as_secs();
22-
format!("{:x}", seconds)
23-
}
24-
25-
fn find_nvidia_devices() -> anyhow::Result<Vec<String>> {
26-
let mut nvidia_devices = Vec::new();
27-
let entries = fs::read_dir("/dev")?;
28-
for entry in entries.flatten() {
29-
let path = entry.path();
30-
let metadata = path.metadata()?;
31-
if metadata.file_type().is_char_device() {
32-
let file_name = path
33-
.file_name()
34-
.unwrap_or_default()
35-
.to_str()
36-
.unwrap_or_default();
37-
if file_name.starts_with("nvidia") {
38-
if let Some(path_str) = path.to_str() {
39-
nvidia_devices.push(path_str.to_string());
40-
}
41-
}
42-
}
43-
}
44-
Ok(nvidia_devices)
45-
}
46-
4716
/// Gets the corresponding bwrap parameters for the selected DeviceAccess option.
4817
pub fn get_device_args(device_access: &DeviceAccess) -> anyhow::Result<Vec<String>> {
4918
match device_access {
@@ -84,10 +53,6 @@ fn get_mount_args(mount_mappings: &[MountMapping]) -> Vec<String> {
8453
args
8554
}
8655

87-
const INNER_WINE_ROOT: &str = "/opt/wine";
88-
const INNER_WINE_PREFIX: &str = "/var/lib/wine";
89-
const INNER_APP_DIR: &str = "/app";
90-
9156
fn build_args(
9257
sandbox_config: &SandboxConfig,
9358
launch_config: &LaunchConfig,
@@ -209,26 +174,24 @@ fn build_args(
209174
// Mount the directory that contains the Wine binaries and libraries (a.k.a. runner), the Wine
210175
// version to be mounted must be statically compiled in order to not rely on any host library
211176
// i.e. the runners downloaded by Bottles are statically compiled.
212-
args.extend([
213-
"--tmpfs",
214-
"/opt",
215-
"--ro-bind",
216-
launch_config
217-
.runner_path
218-
.to_str()
219-
.context("bad runner path")?,
220-
INNER_WINE_ROOT,
221-
]);
177+
if let Some(runner_path) = &launch_config.runner_path {
178+
args.extend([
179+
"--tmpfs",
180+
"/opt",
181+
"--ro-bind",
182+
runner_path.to_str().context("bad runner path")?,
183+
INNER_WINE_ROOT,
184+
]);
185+
}
222186
// Prefix needs to be read-write because some dependencies may be installed or system files change
223187
// while wine is running, even changing the registry requires write access.
224-
args.extend([
225-
"--bind",
226-
launch_config
227-
.prefix_path
228-
.to_str()
229-
.context("bad prefix path")?,
230-
INNER_WINE_PREFIX,
231-
]);
188+
if let Some(prefix_path) = &launch_config.prefix_path {
189+
args.extend([
190+
"--bind",
191+
prefix_path.to_str().context("bad prefix path")?,
192+
INNER_WINE_PREFIX,
193+
]);
194+
}
232195
// Mount X11 socket to allow running GUI apps. Using the same X11 display number as the host
233196
// because using a different number will not work despite being the first recommendation in the
234197
// ArchWiki: https://wiki.archlinux.org/title/Bubblewrap#Using_X11.
@@ -402,7 +365,7 @@ fn build_args(
402365
let bin_path = bin_buf
403366
.to_str()
404367
.with_context(|| format!("invalid path: {}", bin_buf.to_string_lossy()))?;
405-
if bin_path.ends_with(".exe") {
368+
if launch_config.launch_params.is_windows_binary() {
406369
final_args.push("wine".into());
407370
}
408371
final_args.push(bin_path.into());

src/sandbox/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ pub mod bwrap;
33
mod display;
44
pub mod mount;
55
pub mod sandbox;
6+
mod sandbox_config;
67
pub mod user_mapping;
78
pub mod wine;

src/sandbox/sandbox.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,24 @@ impl LaunchParams {
142142
app_args: app_args.unwrap_or(vec![]),
143143
}
144144
}
145+
146+
pub fn is_windows_binary(&self) -> bool {
147+
match self {
148+
LaunchParams::Configured {
149+
app_bin: Some(app_bin),
150+
..
151+
} => app_bin.ends_with(".exe"),
152+
_ => false,
153+
}
154+
}
145155
}
146156

147157
// TODO: detect GPUs and configure environment to use the dedicated GPU, currently bottles uses
148158
// lspci and grep, however it does not seem to work in many scenarios. See
149159
// https://github.com/bottlesdevs/Bottles/blob/540f6fc0d4c2853e2a62cab98548ce3210c7352a/bottles/backend/utils/gpu.py.
150160
pub struct LaunchConfig {
151-
pub runner_path: PathBuf,
152-
pub prefix_path: PathBuf,
161+
pub runner_path: Option<PathBuf>,
162+
pub prefix_path: Option<PathBuf>,
153163
/// Application to execute inside the sandbox, if not set, a shell will be started instead.
154164
pub launch_params: LaunchParams,
155165
/// Optional upscale mode (needs to be supported by the runner).
@@ -160,23 +170,25 @@ pub struct LaunchConfig {
160170

161171
impl LaunchConfig {
162172
pub fn new(
163-
runner_path: PathBuf,
164-
prefix_path: PathBuf,
173+
runner_path: Option<PathBuf>,
174+
prefix_path: Option<PathBuf>,
165175
launch_params: Option<LaunchParams>,
166176
upscale_mode: Option<UpscaleMode>,
167177
sync_mode: Option<SyncMode>,
168178
) -> anyhow::Result<Self> {
169-
let data_root = bottles::get_data_root()?;
170-
let runner_path = if runner_path.is_absolute() {
171-
runner_path
172-
} else {
173-
data_root.join("runners").join(runner_path)
174-
};
175-
let prefix_path = if prefix_path.is_absolute() {
176-
prefix_path
179+
let data_root: Option<PathBuf> = if runner_path.is_some() || prefix_path.is_some() {
180+
Some(bottles::get_data_root()?)
177181
} else {
178-
data_root.join("bottles").join(prefix_path)
182+
None
179183
};
184+
let runner_path = runner_path.map(|path| match &data_root {
185+
Some(data_root) if !path.is_absolute() => data_root.join("runners").join(path),
186+
_ => path,
187+
});
188+
let prefix_path = prefix_path.map(|path| match &data_root {
189+
Some(data_root) if !path.is_absolute() => data_root.join("bottles").join(path),
190+
_ => path,
191+
});
180192
Ok(LaunchConfig {
181193
runner_path,
182194
prefix_path,

src/sandbox/sandbox_config.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::{
2+
fs,
3+
os::unix::fs::FileTypeExt,
4+
time::{SystemTime, UNIX_EPOCH},
5+
};
6+
7+
pub const INNER_WINE_ROOT: &str = "/opt/wine";
8+
pub const INNER_WINE_PREFIX: &str = "/var/lib/wine";
9+
pub const INNER_APP_DIR: &str = "/app";
10+
11+
pub fn current_timestamp_hex() -> String {
12+
let start = SystemTime::now();
13+
let since_epoch = start.duration_since(UNIX_EPOCH).unwrap();
14+
let seconds = since_epoch.as_secs();
15+
format!("{:x}", seconds)
16+
}
17+
18+
pub fn find_nvidia_devices() -> anyhow::Result<Vec<String>> {
19+
let mut nvidia_devices = Vec::new();
20+
let entries = fs::read_dir("/dev")?;
21+
for entry in entries.flatten() {
22+
let path = entry.path();
23+
let metadata = path.metadata()?;
24+
if metadata.file_type().is_char_device() {
25+
let file_name = path
26+
.file_name()
27+
.unwrap_or_default()
28+
.to_str()
29+
.unwrap_or_default();
30+
if file_name.starts_with("nvidia") {
31+
if let Some(path_str) = path.to_str() {
32+
nvidia_devices.push(path_str.to_string());
33+
}
34+
}
35+
}
36+
}
37+
Ok(nvidia_devices)
38+
}

0 commit comments

Comments
 (0)