aboutsummaryrefslogtreecommitdiffstats
path: root/main/openrc/modloop.initd
blob: 6bd2e8a2f53d0057820ef0123489d1109e3c05ba (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
#!/sbin/openrc-run

# script that will mount image with modules

depend() {
	need dev
	before checkfs fsck hwdrivers modules hwclock
	keyword -vserver -lxc
}

# read kernel options
init_KOPT() {
	eval set -- $(cat /proc/cmdline 2>/dev/null)
	for opt; do
	        case "$opt" in
			modloop=*)
				eval "KOPT_${opt%%=*}='${opt#*=}'" ;;
		esac
	done
}

mountdirs() {
	awk '$2 !~ /^\/(sys|proc|dev|run)/ && $2 != "/" {print $2}' /proc/mounts
}

find_modloop() {
	local dir="$1"
	local kver=$(uname -r)
	local oifs="$IFS"
	IFS=$'\n'
	set -- $(blkid "$dir"/boot/* "$dir"/*)
	IFS="$oifs"
	for line; do
		img=${line%%:*}
		mount "$img" -o loop,ro /.modloop || continue
		if [ -d /.modloop/modules/$kver ]; then
			return 0
		fi
		umount /.modloop
	done
	return 1
}

find_backing_file() {
	local dir="$1"
	local dev=$(df -P "$dir" | tail -1 | awk '{print $1}')
	cat /sys/block/${dev#/dev/}/loop/backing_file 2>/dev/null
}

find_alpine_mnt() {
	local img="$(find_backing_file $1)"
	if [ -n "$img" ]; then
		df -P "$img" | tail -1 | awk '{print $6}'
	fi
}

start() {
	local modloop= mount_opts= modloop_dldir="/lib"

	mkdir -p /.modloop /lib
	case "$KOPT_modloop" in
		http://*|https://|ftp://*)
			wget -P "$modloop_dldir" "$KOPT_modloop" \
				&& modloop=$modloop_dldir/$(basename $KOPT_modloop)
			;;
		"")
			ewarn "WARNING! modloop boot option is missing."
			;;
		*)
			for dir in $(mountdirs); do
				if [ -f "$dir"/$KOPT_modloop ]; then
					modloop="$dir/${KOPT_modloop##/}"
					alpine_mnt="$dir"
					break
				fi
			done
			;;
	esac

	ebegin "Mounting modloop $modloop"
	if [ -n "$modloop" ]; then
		mount -o loop,ro $modloop /.modloop
		eend $? || return 1
	else
		for dir in $(mountdirs); do
			if find_modloop "$dir"; then
				alpine_mnt="$dir"
				break
			fi
		done
		if [ -d /.modloop/modules/$(uname -r) ]; then
			eend 0
		else
			eend 1 || return 1
		fi
	fi

	#use unionfs is available and configured
	if grep -q -w "unionfs$" /proc/filesystems && [ -n "$unionfs_size" ]; then
		ebegin "UnionFS detected. Mounting modloop rw"
		mkdir -p /.modunisonfs/modules /lib/modules
		mount -t tmpfs -o size="$unionfs_size" tmpfs /.modunisonfs/modules
		mount -t unionfs -o dirs=/.modunisonfs/modules=rw:/.modloop/modules=ro unionfs /lib/modules
		eend $? || return 1
	else
		rm -rf /lib/modules && ln -sf /.modloop/modules /lib/
	fi

	# copy firmware if there are any
	if [ -d $alpine_mnt/firmware ]; then
	        ebegin "Copying firmware from $alpine_mnt/firmware"
	        cp -R -a $alpine_mnt/firmware /lib/
	        eend $?
	elif  [ -d /lib/modules/firmware ]; then
		rmdir /lib/firmware 2>/dev/null \
			&& ln -s /lib/modules/firmware /lib/
	fi
	return 0
}

stop() {
	local rc=0
	alpine_mnt=$(find_alpine_mnt /.modloop)
	if mountinfo --quiet /.modunisonfs/modules && mountinfo --quiet /lib/modules; then
		umount /lib/modules
		umount /.modunisonfs/modules
	fi
	if mountinfo --quiet /.modloop; then
		ebegin "Unmounting /.modloop"
		umount -d /.modloop
		eend $? || return 1
	fi
	if [ -n "$alpine_mnt" ] && mountinfo --quiet $alpine_mnt; then
		ebegin "Unmounting $alpine_mnt"
		umount $alpine_mnt
		eend $?
	fi
}