aboutsummaryrefslogtreecommitdiff
blob: 7dbacce0d94f30798be54e3133d9f8b20a51cec0 (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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/sbin/openrc-run
# Copyright 1999-2016 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

depend() {
	# As of .67-r1, we call ALL lvm start/stop scripts with --sysinit, that
	# means dmeventd is NOT notified, as it cannot be safely running
	before dmeventd checkfs fsck
	after modules
}

dm_in_proc() {
	local retval=0
	for x in devices misc ; do
		grep -qs 'device-mapper' /proc/${x}
		retval=$((${retval} + $?))
	done
	return ${retval}
}

# char **build_dmsetup_command(volume)
#
# Returns complete dmsetup command given single volume name
build_dmsetup_command() {
	local count dmsetup_cmd
	
	# Number of lines mentioning volume name
	count=$(grep -v -e '^[[:space:]]*\(#\|$\)' /etc/dmtab | grep -c ${1})
	
	# If there's just one line:
	if [ ${count} -eq 1 ] ; then
		echo "echo $(grep -v -e '^[[:space:]]*\(#\|$\)' /etc/dmtab | \
			  grep ${1} | awk '{$1=""; print $0}') | /sbin/dmsetup create ${1}"
			  
	# For all cases with more lines:
	elif [ ${count} -gt 1 ] ; then
		for c in $( seq 1 ${count} ) ; do
			if [ ${c} -eq 1 ] ; then
				# Heavy escaping in awk-statement because we cannot use apostrophes
				dmsetup_cmd="echo -e $(grep -v -e '^[[:space:]]*\(#\|$\)' /etc/dmtab | \
							 grep ${1} | awk NR==${c}\ \{\$1=\"\"\;\ print\ \$0\})"
			else
				# Append starting with newline
				dmsetup_cmd="${dmsetup_cmd}\\\\n \
							 $(grep -v -e '^[[:space:]]*\(#\|$\)' /etc/dmtab | \
							 grep ${1} | awk NR==${c}\ \{\$1=\"\"\;\ print\ \$0\})"
			fi
		done
		echo "${dmsetup_cmd} | /sbin/dmsetup create ${1}"
	fi

	return 0
}

# char **get_new_dm_volumes(void)
#
#   Return unique volumes from /etc/dmtab
get_new_dm_volumes() {
	local volume

	# Filter comments and blank lines
	grep -v -e '^[[:space:]]*\(#\|$\)' /etc/dmtab | \
	awk '{ print $1 }' | \
	uniq | \
	while read volume ; do
		# If it exists, skip it
		dmvolume_exists "${volume%:}" && continue

		echo "${volume%:}"
	done

	return 0
}

# int dmvolume_exists(volume)
#
#   Return true if volume exists in DM table
dmvolume_exists() {
	local x line volume=$1

	[ -z "${volume}" ] && return 1

	/sbin/dmsetup ls 2>/dev/null | \
	while read line ; do
		for x in ${line} ; do
			# the following conditonal return only breaks out
			# of the while loop, as it is running in a pipe.
			[ "${x}" = "${volume}" ] && return 1
			# We only want to check the volume name
			break
		done
	done

	# if 1 was returned from the above loop, then indicate that
	# volume exists
	[ $? = 1 ] && return 0

	# otherwise the loop exited normally and the volume does not
	# exist
	return 1
}

# int is_empty_dm_volume(volume)
#
#   Return true if the volume exists in DM table, but is empty/non-valid
is_empty_dm_volume() {
	local table volume=$1

	set -- $(/sbin/dmsetup table 2>/dev/null | grep -e "^${volume}:")
	[ "${volume}" = "$1" -a -z "$2" ]
}


start() {
	if [ -e /proc/modules ] && ! dm_in_proc ; then
		modprobe dm-mod 2>/dev/null
	fi
	# Ensure the dirs exist for locking and running
	checkpath -q -d -m 0700 -o root:root /run/lvm /run/lock/lvm

	local x volume
	
	if [ -x /sbin/dmsetup -a -c /dev/mapper/control -a -f /etc/dmtab ] ; then
		[ -n "$(get_new_dm_volumes)" ] && \
			einfo " Setting up device-mapper volumes:"
		
		get_new_dm_volumes | \
		while read x ; do
			[ -n "${x}" ] || continue
			
			volume="${x##* }"
			
			ebegin "  Creating volume: ${volume}"
			if ! eval $(build_dmsetup_command ${volume}) >/dev/null 2>/dev/null ; then
				eend 1 "  Error creating volume: ${volume}"
				# dmsetup still adds an empty volume in some cases,
				#  so lets remove it
				is_empty_dm_volume "${volume}" && \
					/sbin/dmsetup remove "${volume}" 2>/dev/null
			else
				eend 0
			fi
		done
	fi
}