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