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

# script that will mount image with modules

depend() {
	after dev-mount
	before checkfs fsck hwdrivers modules hwclock dev sysfs
	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
}

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

	mkdir -p /.modloop /lib
	case "$KOPT_modloop" in
		http://*|https://*|ftp://*)
			wget -P "$modloop_dldir" "$KOPT_modloop" \
				&& modloop=$modloop_dldir/$(basename $KOPT_modloop)
			;;
		*)
			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 overlayfs if available and configured
	if grep -q -w "overlay$" /proc/filesystems && [ -n "$unionfs_size" ]; then
		ebegin "OverlayFS detected, mounting modloop rw"
		mkdir -p /.modunisonfs /lib/modules
		mount -t tmpfs -o size="$unionfs_size" tmpfs /.modunisonfs
		mkdir -p /.modunisonfs/modules /.modunisonfs/work
		mount -t overlay -o upperdir=/.modunisonfs/modules,lowerdir=/.modloop/modules,workdir=/.modunisonfs/work overlay /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
	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
}