Mercurial > hg
annotate rust/hg-core/src/lock.rs @ 51470:406b413e3cf2 stable
rust-filepatterns: export glob_to_re function
Making this function public should not risk freezing the internal API,
and it can be useful for all downstream code that needs to perform
glob matching against byte strings, such as RHGitaly where it will
be useful to match on branches and tags.
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Mon, 11 Mar 2024 13:23:18 +0100 |
parents | e98fd81bb151 |
children | db7dbe6f7bb2 |
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::vfs::Vfs; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
6 use std::io; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
7 use std::io::ErrorKind; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
8 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
9 #[derive(derive_more::From)] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
10 pub enum LockError { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
11 AlreadyHeld, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
12 #[from] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
13 Other(HgError), |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
14 } |
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 /// Try to call `f` with the lock acquired, without waiting. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
17 /// |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
18 /// 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
|
19 /// 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
|
20 /// 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
|
21 /// 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
|
22 /// return value of `f` is forwarded. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
23 pub fn try_with_lock_no_wait<R>( |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
24 hg_vfs: Vfs, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
25 lock_filename: &str, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
26 f: impl FnOnce() -> R, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
27 ) -> Result<R, LockError> { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
28 let our_lock_data = &*OUR_LOCK_DATA; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
29 for _retry in 0..5 { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
30 match make_lock(hg_vfs, lock_filename, our_lock_data) { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
31 Ok(()) => { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
32 let result = f(); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
33 unlock(hg_vfs, lock_filename)?; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
34 return Ok(result); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
35 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
36 Err(HgError::IoError { error, .. }) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
37 if error.kind() == ErrorKind::AlreadyExists => |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
38 { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
39 let lock_data = read_lock(hg_vfs, lock_filename)?; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
40 if lock_data.is_none() { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
41 // Lock was apparently just released, retry acquiring it |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
42 continue; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
43 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
44 if !lock_should_be_broken(&lock_data) { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
45 return Err(LockError::AlreadyHeld); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
46 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
47 // 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
|
48 // anymore. Break it, but with another lock to |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
49 // avoid a race. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
50 break_lock(hg_vfs, lock_filename)?; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
51 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
52 // Retry acquiring |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
53 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
54 Err(error) => Err(error)?, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
55 } |
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 Err(LockError::AlreadyHeld) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
58 } |
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 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
|
61 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
|
62 // Check again in case some other process broke and |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
63 // acquired the lock in the meantime |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
64 let lock_data = read_lock(hg_vfs, lock_filename)?; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
65 if !lock_should_be_broken(&lock_data) { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
66 return Err(LockError::AlreadyHeld); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
67 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
68 Ok(hg_vfs.remove_file(lock_filename)?) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
69 })? |
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 #[cfg(unix)] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
73 fn make_lock( |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
74 hg_vfs: Vfs, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
75 lock_filename: &str, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
76 data: &str, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
77 ) -> Result<(), HgError> { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
78 // Use a symbolic link because creating it is atomic. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
79 // The link’s "target" contains data not representing any path. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
80 let fake_symlink_target = data; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
81 hg_vfs.create_symlink(lock_filename, fake_symlink_target) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
82 } |
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 fn read_lock( |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
85 hg_vfs: Vfs, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
86 lock_filename: &str, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
87 ) -> Result<Option<String>, HgError> { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
88 let link_target = |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
89 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
|
90 if let Some(target) = link_target { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
91 let data = target |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
92 .into_os_string() |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
93 .into_string() |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
94 .map_err(|_| HgError::corrupted("non-UTF-8 lock data"))?; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
95 Ok(Some(data)) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
96 } else { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
97 Ok(None) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
98 } |
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 fn unlock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), HgError> { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
102 hg_vfs.remove_file(lock_filename) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
103 } |
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 /// 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
|
106 /// running anymore. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
107 fn lock_should_be_broken(data: &Option<String>) -> bool { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
108 (|| -> Option<bool> { |
49632
29cf3167e459
hg-core: remove unneeded trait now that we support Rust 1.52+
Raphaël Gomès <rgomes@octobus.net>
parents:
48962
diff
changeset
|
109 let (prefix, pid) = data.as_ref()?.split_once(':')?; |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49632
diff
changeset
|
110 if prefix != *LOCK_PREFIX { |
48417
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
111 return Some(false); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
112 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
113 let process_is_running; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
114 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
115 #[cfg(unix)] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
116 { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
117 let pid: libc::pid_t = pid.parse().ok()?; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
118 unsafe { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
119 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
|
120 let result = libc::kill(pid, signal); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
121 if result == 0 { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
122 process_is_running = true |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
123 } else { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
124 let errno = |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
125 io::Error::last_os_error().raw_os_error().unwrap(); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
126 process_is_running = errno != libc::ESRCH |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
127 } |
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 Some(!process_is_running) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
132 })() |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
133 .unwrap_or(false) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
134 } |
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 lazy_static::lazy_static! { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
137 /// A string which is used to differentiate pid namespaces |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
138 /// |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
139 /// 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
|
140 /// 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
|
141 /// extra Linux-specific pid namespace identifier. |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
142 static ref LOCK_PREFIX: String = { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
143 // 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
|
144 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
145 /// 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
|
146 const BUFFER_SIZE: usize = 1024; |
49930
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49632
diff
changeset
|
147 // This cast is *needed* for platforms with signed chars |
e98fd81bb151
rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents:
49632
diff
changeset
|
148 #[allow(clippy::unnecessary_cast)] |
48962
59be65b7cdfd
rust-hg-core: use correct type for libc hostname buffer
Luke Granger-Brown <hg@lukegb.com>
parents:
48417
diff
changeset
|
149 let mut buffer = [0 as libc::c_char; BUFFER_SIZE]; |
48417
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
150 let hostname_bytes = unsafe { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
151 let result = libc::gethostname(buffer.as_mut_ptr(), BUFFER_SIZE); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
152 if result != 0 { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
153 panic!("gethostname: {}", io::Error::last_os_error()) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
154 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
155 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
|
156 }; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
157 let hostname = |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
158 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
|
159 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
160 #[cfg(target_os = "linux")] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
161 { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
162 use std::os::linux::fs::MetadataExt; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
163 match std::fs::metadata("/proc/self/ns/pid") { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
164 Ok(meta) => { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
165 return format!("{}/{:x}", hostname, meta.st_ino()) |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
166 } |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
167 Err(error) => { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
168 // TODO: match on `error.kind()` when `NotADirectory` |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
169 // is available on all supported Rust versions: |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
170 // https://github.com/rust-lang/rust/issues/86442 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
171 use libc::{ |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
172 ENOENT, // ErrorKind::NotFound |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
173 ENOTDIR, // ErrorKind::NotADirectory |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
174 EACCES, // ErrorKind::PermissionDenied |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
175 }; |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
176 match error.raw_os_error() { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
177 Some(ENOENT) | Some(ENOTDIR) | Some(EACCES) => {} |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
178 _ => panic!("stat /proc/self/ns/pid: {}", error), |
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 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
184 hostname.to_owned() |
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 |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
187 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
|
188 } |