Gentoo Archives: gentoo-portage-dev

From: Chris Reffett <creffett@g.o>
To: gentoo-portage-dev@l.g.o
Subject: [gentoo-portage-dev] [PATCH v2] Test for read-only filesystems, bail out during preinst if there are any which will be written to and display a useful error message. Fixes bug 378869.
Date: Fri, 17 Jan 2014 00:40:20
Message-Id: 1389919144-30969-1-git-send-email-creffett@gentoo.org
In Reply to: Re: [gentoo-portage-dev] [PATCH] Check for and report read-only filesystems by Mike Frysinger
1 v2: Reformat, add a function to return an appropriate read-only checker
2 for the operating system, so that this can be extended to other OSes.
3 ---
4 pym/portage/dbapi/vartree.py | 32 +++++++++++++++++
5 pym/portage/util/rochecker.py | 81 +++++++++++++++++++++++++++++++++++++++++++
6 2 files changed, 113 insertions(+)
7 create mode 100644 pym/portage/util/rochecker.py
8
9 diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
10 index ed62323..c77cf07 100644
11 --- a/pym/portage/dbapi/vartree.py
12 +++ b/pym/portage/dbapi/vartree.py
13 @@ -32,6 +32,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
14 'portage.util.env_update:env_update',
15 'portage.util.listdir:dircache,listdir',
16 'portage.util.movefile:movefile',
17 + 'portage.util.rochecker:get_ro_checker',
18 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
19 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
20 'portage.util._async.SchedulerInterface:SchedulerInterface',
21 @@ -3508,6 +3509,8 @@ class dblink(object):
22
23 This function does the following:
24
25 + calls get_ro_checker to retrieve a function for checking whether Portage
26 + will write to a read-only filesystem, then runs it against the directory list
27 calls self._preserve_libs if FEATURES=preserve-libs
28 calls self._collision_protect if FEATURES=collision-protect
29 calls doebuild(mydo=pkg_preinst)
30 @@ -3685,6 +3688,7 @@ class dblink(object):
31 eagain_error = False
32
33 myfilelist = []
34 + mydirlist = []
35 mylinklist = []
36 paths_with_newlines = []
37 def onerror(e):
38 @@ -3717,6 +3721,9 @@ class dblink(object):
39 unicode_errors.append(new_parent[ed_len:])
40 break
41
42 + relative_path = parent[srcroot_len:]
43 + mydirlist.append("/" + relative_path)
44 +
45 for fname in files:
46 try:
47 fname = _unicode_decode(fname,
48 @@ -3829,6 +3836,31 @@ class dblink(object):
49 for other in others_in_slot])
50 prepare_build_dirs(settings=self.settings, cleanup=cleanup)
51
52 + # Check for read-only filesystems
53 + ro_checker_func = get_ro_checker()
54 + rofilesystems = ro_checker_func(mydirlist)
55 +
56 + if rofilesystems:
57 + msg = _("One or more files installed to this package are "
58 + "set to be installed to read-only filesystems. "
59 + "Please mount the filesystems below read-write "
60 + "and retry.")
61 + msg = textwrap.wrap(msg, 70)
62 + msg.append("")
63 + for f in rofilesystems:
64 + msg.append("\t%s" % os.path.join(destroot,
65 + f.lstrip(os.path.sep)))
66 + msg.append("")
67 + self._elog("eerror", "preinst", msg)
68 +
69 + msg = _("Package '%s' NOT merged due to read-only file systems.") % \
70 + self.settings.mycpv
71 + msg += _(" If necessary, refer to your elog "
72 + "messages for the whole content of the above message.")
73 + msg = textwrap.wrap(msg, 70)
74 + eerror(msg)
75 + return 1
76 +
77 # check for package collisions
78 blockers = self._blockers
79 if blockers is None:
80 diff --git a/pym/portage/util/rochecker.py b/pym/portage/util/rochecker.py
81 new file mode 100644
82 index 0000000..67e8131
83 --- /dev/null
84 +++ b/pym/portage/util/rochecker.py
85 @@ -0,0 +1,81 @@
86 +#-*- coding:utf-8 -*-
87 +# Copyright 2014 Gentoo Foundation
88 +# Distributed under the terms of the GNU General Public License v2
89 +"""
90 +Methods to check whether Portage is going to write to read-only filesystems.
91 +Since the methods are not portable across different OSes, each OS needs its
92 +own method. To expand RO checking for different OSes, add a method which
93 +accepts a list of directories and returns a list of mounts which need to be
94 +remounted RW, then add "elif ostype == (the ostype value for your OS)" to
95 +get_ro_checker()
96 +"""
97 +from __future__ import unicode_literals
98 +
99 +import logging
100 +import re
101 +
102 +from portage.util import writemsg_level
103 +from portage.localization import _
104 +from portage.data import ostype
105 +
106 +
107 +def get_ro_checker():
108 + """
109 + Uses the system type to find an appropriate method for testing whether Portage
110 + is going to write to any read-only filesystems
111 +
112 + @return:
113 + 1. A method for testing for RO filesystems appropriate to the current system
114 + """
115 + if ostype == "Linux":
116 + return linux_ro_checker
117 + else:
118 + return empty_ro_checker
119 +
120 +
121 +def linux_ro_checker(dir_list):
122 + """
123 + Use /proc/mounts to check that no directories installed by the ebuild are set
124 + to be installed to a read-only filesystem
125 +
126 + @param dir_list: Directories installed by the ebuild
127 + @type dir_list: List
128 + @return:
129 + 1. A list of filesystems which are both set to be written to and are mounted
130 + read-only, may be empty.
131 + """
132 + ro_filesystems = set()
133 + ro_filesystems_written = set()
134 +
135 + try:
136 + with open("/proc/mounts") as f:
137 + roregex = re.compile(r'(\A|,)ro(\Z|,)')
138 + for line in f:
139 + if roregex.search(line.split(" ")[3].strip()) is not None:
140 + romount = line.split(" ")[1].strip()
141 + ro_filesystems.add(romount)
142 +
143 + # If /proc/mounts can't be read, assume that there are no RO
144 + # filesystems and return
145 + except EnvironmentError:
146 + writemsg_level(_("!!! /proc/mounts cannot be read"),
147 + level=logging.WARNING, noiselevel=-1)
148 + return []
149 +
150 + if not ro_filesystems:
151 + return ro_filesystems
152 +
153 + for directory in dir_list:
154 + for filesystem in ro_filesystems:
155 + if filesystem == directory:
156 + ro_filesystems_written.add(filesystem)
157 +
158 + return ro_filesystems_written
159 +
160 +
161 +def empty_ro_checker(dir_list):
162 + """
163 + Always returns [], this is the fallback function if the system does not have
164 + an ro_checker method defined
165 + """
166 + return []
167 --
168 1.8.5.1

Replies