aboutsummaryrefslogtreecommitdiff
blob: e6ddce6805cfe6da375832e07adc9ed1796f593b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#-*- coding:utf-8 -*-
# Copyright 2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
"""
Methods to check whether Portage is going to write to read-only filesystems.
Since the methods are not portable across different OSes, each OS needs its
own method. To expand RO checking for different OSes, add a method which
accepts a list of directories and returns a list of mounts which need to be
remounted RW, then add "elif ostype == (the ostype value for your OS)" to
get_ro_checker().
"""
from __future__ import unicode_literals

import io
import logging
import re

from portage import _encodings
from portage.util import writemsg_level
from portage.localization import _
from portage.data import ostype


def get_ro_checker():
	"""
	Uses the system type to find an appropriate method for testing whether Portage
	is going to write to any read-only filesystems.

	@return:
	1. A method for testing for RO filesystems appropriate to the current system.
	"""
	return _CHECKERS.get(ostype, empty_ro_checker)


def linux_ro_checker(dir_list):
	"""
	Use /proc/mounts to check that no directories installed by the ebuild are set
	to be installed to a read-only filesystem.

	@param dir_list: A list of directories installed by the ebuild.
	@type dir_list: List
	@return:
	1. A list of filesystems which are both set to be written to and are mounted
	read-only, may be empty.
	"""
	ro_filesystems = set()

	try:
		with io.open("/proc/mounts", mode='r', encoding=_encodings['content'],
			errors='replace') as f:
			roregex = re.compile(r'(\A|,)ro(\Z|,)')
			for line in f:
				if roregex.search(line.split(" ")[3].strip()) is not None:
					romount = line.split(" ")[1].strip()
					ro_filesystems.add(romount)

	# If /proc/mounts can't be read, assume that there are no RO
	# filesystems and return.
	except EnvironmentError:
		writemsg_level(_("!!! /proc/mounts cannot be read"),
			level=logging.WARNING, noiselevel=-1)
		return []

	return set.intersection(ro_filesystems, set(dir_list))


def empty_ro_checker(dir_list):
	"""
	Always returns [], this is the fallback function if the system does not have
	an ro_checker method defined.
	"""
	return []


# _CHECKERS is a map from ostype output to the appropriate function to return
# in get_ro_checker.
_CHECKERS = {
	"Linux": linux_ro_checker,
}