annotate rust/hg-core/src/lock.rs @ 48614:3efc8644dd00

test-http-bad-server: refactor the reading logic to avoid early return Our ultimate goal is to add another way to define the connection needs to be closed. To do so, we need the "read" code to be more unified. Differential Revision: https://phab.mercurial-scm.org/D12045
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Fri, 21 Jan 2022 11:15:56 +0100
parents 5734b03ecf3e
children 59be65b7cdfd
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
1 //! Filesystem-based locks for local repositories
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
2
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
3 use crate::errors::HgError;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
4 use crate::errors::HgResultExt;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
5 use crate::utils::StrExt;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
6 use crate::vfs::Vfs;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
7 use std::io;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 use std::io::ErrorKind;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
9
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10 #[derive(derive_more::From)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
11 pub enum LockError {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
12 AlreadyHeld,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
13 #[from]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
14 Other(HgError),
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17 /// Try to call `f` with the lock acquired, without waiting.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18 ///
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 /// If the lock is aready held, `f` is not called and `LockError::AlreadyHeld`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
20 /// is returned. `LockError::Io` is returned for any unexpected I/O error
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 /// accessing the lock file, including for removing it after `f` was called.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
22 /// The return value of `f` is dropped in that case. If all is successful, the
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
23 /// return value of `f` is forwarded.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
24 pub fn try_with_lock_no_wait<R>(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
25 hg_vfs: Vfs,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
26 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
27 f: impl FnOnce() -> R,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
28 ) -> Result<R, LockError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
29 let our_lock_data = &*OUR_LOCK_DATA;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
30 for _retry in 0..5 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
31 match make_lock(hg_vfs, lock_filename, our_lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
32 Ok(()) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
33 let result = f();
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
34 unlock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
35 return Ok(result);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
36 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
37 Err(HgError::IoError { error, .. })
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
38 if error.kind() == ErrorKind::AlreadyExists =>
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
39 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
40 let lock_data = read_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 if lock_data.is_none() {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
42 // Lock was apparently just released, retry acquiring it
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
43 continue;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
44 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
45 if !lock_should_be_broken(&lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
46 return Err(LockError::AlreadyHeld);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
47 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
48 // The lock file is left over from a process not running
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
49 // anymore. Break it, but with another lock to
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
50 // avoid a race.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
51 break_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
52
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
53 // Retry acquiring
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
54 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
55 Err(error) => Err(error)?,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
56 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
57 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
58 Err(LockError::AlreadyHeld)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
59 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
60
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
61 fn break_lock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), LockError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
62 try_with_lock_no_wait(hg_vfs, &format!("{}.break", lock_filename), || {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
63 // Check again in case some other process broke and
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
64 // acquired the lock in the meantime
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
65 let lock_data = read_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
66 if !lock_should_be_broken(&lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
67 return Err(LockError::AlreadyHeld);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
68 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
69 Ok(hg_vfs.remove_file(lock_filename)?)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
70 })?
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
71 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
72
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
73 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
74 fn make_lock(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
75 hg_vfs: Vfs,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
76 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
77 data: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
78 ) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
79 // Use a symbolic link because creating it is atomic.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
80 // The link’s "target" contains data not representing any path.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
81 let fake_symlink_target = data;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
82 hg_vfs.create_symlink(lock_filename, fake_symlink_target)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
83 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
84
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
85 fn read_lock(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
86 hg_vfs: Vfs,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
87 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
88 ) -> Result<Option<String>, HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
89 let link_target =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
90 hg_vfs.read_link(lock_filename).io_not_found_as_none()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
91 if let Some(target) = link_target {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
92 let data = target
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
93 .into_os_string()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
94 .into_string()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
95 .map_err(|_| HgError::corrupted("non-UTF-8 lock data"))?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
96 Ok(Some(data))
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
97 } else {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
98 Ok(None)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
99 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
100 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
101
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
102 fn unlock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
103 hg_vfs.remove_file(lock_filename)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
104 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
105
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106 /// Return whether the process that is/was holding the lock is known not to be
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
107 /// running anymore.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
108 fn lock_should_be_broken(data: &Option<String>) -> bool {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
109 (|| -> Option<bool> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
110 let (prefix, pid) = data.as_ref()?.split_2(':')?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
111 if prefix != &*LOCK_PREFIX {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
112 return Some(false);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
113 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
114 let process_is_running;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
115
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
116 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
117 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
118 let pid: libc::pid_t = pid.parse().ok()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
119 unsafe {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
120 let signal = 0; // Test if we could send a signal, without sending
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
121 let result = libc::kill(pid, signal);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
122 if result == 0 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
123 process_is_running = true
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
124 } else {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
125 let errno =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
126 io::Error::last_os_error().raw_os_error().unwrap();
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
127 process_is_running = errno != libc::ESRCH
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
128 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
129 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
130 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
131
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
132 Some(!process_is_running)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
133 })()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
134 .unwrap_or(false)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
135 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
136
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
137 lazy_static::lazy_static! {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
138 /// A string which is used to differentiate pid namespaces
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
139 ///
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
140 /// It's useful to detect "dead" processes and remove stale locks with
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
141 /// confidence. Typically it's just hostname. On modern linux, we include an
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
142 /// extra Linux-specific pid namespace identifier.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
143 static ref LOCK_PREFIX: String = {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
144 // Note: this must match the behavior of `_getlockprefix` in `mercurial/lock.py`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
145
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
146 /// Same as https://github.com/python/cpython/blob/v3.10.0/Modules/socketmodule.c#L5414
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
147 const BUFFER_SIZE: usize = 1024;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
148 let mut buffer = [0_i8; BUFFER_SIZE];
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
149 let hostname_bytes = unsafe {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
150 let result = libc::gethostname(buffer.as_mut_ptr(), BUFFER_SIZE);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
151 if result != 0 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
152 panic!("gethostname: {}", io::Error::last_os_error())
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
153 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
154 std::ffi::CStr::from_ptr(buffer.as_mut_ptr()).to_bytes()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
155 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
156 let hostname =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
157 std::str::from_utf8(hostname_bytes).expect("non-UTF-8 hostname");
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
158
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
159 #[cfg(target_os = "linux")]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
160 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
161 use std::os::linux::fs::MetadataExt;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
162 match std::fs::metadata("/proc/self/ns/pid") {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
163 Ok(meta) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
164 return format!("{}/{:x}", hostname, meta.st_ino())
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
165 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
166 Err(error) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
167 // TODO: match on `error.kind()` when `NotADirectory`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
168 // is available on all supported Rust versions:
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
169 // https://github.com/rust-lang/rust/issues/86442
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
170 use libc::{
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
171 ENOENT, // ErrorKind::NotFound
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
172 ENOTDIR, // ErrorKind::NotADirectory
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
173 EACCES, // ErrorKind::PermissionDenied
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
174 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
175 match error.raw_os_error() {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
176 Some(ENOENT) | Some(ENOTDIR) | Some(EACCES) => {}
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
177 _ => panic!("stat /proc/self/ns/pid: {}", error),
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
178 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
179 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
180 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
181 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
182
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
183 hostname.to_owned()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
184 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
185
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
186 static ref OUR_LOCK_DATA: String = format!("{}:{}", &*LOCK_PREFIX, std::process::id());
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
187 }