1use crate::config::PinConfig;
10use crate::error::*;
11use lazy_static::lazy_static;
12use nix::unistd::{chown, Gid, Uid};
13use std::fs;
14use std::io::ErrorKind;
15use std::os::unix::fs as unix_fs;
16use std::os::unix::fs::PermissionsExt;
17use std::path;
18use std::sync::Mutex;
19use sysfs_gpio;
20use uzers::{Groups, Users, UsersCache};
21
22lazy_static! {
23 static ref USERS_CACHE: Mutex<UsersCache> = Mutex::new(UsersCache::new());
24}
25
26pub fn unexport(pin_config: &PinConfig, symlink_root: Option<&str>) -> Result<()> {
38 if let Some(symroot) = symlink_root {
39 for name in &pin_config.names {
41 let mut dst = path::PathBuf::from(symroot);
42 dst.push(name);
43 match fs::remove_file(dst) {
44 Ok(_) => (),
45 Err(ref e) if e.kind() == ErrorKind::NotFound => (),
46 Err(e) => return Err(e.into()),
47 };
48 }
49 }
50
51 let pin = pin_config.get_pin();
56 match pin.unexport() {
57 Ok(_) => Ok(()),
58 Err(sysfs_gpio::Error::Io(ref e)) if e.kind() == ErrorKind::InvalidInput => Ok(()),
59 Err(e) => Err(e.into()),
60 }
61}
62
63pub fn export(pin_config: &PinConfig, symlink_root: Option<&str>) -> Result<()> {
75 let pin = pin_config.get_pin();
76 pin.export()?;
77
78 let uid = if let Some(username) = pin_config.user.as_ref() {
79 Some(
80 USERS_CACHE
81 .lock()
82 .unwrap()
83 .get_user_by_name(username)
84 .map(|u| Uid::from_raw(u.uid()))
85 .ok_or_else(|| format!("Unable to find user {:?}", username))?,
86 )
87 } else {
88 None
89 };
90
91 let gid = if let Some(groupname) = pin_config.group.as_ref() {
92 Some(
93 USERS_CACHE
94 .lock()
95 .unwrap()
96 .get_group_by_name(groupname)
97 .map(|g| Gid::from_raw(g.gid()))
98 .ok_or_else(|| format!("Unable to find group {:?}", groupname))?,
99 )
100 } else {
101 None
102 };
103
104 if uid.is_some() || gid.is_some() || pin_config.mode.is_some() {
106 for entry in fs::read_dir(format!("/sys/class/gpio/gpio{}", &pin_config.num))? {
107 let e = entry?;
108 let metadata = e.metadata()?;
109
110 if metadata.is_file() {
111 if uid.is_some() || gid.is_some() {
112 chown(e.path().as_path(), uid, gid)?;
113 }
114
115 if let Some(mode) = pin_config.mode {
116 let mut permissions = metadata.permissions();
117 permissions.set_mode(mode);
118 fs::set_permissions(e.path().as_path(), permissions)?;
119 }
120 }
121 }
122 }
123
124 if let Some(symroot) = symlink_root {
126 fs::create_dir_all(symroot)?;
128
129 pin_config.get_pin().set_active_low(pin_config.active_low)?;
131
132 pin_config.get_pin().set_direction(pin_config.direction)?;
134
135 for name in &pin_config.names {
137 let mut dst = path::PathBuf::from(symroot);
138 dst.push(name);
139 match unix_fs::symlink(format!("/sys/class/gpio/gpio{}", pin_config.num), dst) {
140 Err(ref e) if e.kind() == ErrorKind::AlreadyExists => (),
141 Err(e) => return Err(e.into()),
142 _ => (),
143 };
144 }
145 }
146
147 Ok(())
148}