commit:     fcf1829e26eb901354958e92d48f214f2475aff4
Author:     Matt Turner <mattst88 <AT> gentoo <DOT> org>
AuthorDate: Sat May 16 21:44:37 2020 +0000
Commit:     Matt Turner <mattst88 <AT> gentoo <DOT> org>
CommitDate: Wed May 27 06:21:10 2020 +0000
URL:        https://gitweb.gentoo.org/proj/catalyst.git/commit/?id=fcf1829e

catalyst: Add and use support API for handling mounts

Handle the mounts/unmounts in all in process rather than shelling out
(pun intended!) to an external program.

Signed-off-by: Matt Turner <mattst88 <AT> gentoo.org>

 catalyst/base/stagebase.py | 28 ++++++++++++++++++----------
 catalyst/mount.py          | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/catalyst/base/stagebase.py b/catalyst/base/stagebase.py
index 00efd252..aa5cafd0 100644
--- a/catalyst/base/stagebase.py
+++ b/catalyst/base/stagebase.py
@@ -15,6 +15,7 @@ from DeComp.compress import CompressMap
 
 from catalyst import log
 from catalyst.defaults import (confdefaults, MOUNT_DEFAULTS, PORT_LOGDIR_CLEAN)
+from catalyst.mount import MS, mount, umount
 from catalyst.support import (CatalystError, file_locate, normpath,
                               cmd, read_makeconf, ismount, file_check)
 from catalyst.base.targetbase import TargetBase
@@ -847,7 +848,9 @@ class StageBase(TargetBase, ClearBase, GenBase):
 
             source = str(self.mount[x]['source'])
             target = self.settings['chroot_path'] + 
str(self.mount[x]['target'])
-            mount = ['mount']
+            filesystem = ''
+            flags = MS.NONE
+            options = ''
 
             log.debug('bind %s: "%s" -> "%s"', x, source, target)
 
@@ -855,18 +858,19 @@ class StageBase(TargetBase, ClearBase, GenBase):
                 if 'var_tmpfs_portage' not in self.settings:
                     continue
 
-                mount += ['-t', 'tmpfs', '-o',
-                          f"size={self.settings['var_tmpfs_portage']}G"]
+                filesystem = 'tmpfs'
+                options = f"size={self.settings['var_tmpfs_portage']}G"
             elif source == 'tmpfs':
-                mount += ['-t', 'tmpfs']
+                filesystem = 'tmpfs'
             elif source == 'shm':
-                mount += ['-t', 'tmpfs', '-o', 'noexec,nosuid,nodev']
+                filesystem = 'tmpfs'
+                flags = MS.NOEXEC | MS.NOSUID | MS.NODEV
             else:
                 source_path = Path(self.mount[x]['source'])
                 if source_path.suffix == '.sqfs':
-                    mount += ['-o', 'ro']
+                    flags = MS.RDONLY
                 else:
-                    mount.append('--bind')
+                    flags = MS.BIND
 
                     # We may need to create the source of the bind mount. 
E.g., in the
                     # case of an empty package cache we must create the 
directory that
@@ -875,7 +879,11 @@ class StageBase(TargetBase, ClearBase, GenBase):
 
             Path(target).mkdir(mode=0o755, parents=True, exist_ok=True)
 
-            cmd(mount + [source, target], env=self.env, fail_func=self.unbind)
+            try:
+                mount(source, target, filesystem, flags, options)
+            except OSError as e:
+                self.unbind()
+                raise CatalystError
 
     def unbind(self):
         ouch = 0
@@ -893,7 +901,7 @@ class StageBase(TargetBase, ClearBase, GenBase):
                 continue
 
             try:
-                cmd(['umount', target], env=self.env)
+                umount(target)
             except CatalystError:
                 log.warning('First attempt to unmount failed: %s', target)
                 log.warning('Killing any pids still running in the chroot')
@@ -901,7 +909,7 @@ class StageBase(TargetBase, ClearBase, GenBase):
                 self.kill_chroot_pids()
 
                 try:
-                    cmd(['umount', target], env=self.env)
+                    umount(target)
                 except CatalystError:
                     ouch = 1
                     log.warning("Couldn't umount bind mount: %s", target)

diff --git a/catalyst/mount.py b/catalyst/mount.py
new file mode 100644
index 00000000..0125353b
--- /dev/null
+++ b/catalyst/mount.py
@@ -0,0 +1,32 @@
+import ctypes
+import ctypes.util
+import enum
+import os
+
+libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
+libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, 
ctypes.c_ulong, ctypes.c_char_p)
+libc.umount.argtypes = (ctypes.c_char_p)
+
+class MS(enum.IntFlag):
+    NONE = 0x0
+    RDONLY = 0x1
+    NOSUID = 0x2
+    NODEV = 0x4
+    NOEXEC = 0x8
+    BIND = 0x1000
+
+def mount(source: str, target: str, fs: str, flags: MS = MS.NONE, options: str 
= '') -> None:
+    ret = libc.mount(source.encode(), target.encode(), fs.encode(), flags,
+                     options.encode())
+    if ret < 0:
+        errno = ctypes.get_errno()
+        raise OSError(errno,
+                      f"Error mounting {source} ({fs}) on {target} with 
options"
+                      f" {options}': {os.strerror(errno)}")
+
+def umount(target: str) -> None:
+    ret = libc.umount(target.encode())
+    if ret < 0:
+        errno = ctypes.get_errno()
+        raise OSError(errno,
+                      f"Error unmounting {target}': {os.strerror(errno)}")

Reply via email to