1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
extern crate libc;
use self::libc::{c_int, O_RDWR, O_CREAT, O_EXCL };
use self::libc::{
	c_void,
	c_char,
	size_t,
	c_uint,
};
use self::libc::open as c_open;
use std::ptr;
use std::os::unix::io::IntoRawFd;
use std::os::unix::io::FromRawFd;
use std::fs::File;
use std::ffi::CString;

pub mod door_h;
use self::door_h::{
	door_call,
	door_create,
	door_desc_t,
	door_return,
	door_server_proc_t
};

mod stropts_h;
use self::stropts_h::fattach;

pub struct Door {
	descriptor: c_int
}

pub fn from(file: File) -> Door {
	Door { descriptor: file.into_raw_fd() }
}

pub fn server_safe_open(path: &str) -> Option<File> {
	let cpath = CString::new(path).unwrap();
	let fd = unsafe { c_open(cpath.as_ptr(), O_RDWR|O_CREAT|O_EXCL, 0400) };
	if fd < 0 {
		None
	} else {
		let file = unsafe { File::from_raw_fd(fd) };
		Some(file)
	}
}

pub trait ServerProcedure {
	fn rust();
	extern "C" fn c(
		_cookie: *const c_void, argp: *const c_char, arg_size: size_t,
		dp: *const door_desc_t, n_desc: c_uint
	) {
		Self::rust();
		unsafe { door_return(argp, arg_size, dp, n_desc) };
		panic!("Door return failed!");
	}
	fn attach_to(path: &str) -> Option<Door> {
		match create(Self::c) {
			None => None,
			Some(door) => {
				match server_safe_open(path) {
					None => None,
					Some(_d) => mount(door, path)
				}
			}
		}
	}
}

#[macro_export]
macro_rules! doorfn {
	($i:ident() $b:block) => {
		use doors::ServerProcedure;
		struct $i;
		impl ServerProcedure for $i {
			fn rust() $b
		}
	}
}

pub fn create(server_proc: door_server_proc_t) -> Option<Door> {
	let fd = unsafe { door_create(server_proc, ptr::null(), 0) };
	if fd < 0 {
		None
	} else {
		Some(Door{ descriptor: fd })
	}
}

pub fn mount(door: Door, path: &str) -> Option<Door> {
	let cpath = CString::new(path).unwrap();
	let success = unsafe { fattach(door.descriptor, cpath.as_ptr()) };
	if success < 0 {
		None
	} else {
		Some(door)
	}
}
	

impl Door {
	pub fn call(&self) -> bool {
		let success = unsafe { door_call(self.descriptor, ptr::null()) };
		(success >= 0)
	}
}

impl Drop for Door {
	fn drop(&mut self) {
		let fd = self.descriptor;
		unsafe { File::from_raw_fd(fd) };
	}
}