Ver código fonte

Merge branch 'LD_LIBRARY_PATH' into 'master'

Ld library path

See merge request redox-os/relibc!279
Jeremy Soller 4 anos atrás
pai
commit
db6a589421
3 arquivos alterados com 86 adições e 38 exclusões
  1. 53 0
      src/ld_so/access.rs
  2. 30 37
      src/ld_so/linker.rs
  3. 3 1
      src/ld_so/mod.rs

+ 53 - 0
src/ld_so/access.rs

@@ -0,0 +1,53 @@
+// Wrapper over the access syscall that doesn't touch errno variable,
+// Do not use outside of ld_so
+
+use crate::{c_str::CStr, platform::types::*};
+
+#[cfg(target_os = "redox")]
+use crate::header::unistd::{F_OK, R_OK, W_OK, X_OK};
+
+#[cfg(target_os = "linux")]
+pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int {
+    let path = CStr::from_ptr(path);
+    syscall!(ACCESS, (path).as_ptr(), mode) as c_int
+}
+
+// Wrapper over the systemcall, Do not use outside of ld_so
+#[cfg(target_os = "redox")]
+pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int {
+    let path = CStr::from_ptr(path).to_bytes();
+    let fd = match syscall::open(path, syscall::O_CLOEXEC) {
+        Ok(fd) => fd,
+        _ => return -1,
+    };
+    if mode == F_OK {
+        return 0;
+    }
+    let mut stat = syscall::Stat::default();
+    if syscall::fstat(fd, &mut stat).is_err() {
+        return -1;
+    }
+    let uid = match syscall::getuid() {
+        Ok(uid) => uid,
+        Err(_) => return -1,
+    };
+    let gid = match syscall::getgid() {
+        Ok(gid) => gid,
+        Err(_) => return -1,
+    };
+
+    let perms = if stat.st_uid as usize == uid {
+        stat.st_mode >> (3 * 2 & 0o7)
+    } else if stat.st_gid as usize == gid {
+        stat.st_mode >> (3 * 1 & 0o7)
+    } else {
+        stat.st_mode & 0o7
+    };
+    if (mode & R_OK == R_OK && perms & 0o4 != 0o4)
+        || (mode & W_OK == W_OK && perms & 0o2 != 0o2)
+        || (mode & X_OK == X_OK && perms & 0o1 != 0o1)
+    {
+        return -1;
+    }
+    0
+}

+ 30 - 37
src/ld_so/linker.rs

@@ -21,16 +21,16 @@ use crate::{
     c_str::CString,
     fs::File,
     header::{fcntl, sys_mman, unistd},
-    io::{self, Read},
+    io::Read,
     platform::types::c_void,
 };
 
 use super::{
+    access::access,
     debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
     tcb::{Master, Tcb},
     PAGE_SIZE,
 };
-
 #[cfg(target_os = "redox")]
 const PATH_SEP: char = ';';
 
@@ -94,54 +94,41 @@ impl Linker {
     }
 
     pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
-        self.dep_tree = self.load_recursive(name, path)?
-            .ok_or(Error::Malformed(format!(
-                "failed to find '{}'",
-                path
-            )))?;
+        self.dep_tree = self.load_recursive(name, path)?;
         if self.verbose {
             println!("Dep tree: {:#?}", self.dep_tree);
         }
         return Ok(());
     }
 
-    fn load_recursive(&mut self, name: &str, path: &str) -> Result<Option<DepTree>> {
+    fn load_recursive(&mut self, name: &str, path: &str) -> Result<DepTree> {
         if self.verbose {
             println!("load {}: {}", name, path);
         }
+        if self.cir_dep.contains(name) {
+            return Err(Error::Malformed(format!(
+                "Circular dependency: {} is a dependency of itself",
+                name
+            )));
+        }
 
+        let mut deps = DepTree::new(name.to_string());
+        let mut data = Vec::new();
+        self.cir_dep.insert(name.to_string());
         let path_c = CString::new(path)
             .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
 
-        let mut data = Vec::new();
         {
             let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
-            let mut file = match File::open(&path_c, flags) {
-                Ok(ok) => ok,
-                Err(err) => match err.kind() {
-                    io::ErrorKind::NotFound => return Ok(None),
-                    _ => return Err(Error::Malformed(format!("failed to open '{}': {}", path, err)))
-                }
-            };
+            let mut file = File::open(&path_c, flags)
+                .map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?;
 
             file.read_to_end(&mut data)
                 .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
         }
-
-        if self.cir_dep.contains(name) {
-            return Err(Error::Malformed(format!(
-                "Circular dependency: {} is a dependency of itself",
-                name
-            )));
-        }
-        self.cir_dep.insert(name.to_string());
-
-        let mut deps = DepTree::new(name.to_string());
         deps.deps = self.load_data(name, data.into_boxed_slice())?;
-
         self.cir_dep.remove(name);
-
-        Ok(Some(deps))
+        Ok(deps)
     }
 
     pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<Vec<DepTree>> {
@@ -164,12 +151,7 @@ impl Linker {
             // It should be previously resolved so we don't need to worry about it
             Ok(None)
         } else if name.contains('/') {
-            Ok(Some(self.load_recursive(name, name)?
-                .ok_or(Error::Malformed(format!(
-                    "failed to find '{}'",
-                    name
-                )))?
-            ))
+            Ok(Some(self.load_recursive(name, name)?))
         } else {
             let library_path = self.library_path.clone();
             for part in library_path.split(PATH_SEP) {
@@ -181,8 +163,19 @@ impl Linker {
                 if self.verbose {
                     println!("check {}", path);
                 }
-                if let Some(deps) = self.load_recursive(name, &path)? {
-                    return Ok(Some(deps));
+                let access = unsafe {
+                    let path_c = CString::new(path.as_bytes()).map_err(|err| {
+                        Error::Malformed(format!("invalid path '{}': {}", path, err))
+                    })?;
+
+                    // TODO: Use R_OK | X_OK
+                    // We cannot use unix stdlib because errno is thead local variable
+                    // and fs:[0] is not set yet.
+                    access(path_c.as_ptr(), unistd::F_OK) == 0
+                };
+
+                if access {
+                    return Ok(Some(self.load_recursive(name, &path)?));
                 }
             }
 

+ 3 - 1
src/ld_so/mod.rs

@@ -1,13 +1,15 @@
 use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};
 
 use self::tcb::{Master, Tcb};
-use crate::{c_str::CStr, platform::types::*, start::Stack};
+use crate::start::Stack;
 pub const PAGE_SIZE: usize = 4096;
 
+mod access;
 pub mod debug;
 pub mod linker;
 pub mod start;
 pub mod tcb;
+
 pub fn static_init(sp: &'static Stack) {
     let mut phdr_opt = None;
     let mut phent_opt = None;