Skip to content

Commit

Permalink
Check that lock still references current pidfile
Browse files Browse the repository at this point in the history
  • Loading branch information
tilde-engineering committed Oct 6, 2014
1 parent 5ac0812 commit db4d127
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
name = "pidfile"
version = "0.1.0"
authors = ["Carl Lerche <[email protected]>"]

[dependencies.nix]
git = "https://github.com/carllerche/nix-rust.git"
6 changes: 6 additions & 0 deletions src/file_posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use libc::{
c_void, c_int, c_short, pid_t, mode_t,
O_CREAT, O_WRONLY, SEEK_SET, EINTR, EACCES, EAGAIN
};
use nix::sys::stat;
use nix::SysResult;
use ffi::{
flock, O_SYNC, F_SETFD, F_GETLK,
F_SETLK, F_WRLCK, F_UNLCK, FD_CLOEXEC
Expand Down Expand Up @@ -124,6 +126,10 @@ impl File {

Ok(())
}

pub fn stat(&self) -> SysResult<stat::FileStat> {
stat::fstat(self.fd)
}
}

impl Drop for File {
Expand Down
63 changes: 52 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
#![feature(phase)]

extern crate libc;
extern crate nix;

#[phase(plugin, link)]
extern crate log;

use std::fmt;
use std::io::{FilePermission, IoResult, IoError, FileNotFound};
use std::io::fs;
use std::path::{BytesContainer, Path};
use std::from_str::FromStr;
use libc::pid_t;
use nix::sys::stat::stat;
use file::File;

#[cfg(any(target_os = "macos", target_os = "ios"))]
Expand Down Expand Up @@ -46,13 +49,16 @@ impl Request {
let mut f = try!(res.map_err(LockError::io_error));

if !try!(f.lock().map_err(LockError::io_error)) {
debug!("lock not acquired; conflict");
return Err(LockError::conflict());
}

debug!("lock acquired");

try!(f.truncate().map_err(LockError::io_error));
try!(f.write(self.pid).map_err(LockError::io_error));

debug!("lock acquired");
debug!("lockfile written");

return Ok(Lock {
pidfile: Pidfile { pid: self.pid as uint },
Expand Down Expand Up @@ -94,7 +100,7 @@ impl Request {

/// Represents a pidfile that exists at the requested location and has an
/// active lock.
#[deriving(Clone)]
#[deriving(Clone, Show)]
pub struct Pidfile {
pid: uint
}
Expand All @@ -108,7 +114,6 @@ impl Pidfile {
pub struct Lock {
pidfile: Pidfile,
path: Path,

#[allow(dead_code)]
handle: File,
}
Expand All @@ -117,14 +122,44 @@ impl Lock {
pub fn pidfile(&self) -> Pidfile {
self.pidfile
}
}

impl Drop for Lock {
#[allow(unused_must_use)]
fn drop(&mut self) {
// Some non-critical cleanup. We do not assume that the pidfile will
// properly get cleaned up since this handler may not get executed.
fs::unlink(&self.path);
pub fn ensure_current(&self) -> Result<(), Option<uint>> {
// 1. stat the current fd
// - if error, try to read the pid, if it exists
// - if success, return Err(Some(new_pid))
// - otherwise, return Err(None)
// 2. stat the path
// - if error, return Err(None)
// 3. compare the inodes in the two stat results
// - if same, return Ok(())
// - otherwise, try to read the pid
// - if success, return Err(Some(new_pid))
// - otherwise, return Err(None)
//

let current_stat = match self.handle.stat() {
Err(_) => return Err(self.read_pid()),
Ok(stat) => stat
};

let path_stat = try!(stat(&self.path).map_err(|_| None));

if current_stat.st_ino == path_stat.st_ino {
Ok(())
} else {
Err(self.read_pid())
}
}

fn read_pid(&self) -> Option<uint> {
let mut f = std::io::File::open(&self.path);

let s = match f.read_to_string() {
Ok(val) => val,
Err(_) => return None
};

s.as_slice().lines().nth(0).and_then(|l| FromStr::from_str(l))
}
}

Expand All @@ -150,6 +185,12 @@ impl LockError {
}
}

impl fmt::Show for Lock {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Lock {{ pidfile: {}, path: {} }}", self.pidfile, self.path.display())
}
}

pub type LockResult<T> = Result<T, LockError>;

fn pid() -> pid_t {
Expand Down

0 comments on commit db4d127

Please sign in to comment.