1 |
commit: 40696b7445cd4353fa542ad3dc84e120bbfa9612 |
2 |
Author: Matt Turner <mattst88 <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sat May 16 21:44:37 2020 +0000 |
4 |
Commit: Matt Turner <mattst88 <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Oct 29 15:24:45 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/catalyst.git/commit/?id=40696b74 |
7 |
|
8 |
catalyst: Use libmount for handling mounts |
9 |
|
10 |
Handle the mounts/unmounts in all in process rather than shelling out |
11 |
(pun intended!) to an external program. |
12 |
|
13 |
While we're here, change some log.notice to log.debug since those cases |
14 |
are normal and expected. |
15 |
|
16 |
Signed-off-by: Matt Turner <mattst88 <AT> gentoo.org> |
17 |
|
18 |
catalyst/base/stagebase.py | 57 ++++++++++++++++++++++++++++------------------ |
19 |
1 file changed, 35 insertions(+), 22 deletions(-) |
20 |
|
21 |
diff --git a/catalyst/base/stagebase.py b/catalyst/base/stagebase.py |
22 |
index cdc5a8a9..fd723e48 100644 |
23 |
--- a/catalyst/base/stagebase.py |
24 |
+++ b/catalyst/base/stagebase.py |
25 |
@@ -6,6 +6,7 @@ import sys |
26 |
|
27 |
from pathlib import Path |
28 |
|
29 |
+import libmount |
30 |
import toml |
31 |
|
32 |
from snakeoil import fileutils |
33 |
@@ -860,7 +861,8 @@ class StageBase(TargetBase, ClearBase, GenBase): |
34 |
|
35 |
source = str(self.mount[x]['source']) |
36 |
target = self.settings['chroot_path'] + str(self.mount[x]['target']) |
37 |
- mount = ['mount'] |
38 |
+ fstype = '' |
39 |
+ options = '' |
40 |
|
41 |
log.debug('bind %s: "%s" -> "%s"', x, source, target) |
42 |
|
43 |
@@ -868,18 +870,20 @@ class StageBase(TargetBase, ClearBase, GenBase): |
44 |
if 'var_tmpfs_portage' not in self.settings: |
45 |
continue |
46 |
|
47 |
- mount += ['-t', 'tmpfs', '-o', |
48 |
- f"size={self.settings['var_tmpfs_portage']}G"] |
49 |
+ fstype = 'tmpfs' |
50 |
+ options = f"size={self.settings['var_tmpfs_portage']}G" |
51 |
elif source == 'tmpfs': |
52 |
- mount += ['-t', 'tmpfs'] |
53 |
+ fstype = 'tmpfs' |
54 |
elif source == 'shm': |
55 |
- mount += ['-t', 'tmpfs', '-o', 'noexec,nosuid,nodev'] |
56 |
+ fstype = 'tmpfs' |
57 |
+ options = "noexec,nosuid,nodev" |
58 |
else: |
59 |
source_path = Path(self.mount[x]['source']) |
60 |
if source_path.suffix == '.sqfs': |
61 |
- mount += ['-o', 'ro'] |
62 |
+ fstype = "squashfs" |
63 |
+ options = "ro,loop" |
64 |
else: |
65 |
- mount.append('--bind') |
66 |
+ options = "bind" |
67 |
|
68 |
# We may need to create the source of the bind mount. E.g., in the |
69 |
# case of an empty package cache we must create the directory that |
70 |
@@ -888,38 +892,47 @@ class StageBase(TargetBase, ClearBase, GenBase): |
71 |
|
72 |
Path(target).mkdir(mode=0o755, parents=True, exist_ok=True) |
73 |
|
74 |
- cmd(mount + [source, target], env=self.env, fail_func=self.unbind) |
75 |
+ try: |
76 |
+ cxt = libmount.Context(source=source, target=target, |
77 |
+ fstype=fstype, options=options) |
78 |
+ cxt.mount() |
79 |
+ except OSError as e: |
80 |
+ self.unbind() |
81 |
+ raise CatalystError(f"Counldn't mount: {source}, {e.strerror}") |
82 |
|
83 |
def unbind(self): |
84 |
- ouch = 0 |
85 |
- mypath = self.settings["chroot_path"] |
86 |
+ chroot_path = self.settings["chroot_path"] |
87 |
+ umount_failed = False |
88 |
|
89 |
# Unmount in reverse order |
90 |
- for x in [x for x in reversed(self.mount) if self.mount[x]['enable']]: |
91 |
- target = normpath(mypath + self.mount[x]['target']) |
92 |
- if not os.path.exists(target): |
93 |
- log.notice('%s does not exist. Skipping', target) |
94 |
+ for target in [Path(chroot_path + self.mount[x]['target']) |
95 |
+ for x in reversed(self.mount) |
96 |
+ if self.mount[x]['enable']]: |
97 |
+ if not target.exists(): |
98 |
+ log.debug('%s does not exist. Skipping', target) |
99 |
continue |
100 |
|
101 |
if not ismount(target): |
102 |
- log.notice('%s is not a mount point. Skipping', target) |
103 |
+ log.debug('%s is not a mount point. Skipping', target) |
104 |
continue |
105 |
|
106 |
try: |
107 |
- cmd(['umount', target], env=self.env) |
108 |
- except CatalystError: |
109 |
+ cxt = libmount.Context(target=str(target)) |
110 |
+ cxt.umount() |
111 |
+ except OSError: |
112 |
log.warning('First attempt to unmount failed: %s', target) |
113 |
log.warning('Killing any pids still running in the chroot') |
114 |
|
115 |
self.kill_chroot_pids() |
116 |
|
117 |
try: |
118 |
- cmd(['umount', target], env=self.env) |
119 |
- except CatalystError: |
120 |
- ouch = 1 |
121 |
- log.warning("Couldn't umount bind mount: %s", target) |
122 |
+ cxt.umount() |
123 |
+ except OSError as e: |
124 |
+ umount_failed = True |
125 |
+ log.warning("Couldn't umount: %s, %s", target, |
126 |
+ e.strerror) |
127 |
|
128 |
- if ouch: |
129 |
+ if umount_failed: |
130 |
# if any bind mounts really failed, then we need to raise |
131 |
# this to potentially prevent an upcoming bash stage cleanup script |
132 |
# from wiping our bind mounts. |