Skip to content

Commit 8235787

Browse files
committed
fix(run): explicit config path needed when executing as root with rootless configure
1 parent 522ab52 commit 8235787

8 files changed

Lines changed: 52 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- New TUI interface for improved user experience and understanding.
1212
- `tweak` command is now accessible via the `configure` command.
1313
- Better balance between configuration search time and exhaustiveness.
14+
- Full rootless capabilities.
1415

1516
### Added
1617
- More debug commands to help users to report issues: `--config`, `--log`, `--grey-devices`.

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Thank you for considering contributing to our project! We appreciate your intere
33

44
## Packaging Guidelines
55
When building a package for distribution, please ensure the following:
6-
1. You modified the configuration and log file paths in [.cargo/config.toml](.cargo/config.toml) to match the packaging standards of the target distribution.
6+
1. You can modify the configuration and log file paths in [.cargo/config.toml](.cargo/config.toml) to match the packaging standards of the target distribution. Note that the defaults allow rootless utilization.
77
2. The only external *compile time* dependency needed are
88
* `gcc`
99
* `libclang`

Cargo.lock

Lines changed: 3 additions & 3 deletions
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 = "linux-enable-ir-emitter"
3-
version = "7.0.0-beta1"
3+
version = "7.0.0-beta2"
44
edition = "2024"
55
authors = ["Maxime Dirksen (EmixamPP)"]
66
license = "MIT"

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ Provides support for infrared cameras that are not directly enabled out-of-the b
1111
> If you plan to package this software for a Linux distribution, or to contribute code, please read [CONTRIBUTING.md](CONTRIBUTING.md).
1212
1313
## Installation
14-
Download the latest [linux-enable-ir-emitter-x.x.x-release-x86-64.tar.gz](https://github.com/EmixamPP/linux-enable-ir-emitter/releases). Then execute:
14+
Download the latest asset [linux-enable-ir-emitter-x.x.x-release-x86-64.tar.gz](https://github.com/EmixamPP/linux-enable-ir-emitter/releases). Then execute:
1515
> [!NOTE]
1616
> Please try the 7.0.0-beta! Furthermore, this README has been updated for this version.
1717
1818
```
1919
tar -C $HOME/.local/bin --no-same-owner -m -vxzf linux-enable-ir-emitter*.tar.gz
2020
```
21-
If not already done, add `$HOME/.local/bin` to your PATH, e.g.:
21+
If not already done, add `$HOME/.local/bin` to your `$PATH`, e.g.:
2222
```
2323
echo 'export PATH=$HOME/.local/bin:$PATH' >> $HOME/.bashrc && source $HOME/.bashrc
2424
```
@@ -31,16 +31,20 @@ The installation consists of 3 files:
3131
### Integration with Howdy
3232
In all files returned by `grep -rl howdy /etc/pam.d`, add the following line before the one mentioning "howdy", replacing `<USER>` with your actual username:
3333
```
34-
auth optional pam_exec.so /home/<USER>/.local/bin/linux-enable-ir-emitter run
34+
auth optional pam_exec.so /home/<USER>/.local/bin/linux-enable-ir-emitter run --config /home/<USER>/.config/linux-enable-ir-emitter.toml
3535
```
3636

37-
The path to the binary may vary depending on your installation method. You can determine the correct absolute path by running `which linux-enable-ir-emitter` and use that path instead.
37+
> [!TIP]
38+
> The installation paths may vary depending on your installation method. You can determine the correct binary absolute paths by running `which linux-enable-ir-emitter` and use that path instead. For the configuration path, it will be written when you can execute `linux-enable-ir-emitter --config`.
3839
3940
### Integration with other program
4041
You will need to execute the `linux-enable-ir-emitter run` command before the program that uses the infrared camera.
4142

4243
Alternatively, if you can and/or want to integrate better with the program that uses the camera, you can pass an opened file descriptor for the camera to the command: `linux-enable-ir-emitter run --device <DEVICE> --fd <FD>`.
4344

45+
> [!Important]
46+
> You will need to pass the config path as argument to `linux-enable-ir-emitter run --config <CONFIG_PATH>` **when executed as root** if `linux-enable-ir-emitter configure` was executed as a normal user.
47+
4448
## How do I enable my infrared emitter?
4549
0. For a better experience, use a large terminal window.
4650
1. Execute the command: `linux-enable-ir-emitter configure`

src/configuration.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::video::uvc::XuControl;
22

33
use std::collections::{BTreeMap as Map, BTreeSet as Set};
4-
use std::path::Path;
4+
use std::path::{Path, PathBuf};
55

66
use anyhow::{Context, Result, anyhow};
77
use derive_more::AsRef;
@@ -13,23 +13,23 @@ static _CONFIG: &str = env!("CONFIG");
1313
#[cfg(test)]
1414
pub const _CONFIG: &str = "target/tmp/linux-enable-ir-emitter.toml";
1515

16-
fn config_file_path() -> Result<String> {
16+
fn config_file_path() -> Result<PathBuf> {
1717
Ok(shellexpand::env(_CONFIG)
1818
.context("failed to expend shell variable in log file path")?
19-
.to_string())
19+
.to_string()
20+
.into())
2021
}
2122

2223
pub fn print_config() -> Result<()> {
2324
let config_file = config_file_path()?;
2425
let content_str =
2526
std::fs::read_to_string(&config_file).context("failed to read configuration file")?;
26-
print!("# {}\n\n{}", config_file, content_str);
27+
print!("# {}\n\n{}", config_file.display(), content_str);
2728
Ok(())
2829
}
2930

3031
mod path {
3132
use super::*;
32-
use std::path::PathBuf;
3333

3434
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, AsRef)]
3535
pub struct V4LPath(PathBuf);
@@ -118,18 +118,25 @@ impl Configurations {
118118
let config_str =
119119
toml::to_string(&self.devices).context("failed to serialize configuration")?;
120120
let config_file = config_file_path()?;
121-
log::debug!("Saving configuration at {}:\n{}", config_file, config_str);
121+
log::debug!(
122+
"Saving configuration at {}:\n{}",
123+
config_file.display(),
124+
config_str
125+
);
122126
std::fs::write(config_file, config_str).context("failed to write configuration file")
123127
}
124128

125-
/// Load an existing configurations or create an empty one.
129+
/// Load an existing configurations at the default location or create an empty one.
126130
pub fn load() -> Result<Self> {
127-
Ok(match std::fs::read_to_string(config_file_path()?) {
128-
Ok(config_str) => Self {
129-
devices: toml::from_str(&config_str)
130-
.context("failed to parse configuration file")?,
131-
},
132-
Err(_) => Self::default(),
131+
Ok(Self::load_from(&config_file_path()?).unwrap_or_default())
132+
}
133+
134+
/// Load an existing configurations at a specified path.
135+
pub fn load_from(config: &Path) -> Result<Self> {
136+
log::info!("Loading configuration from {}.", config.display());
137+
let config_str = std::fs::read_to_string(config)?;
138+
Ok(Self {
139+
devices: toml::from_str(&config_str).context("failed to parse configuration file")?,
133140
})
134141
}
135142

@@ -140,9 +147,8 @@ impl Configurations {
140147
/// Initializes an existing configuration if it does not exist.
141148
fn initialize_config_dir() -> Result<()> {
142149
let config_file = config_file_path()?;
143-
log::debug!("Configuration located at: {}", config_file);
144-
let config_dir = Path::new(&config_file).parent();
145-
if let Some(config_dir) = config_dir {
150+
log::debug!("Configuration located at: {}", config_file.display());
151+
if let Some(config_dir) = config_file.parent() {
146152
std::fs::create_dir_all(config_dir).context("failed to create configuration directory")
147153
} else {
148154
Ok(())

src/main.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ async fn main() -> Result<()> {
2929
log::debug!("Version {}.", env!("CARGO_PKG_VERSION"));
3030
configure::configure().await
3131
}
32-
Some(Commands::Run { device, fd }) => {
32+
Some(Commands::Run { device, fd, config }) => {
3333
logger::init_term()?;
34-
run::run(device.as_deref(), fd)
34+
run::run(device.as_deref(), fd, config.as_deref())
3535
}
3636
None => Ok(()),
3737
}
@@ -76,5 +76,12 @@ enum Commands {
7676
requires = "device"
7777
)]
7878
fd: Option<i32>,
79+
#[arg(
80+
short,
81+
long,
82+
help = "Specify the configuration file to use. Default: use the default configuration path.",
83+
default_value = None,
84+
)]
85+
config: Option<std::path::PathBuf>,
7986
},
8087
}

src/run.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ use std::path::Path;
1010
///
1111
/// Does not return an error if no configuration exists for the device.
1212
///
13-
pub fn run(device: Option<&Path>, fd: Option<i32>) -> Result<()> {
13+
pub fn run(device: Option<&Path>, fd: Option<i32>, config: Option<&Path>) -> Result<()> {
1414
if fd.is_some() && device.is_none() {
1515
bail!("if a file descriptor is provided, a device path must also be provided");
1616
}
1717

18-
let config = Configurations::load()?;
18+
let config = if let Some(config) = config {
19+
Configurations::load_from(config)?
20+
} else {
21+
Configurations::load()?
22+
};
23+
1924
for (path, conf) in config.devices() {
2025
if let Some(d) = device
2126
&& d != path.as_ref()

0 commit comments

Comments
 (0)