Gentoo Archives: gentoo-commits

From: Chris Reffett <creffett@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: pym/portage/dbapi/, pym/portage/util/
Date: Mon, 27 Jan 2014 04:02:48
Message-Id: 1390795295.47ef9a0969474f963dc8e52bfbbb8bc075e8d73c.creffett@gentoo
1 commit: 47ef9a0969474f963dc8e52bfbbb8bc075e8d73c
2 Author: Chris Reffett <creffett <AT> gentoo <DOT> org>
3 AuthorDate: Fri Jan 10 14:03:26 2014 +0000
4 Commit: Chris Reffett <creffett <AT> gentoo <DOT> org>
5 CommitDate: Mon Jan 27 04:01:35 2014 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=47ef9a09
7
8 Test for read-only filesystems, fixes bug 378869
9
10 If any read-only filesystems need writing, bail out and display a
11 useful error message.
12
13 v2: Reformat, add a function to return an appropriate read-only checker
14 for the operating system, so that this can be extended to other OSes.
15
16 v3: minor formatting tweaks from bernalex, including use os.path.join()
17 instead of string concatenation
18
19 v4: Update copyright header, change the code in rochecker to open with
20 io.open in order to not break on non-ascii characters as reported by
21 Arfrever. Change get_ro_checker to use a dict as suggested by vapier.
22
23 v5: Fix comment format as requested by vapier.
24
25 v6: Change linux_ro_checker to use set.intersection instead of the
26 longer check-and-append system as suggested by vapier.
27
28 v7: rename rochecker -> writeable_check
29
30 ---
31 pym/portage/dbapi/vartree.py | 34 +++++++++++++++-
32 pym/portage/util/writeable_check.py | 79 +++++++++++++++++++++++++++++++++++++
33 2 files changed, 112 insertions(+), 1 deletion(-)
34
35 diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
36 index ed62323..7a4a3d2 100644
37 --- a/pym/portage/dbapi/vartree.py
38 +++ b/pym/portage/dbapi/vartree.py
39 @@ -1,4 +1,4 @@
40 -# Copyright 1998-2013 Gentoo Foundation
41 +# Copyright 1998-2014 Gentoo Foundation
42 # Distributed under the terms of the GNU General Public License v2
43
44 from __future__ import unicode_literals
45 @@ -32,6 +32,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
46 'portage.util.env_update:env_update',
47 'portage.util.listdir:dircache,listdir',
48 'portage.util.movefile:movefile',
49 + 'portage.util.writeable_check:get_ro_checker',
50 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
51 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
52 'portage.util._async.SchedulerInterface:SchedulerInterface',
53 @@ -3508,6 +3509,8 @@ class dblink(object):
54
55 This function does the following:
56
57 + calls get_ro_checker to retrieve a function for checking whether Portage
58 + will write to a read-only filesystem, then runs it against the directory list
59 calls self._preserve_libs if FEATURES=preserve-libs
60 calls self._collision_protect if FEATURES=collision-protect
61 calls doebuild(mydo=pkg_preinst)
62 @@ -3685,6 +3688,7 @@ class dblink(object):
63 eagain_error = False
64
65 myfilelist = []
66 + mydirlist = []
67 mylinklist = []
68 paths_with_newlines = []
69 def onerror(e):
70 @@ -3717,6 +3721,9 @@ class dblink(object):
71 unicode_errors.append(new_parent[ed_len:])
72 break
73
74 + relative_path = parent[srcroot_len:]
75 + mydirlist.append(os.path.join("/", relative_path))
76 +
77 for fname in files:
78 try:
79 fname = _unicode_decode(fname,
80 @@ -3829,6 +3836,31 @@ class dblink(object):
81 for other in others_in_slot])
82 prepare_build_dirs(settings=self.settings, cleanup=cleanup)
83
84 + # Check for read-only filesystems.
85 + ro_checker = get_ro_checker()
86 + rofilesystems = ro_checker(mydirlist)
87 +
88 + if rofilesystems:
89 + msg = _("One or more files installed to this package are "
90 + "set to be installed to read-only filesystems. "
91 + "Please mount the following filesystems as read-write "
92 + "and retry.")
93 + msg = textwrap.wrap(msg, 70)
94 + msg.append("")
95 + for f in rofilesystems:
96 + msg.append("\t%s" % os.path.join(destroot,
97 + f.lstrip(os.path.sep)))
98 + msg.append("")
99 + self._elog("eerror", "preinst", msg)
100 +
101 + msg = _("Package '%s' NOT merged due to read-only file systems.") % \
102 + self.settings.mycpv
103 + msg += _(" If necessary, refer to your elog "
104 + "messages for the whole content of the above message.")
105 + msg = textwrap.wrap(msg, 70)
106 + eerror(msg)
107 + return 1
108 +
109 # check for package collisions
110 blockers = self._blockers
111 if blockers is None:
112
113 diff --git a/pym/portage/util/writeable_check.py b/pym/portage/util/writeable_check.py
114 new file mode 100644
115 index 0000000..e6ddce6
116 --- /dev/null
117 +++ b/pym/portage/util/writeable_check.py
118 @@ -0,0 +1,79 @@
119 +#-*- coding:utf-8 -*-
120 +# Copyright 2014 Gentoo Foundation
121 +# Distributed under the terms of the GNU General Public License v2
122 +"""
123 +Methods to check whether Portage is going to write to read-only filesystems.
124 +Since the methods are not portable across different OSes, each OS needs its
125 +own method. To expand RO checking for different OSes, add a method which
126 +accepts a list of directories and returns a list of mounts which need to be
127 +remounted RW, then add "elif ostype == (the ostype value for your OS)" to
128 +get_ro_checker().
129 +"""
130 +from __future__ import unicode_literals
131 +
132 +import io
133 +import logging
134 +import re
135 +
136 +from portage import _encodings
137 +from portage.util import writemsg_level
138 +from portage.localization import _
139 +from portage.data import ostype
140 +
141 +
142 +def get_ro_checker():
143 + """
144 + Uses the system type to find an appropriate method for testing whether Portage
145 + is going to write to any read-only filesystems.
146 +
147 + @return:
148 + 1. A method for testing for RO filesystems appropriate to the current system.
149 + """
150 + return _CHECKERS.get(ostype, empty_ro_checker)
151 +
152 +
153 +def linux_ro_checker(dir_list):
154 + """
155 + Use /proc/mounts to check that no directories installed by the ebuild are set
156 + to be installed to a read-only filesystem.
157 +
158 + @param dir_list: A list of directories installed by the ebuild.
159 + @type dir_list: List
160 + @return:
161 + 1. A list of filesystems which are both set to be written to and are mounted
162 + read-only, may be empty.
163 + """
164 + ro_filesystems = set()
165 +
166 + try:
167 + with io.open("/proc/mounts", mode='r', encoding=_encodings['content'],
168 + errors='replace') as f:
169 + roregex = re.compile(r'(\A|,)ro(\Z|,)')
170 + for line in f:
171 + if roregex.search(line.split(" ")[3].strip()) is not None:
172 + romount = line.split(" ")[1].strip()
173 + ro_filesystems.add(romount)
174 +
175 + # If /proc/mounts can't be read, assume that there are no RO
176 + # filesystems and return.
177 + except EnvironmentError:
178 + writemsg_level(_("!!! /proc/mounts cannot be read"),
179 + level=logging.WARNING, noiselevel=-1)
180 + return []
181 +
182 + return set.intersection(ro_filesystems, set(dir_list))
183 +
184 +
185 +def empty_ro_checker(dir_list):
186 + """
187 + Always returns [], this is the fallback function if the system does not have
188 + an ro_checker method defined.
189 + """
190 + return []
191 +
192 +
193 +# _CHECKERS is a map from ostype output to the appropriate function to return
194 +# in get_ro_checker.
195 +_CHECKERS = {
196 + "Linux": linux_ro_checker,
197 +}