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