Skip to content

Commit cd38a41

Browse files
committed
Add ability to set user/group/mode on exported sysfs gpio entries
In systems where gpio-utils is being used to export entries, it is useful to be able to setup permissions in this same system. Signed-off-by: Paul Osborne <[email protected]>
1 parent c105292 commit cd38a41

File tree

8 files changed

+291
-383
lines changed

8 files changed

+291
-383
lines changed

Cargo.lock

Lines changed: 210 additions & 363 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[package]
22
name = "gpio-utils"
3-
version = "0.1.2"
3+
version = "0.2.0"
44
authors = ["Paul Osborne <[email protected]>"]
55
license = "MIT/Apache-2.0"
66
readme = "README.md"
77
homepage = "https://github.com/rust-embedded/gpio-utils"
8-
keywords = ["gpio", "linux", "sysfs_gpoi", "cli", "command-line"]
8+
keywords = ["gpio", "linux", "sysfs_gpio", "cli", "command-line"]
99
description = """
1010
Command-line utilities for interacting with GPIOs under Linux
1111
@@ -15,21 +15,16 @@ Rust applications or any other applications.
1515

1616
[dependencies]
1717
clap = "2.2"
18+
error-chain = "0.12"
1819
sysfs_gpio = "0.5.2"
1920
toml = "0.4"
2021
glob = "0.2"
21-
log = "0.3"
22-
env_logger = "0.3"
22+
log = "0.4"
23+
env_logger = "0.5"
24+
nix = "0.11"
2325
serde_derive = "1.0"
2426
serde = "1.0"
25-
26-
[dependencies.clippy]
27-
version = "0.0"
28-
optional = true
29-
30-
[features]
31-
default = []
32-
lints = ["clippy"]
27+
users = "0.8"
3328

3429
[[bin]]
3530
name = "gpio"

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ cargo install gpio-utils
2929
- [x] Ability to get/set gpio values by pin number or name (including temporary
3030
export if necessary)
3131
- [x] Ability to block awaiting pin state change (with timeout)
32+
- [x] Ability to set exported GPIO permissions
3233

3334
## System Integration
3435

@@ -66,14 +67,19 @@ how you can configure your GPIOs.
6667
# be reversed.
6768
# - `export`: Default: `true`. If true, this GPIO will be automatically
6869
# exported when `gpio export-all` is run (e.g. by an init script).
69-
#
70+
# - `user`: User that should own the exported GPIO
71+
# - `group`: Group that should own the exported GPIO
72+
# - `mode`: Mode for exported directory
7073

7174
[[pins]]
7275
num = 73 # required
7376
names = ["reset_button"] # required (may have multiple)
7477
direction = "in" # default: in
7578
active_low = false # default: false (really means invert logic)
7679
export = true # default: true
80+
user = "root" # default: (OS Default - root)
81+
group = "gpio" # default: (OS Default - root)
82+
mode = 0o664 # default: (OS Default - 0o644)
7783

7884
[[pins]]
7985
num = 37

src/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ pub struct PinConfig {
5353
pub export: bool,
5454
#[serde(default)]
5555
pub active_low: bool,
56+
pub user: Option<String>,
57+
pub group: Option<String>,
58+
pub mode: Option<u32>,
5659
}
5760

5861
fn default_direction()-> sysfs_gpio::Direction {

src/error.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) 2018, The gpio-utils Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
use sysfs_gpio::Error as GpioError;
10+
use nix::Error as NixError;
11+
use std::io::Error as IoError;
12+
13+
error_chain! {
14+
types {
15+
Error, ErrorKind, ResultExt, Result;
16+
}
17+
18+
foreign_links {
19+
Gpio(GpioError);
20+
Nix(NixError);
21+
Io(IoError);
22+
}
23+
}

src/export.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88

99
use std::path;
1010
use std::os::unix::fs as unix_fs;
11+
use std::os::unix::fs::PermissionsExt;
1112
use std::fs;
1213
use std::io::ErrorKind;
1314
use config::PinConfig;
15+
use nix::unistd::{chown, Gid, Uid};
1416
use sysfs_gpio;
17+
use users::{get_user_by_name, get_group_by_name};
18+
use error::*;
1519

1620
/// Unexport the pin specified in the provided config
1721
///
@@ -26,7 +30,7 @@ use sysfs_gpio;
2630
/// without an error as the desired end state is achieved.
2731
pub fn unexport(pin_config: &PinConfig,
2832
symlink_root: Option<&str>)
29-
-> Result<(), sysfs_gpio::Error> {
33+
-> Result<()> {
3034
if let Some(symroot) = symlink_root {
3135
// create symlink for each name
3236
for name in &pin_config.names {
@@ -48,7 +52,7 @@ pub fn unexport(pin_config: &PinConfig,
4852
match pin.unexport() {
4953
Ok(_) => Ok(()),
5054
Err(sysfs_gpio::Error::Io(ref e)) if e.kind() == ErrorKind::InvalidInput => Ok(()),
51-
Err(e) => Err(e)
55+
Err(e) => Err(e.into())
5256
}
5357
}
5458

@@ -63,10 +67,34 @@ pub fn unexport(pin_config: &PinConfig,
6367
///
6468
/// If the GPIO is already exported, this function will continue
6569
/// without an error as the desired end state is achieved.
66-
pub fn export(pin_config: &PinConfig, symlink_root: Option<&str>) -> Result<(), sysfs_gpio::Error> {
70+
pub fn export(pin_config: &PinConfig, symlink_root: Option<&str>) -> Result<()> {
6771
let pin = pin_config.get_pin();
6872
try!(pin.export());
6973

74+
// change user, group, mode for files in gpio directory
75+
for entry in fs::read_dir(format!("/sys/class/gpio/gpio{}", &pin_config.num))? {
76+
let e = entry?;
77+
let metadata = e.metadata()?;
78+
79+
let user = pin_config.user.as_ref().and_then(|username| get_user_by_name(username));
80+
let group = pin_config.group.as_ref().and_then(|groupname| get_group_by_name(groupname));
81+
82+
if metadata.is_file() {
83+
if user.is_some() && group.is_some() {
84+
chown(e.path().as_path(),
85+
user.as_ref().map(|u| Uid::from_raw(u.uid())),
86+
group.as_ref().map(|g| Gid::from_raw(g.gid())))?;
87+
}
88+
89+
if let Some(mode) = pin_config.mode {
90+
let mut permissions = metadata.permissions();
91+
permissions.set_mode(mode);
92+
fs::set_permissions(e.path().as_path(), permissions)?;
93+
}
94+
}
95+
}
96+
97+
7098
// if there is a symlink root provided, create symlink
7199
if let Some(symroot) = symlink_root {
72100
// create root directory if not exists

src/lib.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
extern crate sysfs_gpio;
10-
extern crate toml;
9+
#[macro_use]
10+
extern crate error_chain;
1111
extern crate glob;
1212
extern crate log;
13+
extern crate nix;
1314
extern crate serde;
14-
#[macro_use] extern crate serde_derive;
15+
#[macro_use]
16+
extern crate serde_derive;
17+
extern crate sysfs_gpio;
18+
extern crate toml;
19+
extern crate users;
1520

21+
pub mod error;
1622
pub mod options;
1723
pub mod config;
1824
pub mod commands;

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use gpio_utils::config::{self, GpioConfig};
1717
use std::process::exit;
1818

1919
fn main() {
20-
env_logger::init().unwrap();
20+
env_logger::init();
2121

2222
let matches = App::new("GPIO Utils")
2323
.version(env!("CARGO_PKG_VERSION"))

0 commit comments

Comments
 (0)