Gentoo Archives: gentoo-commits

From: Matt Turner <mattst88@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/catalyst:wip/mattst88 commit in: catalyst/, catalyst/base/
Date: Wed, 27 May 2020 06:23:02
Message-Id: 1590560571.4df7daf31c225910ef711aa980e9822c37018ed9.mattst88@gentoo
1 commit: 4df7daf31c225910ef711aa980e9822c37018ed9
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: Wed May 27 06:22:51 2020 +0000
6 URL: https://gitweb.gentoo.org/proj/catalyst.git/commit/?id=4df7daf3
7
8 catalyst: Add and use support API 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 Signed-off-by: Matt Turner <mattst88 <AT> gentoo.org>
14
15 catalyst/base/stagebase.py | 28 ++++++++++++++++++----------
16 catalyst/mount.py | 32 ++++++++++++++++++++++++++++++++
17 2 files changed, 50 insertions(+), 10 deletions(-)
18
19 diff --git a/catalyst/base/stagebase.py b/catalyst/base/stagebase.py
20 index 00efd252..aa5cafd0 100644
21 --- a/catalyst/base/stagebase.py
22 +++ b/catalyst/base/stagebase.py
23 @@ -15,6 +15,7 @@ from DeComp.compress import CompressMap
24
25 from catalyst import log
26 from catalyst.defaults import (confdefaults, MOUNT_DEFAULTS, PORT_LOGDIR_CLEAN)
27 +from catalyst.mount import MS, mount, umount
28 from catalyst.support import (CatalystError, file_locate, normpath,
29 cmd, read_makeconf, ismount, file_check)
30 from catalyst.base.targetbase import TargetBase
31 @@ -847,7 +848,9 @@ class StageBase(TargetBase, ClearBase, GenBase):
32
33 source = str(self.mount[x]['source'])
34 target = self.settings['chroot_path'] + str(self.mount[x]['target'])
35 - mount = ['mount']
36 + filesystem = ''
37 + flags = MS.NONE
38 + options = ''
39
40 log.debug('bind %s: "%s" -> "%s"', x, source, target)
41
42 @@ -855,18 +858,19 @@ class StageBase(TargetBase, ClearBase, GenBase):
43 if 'var_tmpfs_portage' not in self.settings:
44 continue
45
46 - mount += ['-t', 'tmpfs', '-o',
47 - f"size={self.settings['var_tmpfs_portage']}G"]
48 + filesystem = 'tmpfs'
49 + options = f"size={self.settings['var_tmpfs_portage']}G"
50 elif source == 'tmpfs':
51 - mount += ['-t', 'tmpfs']
52 + filesystem = 'tmpfs'
53 elif source == 'shm':
54 - mount += ['-t', 'tmpfs', '-o', 'noexec,nosuid,nodev']
55 + filesystem = 'tmpfs'
56 + flags = MS.NOEXEC | MS.NOSUID | MS.NODEV
57 else:
58 source_path = Path(self.mount[x]['source'])
59 if source_path.suffix == '.sqfs':
60 - mount += ['-o', 'ro']
61 + flags = MS.RDONLY
62 else:
63 - mount.append('--bind')
64 + flags = MS.BIND
65
66 # We may need to create the source of the bind mount. E.g., in the
67 # case of an empty package cache we must create the directory that
68 @@ -875,7 +879,11 @@ class StageBase(TargetBase, ClearBase, GenBase):
69
70 Path(target).mkdir(mode=0o755, parents=True, exist_ok=True)
71
72 - cmd(mount + [source, target], env=self.env, fail_func=self.unbind)
73 + try:
74 + mount(source, target, filesystem, flags, options)
75 + except OSError as e:
76 + self.unbind()
77 + raise CatalystError
78
79 def unbind(self):
80 ouch = 0
81 @@ -893,7 +901,7 @@ class StageBase(TargetBase, ClearBase, GenBase):
82 continue
83
84 try:
85 - cmd(['umount', target], env=self.env)
86 + umount(target)
87 except CatalystError:
88 log.warning('First attempt to unmount failed: %s', target)
89 log.warning('Killing any pids still running in the chroot')
90 @@ -901,7 +909,7 @@ class StageBase(TargetBase, ClearBase, GenBase):
91 self.kill_chroot_pids()
92
93 try:
94 - cmd(['umount', target], env=self.env)
95 + umount(target)
96 except CatalystError:
97 ouch = 1
98 log.warning("Couldn't umount bind mount: %s", target)
99
100 diff --git a/catalyst/mount.py b/catalyst/mount.py
101 new file mode 100644
102 index 00000000..21e974b1
103 --- /dev/null
104 +++ b/catalyst/mount.py
105 @@ -0,0 +1,32 @@
106 +import ctypes
107 +import ctypes.util
108 +import enum
109 +import os
110 +
111 +libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
112 +libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p)
113 +libc.umount.argtypes = (ctypes.c_char_p,)
114 +
115 +class MS(enum.IntFlag):
116 + NONE = 0x0
117 + RDONLY = 0x1
118 + NOSUID = 0x2
119 + NODEV = 0x4
120 + NOEXEC = 0x8
121 + BIND = 0x1000
122 +
123 +def mount(source: str, target: str, fs: str, flags: MS = MS.NONE, options: str = '') -> None:
124 + ret = libc.mount(source.encode(), target.encode(), fs.encode(), flags,
125 + options.encode())
126 + if ret < 0:
127 + errno = ctypes.get_errno()
128 + raise OSError(errno,
129 + f"Error mounting {source} ({fs}) on {target} with options"
130 + f" {options}': {os.strerror(errno)}")
131 +
132 +def umount(target: str) -> None:
133 + ret = libc.umount(target.encode())
134 + if ret < 0:
135 + errno = ctypes.get_errno()
136 + raise OSError(errno,
137 + f"Error unmounting {target}': {os.strerror(errno)}")