]> git.ipfire.org Git - thirdparty/dracut.git/blob - modules.d/90dmsquash-live/dmsquash-live-root.sh
dmsquash-live, livenet: Simplify OverlayFS read-only overlay setup.
[thirdparty/dracut.git] / modules.d / 90dmsquash-live / dmsquash-live-root.sh
1 #!/bin/sh
2
3 type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
4
5 command -v unpack_archive >/dev/null || . /lib/img-lib.sh
6
7 PATH=/usr/sbin:/usr/bin:/sbin:/bin
8
9 if getargbool 0 rd.live.debug -n -y rdlivedebug; then
10 exec > /tmp/liveroot.$$.out
11 exec 2>> /tmp/liveroot.$$.out
12 set -x
13 fi
14
15 [ -z "$1" ] && exit 1
16 livedev="$1"
17
18 # parse various live image specific options that make sense to be
19 # specified as their own things
20 live_dir=$(getarg rd.live.dir -d live_dir)
21 [ -z "$live_dir" ] && live_dir="LiveOS"
22 squash_image=$(getarg rd.live.squashimg)
23 [ -z "$squash_image" ] && squash_image="squashfs.img"
24
25 getargbool 0 rd.live.ram -d -y live_ram && live_ram="yes"
26 getargbool 0 rd.live.overlay.reset -d -y reset_overlay && reset_overlay="yes"
27 getargbool 0 rd.live.overlay.readonly -d -y readonly_overlay && readonly_overlay="--readonly" || readonly_overlay=""
28 overlay=$(getarg rd.live.overlay -d overlay)
29 getargbool 0 rd.writable.fsimg -d -y writable_fsimg && writable_fsimg="yes"
30 overlay_size=$(getarg rd.live.overlay.size=)
31 [ -z "$overlay_size" ] && overlay_size=32768
32
33 getargbool 0 rd.live.overlay.thin && thin_snapshot="yes"
34 getargbool 0 rd.live.overlay.overlayfs && overlayfs="yes"
35
36 # CD/DVD media check
37 [ -b $livedev ] && fs=$(blkid -s TYPE -o value $livedev)
38 if [ "$fs" = "iso9660" -o "$fs" = "udf" ]; then
39 check="yes"
40 fi
41 getarg rd.live.check -d check || check=""
42 if [ -n "$check" ]; then
43 type plymouth >/dev/null 2>&1 && plymouth --hide-splash
44 if [ -n "$DRACUT_SYSTEMD" ]; then
45 p=$(dev_unit_name "$livedev")
46 systemctl start checkisomd5@${p}.service
47 else
48 checkisomd5 --verbose $livedev
49 fi
50 if [ $? -eq 1 ]; then
51 die "CD check failed!"
52 exit 1
53 fi
54 type plymouth >/dev/null 2>&1 && plymouth --show-splash
55 fi
56
57 ln -s $livedev /run/initramfs/livedev
58
59 # determine filesystem type for a filesystem image
60 det_img_fs() {
61 udevadm settle >&2
62 blkid -s TYPE -u noraid -o value "$1"
63 }
64
65 modprobe squashfs
66 CMDLINE=$(getcmdline)
67 for arg in $CMDLINE; do case $arg in ro|rw) liverw=$arg ;; esac; done
68 # mount the backing of the live image first
69 mkdir -m 0755 -p /run/initramfs/live
70 if [ -f $livedev ]; then
71 # no mount needed - we've already got the LiveOS image in initramfs
72 # check filesystem type and handle accordingly
73 fstype=$(det_img_fs $livedev)
74 case $fstype in
75 squashfs) SQUASHED=$livedev;;
76 auto) die "cannot mount live image (unknown filesystem type)" ;;
77 *) FSIMG=$livedev ;;
78 esac
79 [ -e /sys/fs/$fstype ] || modprobe $fstype
80 else
81 if [ "$(blkid -o value -s TYPE $livedev)" != "ntfs" ]; then
82 mount -n -t $fstype -o ${liverw:-ro} $livedev /run/initramfs/live
83 else
84 # Symlinking /usr/bin/ntfs-3g as /sbin/mount.ntfs seems to boot
85 # at the first glance, but ends with lots and lots of squashfs
86 # errors, because systemd attempts to kill the ntfs-3g process?!
87 if [ -x "/usr/bin/ntfs-3g" ]; then
88 ( exec -a @ntfs-3g ntfs-3g -o ${liverw:-ro} $livedev /run/initramfs/live ) | vwarn
89 else
90 die "Failed to mount block device of live image: Missing NTFS support"
91 exit 1
92 fi
93 fi
94
95 if [ "$?" != "0" ]; then
96 die "Failed to mount block device of live image"
97 exit 1
98 fi
99 fi
100
101 # overlay setup helper function
102 do_live_overlay() {
103 # create a sparse file for the overlay
104 # overlay: if non-ram overlay searching is desired, do it,
105 # otherwise, create traditional overlay in ram
106
107 l=$(blkid -s LABEL -o value $livedev) || l=""
108 u=$(blkid -s UUID -o value $livedev) || u=""
109
110 if [ -z "$overlay" ]; then
111 pathspec="/${live_dir}/overlay-$l-$u"
112 elif ( echo $overlay | grep -q ":" ); then
113 # pathspec specified, extract
114 pathspec=$( echo $overlay | sed -e 's/^.*://' )
115 fi
116
117 if [ -z "$pathspec" -o "$pathspec" = "auto" ]; then
118 pathspec="/${live_dir}/overlay-$l-$u"
119 fi
120 devspec=$( echo $overlay | sed -e 's/:.*$//' )
121
122 # need to know where to look for the overlay
123 if [ -z "$setup" -a -n "$devspec" -a -n "$pathspec" -a -n "$overlay" ]; then
124 mkdir -m 0755 /run/initramfs/overlayfs
125 opt=''
126 [ -n "$readonly_overlay" ] && opt=-r
127 mount -n -t auto $devspec /run/initramfs/overlayfs || :
128 if [ -f /run/initramfs/overlayfs$pathspec -a -w /run/initramfs/overlayfs$pathspec ]; then
129 OVERLAY_LOOPDEV=$(losetup -f --show $opt /run/initramfs/overlayfs$pathspec)
130 over=$OVERLAY_LOOPDEV
131 umount -l /run/initramfs/overlayfs || :
132 oltype=$(det_img_fs $OVERLAY_LOOPDEV)
133 if [ -z "$oltype" ] || [ "$oltype" = DM_snapshot_cow ]; then
134 if [ -n "$reset_overlay" ]; then
135 info "Resetting the Device-mapper overlay."
136 dd if=/dev/zero of=$OVERLAY_LOOPDEV bs=64k count=1 conv=fsync 2>/dev/null
137 fi
138 if [ -n "$overlayfs" ]; then
139 unset -v overlayfs
140 [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit=":>/xor_overlayfs;"
141 fi
142 setup="yes"
143 else
144 mount -n -t $oltype $opt $OVERLAY_LOOPDEV /run/initramfs/overlayfs
145 if [ -d /run/initramfs/overlayfs/overlayfs ] &&
146 [ -d /run/initramfs/overlayfs/ovlwork ]; then
147 ln -s /run/initramfs/overlayfs/overlayfs /run/overlayfs$opt
148 ln -s /run/initramfs/overlayfs/ovlwork /run/ovlwork$opt
149 if [ -z "$overlayfs" ]; then
150 overlayfs="yes"
151 [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit=":>/xor_overlayfs;"
152 fi
153 setup="yes"
154 fi
155 fi
156 elif [ -d /run/initramfs/overlayfs$pathspec ] &&
157 [ -d /run/initramfs/overlayfs$pathspec/../ovlwork ]; then
158 ln -s /run/initramfs/overlayfs$pathspec /run/overlayfs$opt
159 ln -s /run/initramfs/overlayfs$pathspec/../ovlwork /run/ovlwork$opt
160 if [ -z "$overlayfs" ]; then
161 overlayfs="yes"
162 [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit=":>/xor_overlayfs;"
163 fi
164 setup="yes"
165 fi
166 fi
167 if [ -n "$overlayfs" ]; then
168 modprobe overlay
169 if [ $? != 0 ]; then
170 m='OverlayFS is not available; using temporary Device-mapper overlay.'
171 unset -v overlayfs setup reloadsysrootmountunit
172 fi
173 fi
174
175 if [ -z "$setup" -o -n "$readonly_overlay" ]; then
176 if [ -n "$setup" ]; then
177 warn "Using temporary overlay."
178 elif [ -n "$devspec" -a -n "$pathspec" ]; then
179 [ -z "$m" ] &&
180 m=' Unable to find a persistent overlay; using a temporary one.'
181 m="$m"$'\n All root filesystem changes will be lost on shutdown.'
182 m="$m"$'\n Press [Enter] to continue.'
183 printf "\n\n\n\n${m}\n\n\n" > /dev/kmsg
184 if [ -n "$DRACUT_SYSTEMD" ]; then
185 if type plymouth >/dev/null 2>&1 && plymouth --ping ; then
186 if getargbool 0 rhgb || getargbool 0 splash ; then
187 m='>>>'$'\n''>>>'$'\n''>>>'$'\n\n\n'"$m"
188 m="${m%n.*}"$'n.\n\n\n''<<<'$'\n''<<<'$'\n''<<<'
189 plymouth display-message --text="${m}"
190 else
191 plymouth ask-question --prompt="${m}" --command=true
192 fi
193 else
194 m=">>>${m//.[[:space:]]/.} <<<"
195 systemd-ask-password --timeout=0 "${m}"
196 fi
197 else
198 type plymouth >/dev/null 2>&1 && plymouth --ping && plymouth --quit
199 read -s -r -p $'\n\n'"${m}" -n 1 reply
200 fi
201 fi
202 if [ -n "$overlayfs" ]; then
203 mkdir -m 0755 /run/overlayfs
204 mkdir -m 0755 /run/ovlwork
205 if [ -n "$readonly_overlay" ] && ! [ -h /run/overlayfs-r ]; then
206 info "No persistent overlay found."
207 unset -v readonly_overlay
208 [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit="${reloadsysrootmountunit}:>/xor_readonly;"
209 fi
210 else
211 dd if=/dev/null of=/overlay bs=1024 count=1 seek=$((overlay_size*1024)) 2> /dev/null
212 if [ -n "$setup" -a -n "$readonly_overlay" ]; then
213 RO_OVERLAY_LOOPDEV=$(losetup -f --show /overlay)
214 over=$RO_OVERLAY_LOOPDEV
215 else
216 OVERLAY_LOOPDEV=$(losetup -f --show /overlay)
217 over=$OVERLAY_LOOPDEV
218 fi
219 fi
220 fi
221
222 # set up the snapshot
223 if [ -z "$overlayfs" ]; then
224 if [ -n "$readonly_overlay" ] && [ -n "$OVERLAY_LOOPDEV" ]; then
225 echo 0 $sz snapshot $BASE_LOOPDEV $OVERLAY_LOOPDEV P 8 | dmsetup create --readonly live-ro
226 base="/dev/mapper/live-ro"
227 else
228 base=$BASE_LOOPDEV
229 fi
230 fi
231
232 if [ -n "$thin_snapshot" ]; then
233 modprobe dm_thin_pool
234 mkdir -m 0755 /run/initramfs/thin-overlay
235
236 # In block units (512b)
237 thin_data_sz=$(( $overlay_size * 1024 * 1024 / 512 ))
238 thin_meta_sz=$(( $thin_data_sz / 10 ))
239
240 # It is important to have the backing file on a tmpfs
241 # this is needed to let the loopdevice support TRIM
242 dd if=/dev/null of=/run/initramfs/thin-overlay/meta bs=1b count=1 seek=$((thin_meta_sz)) 2> /dev/null
243 dd if=/dev/null of=/run/initramfs/thin-overlay/data bs=1b count=1 seek=$((thin_data_sz)) 2> /dev/null
244
245 THIN_META_LOOPDEV=$( losetup --show -f /run/initramfs/thin-overlay/meta )
246 THIN_DATA_LOOPDEV=$( losetup --show -f /run/initramfs/thin-overlay/data )
247
248 echo 0 $thin_data_sz thin-pool $THIN_META_LOOPDEV $THIN_DATA_LOOPDEV 1024 1024 | dmsetup create live-overlay-pool
249 dmsetup message /dev/mapper/live-overlay-pool 0 "create_thin 0"
250
251 # Create a snapshot of the base image
252 echo 0 $sz thin /dev/mapper/live-overlay-pool 0 $base | dmsetup create live-rw
253 elif [ -z "$overlayfs" ]; then
254 echo 0 $sz snapshot $base $over PO 8 | dmsetup create live-rw
255 fi
256
257 # Create a device for the ro base of overlayed file systems.
258 if [ -z "$overlayfs" ]; then
259 echo 0 $sz linear $BASE_LOOPDEV 0 | dmsetup create --readonly live-base
260 fi
261 ln -s $BASE_LOOPDEV /dev/live-base
262 }
263 # end do_live_overlay()
264
265 # we might have a genMinInstDelta delta file for anaconda to take advantage of
266 if [ -e /run/initramfs/live/${live_dir}/osmin.img ]; then
267 OSMINSQFS=/run/initramfs/live/${live_dir}/osmin.img
268 # decompress the delta data
269 dd if=$OSMINSQFS of=/run/initramfs/osmin.img 2> /dev/null
270 OSMIN_SQUASHED_LOOPDEV=$( losetup -f )
271 losetup -r $OSMIN_SQUASHED_LOOPDEV /run/initramfs/osmin.img
272 mkdir -m 0755 -p /run/initramfs/squashfs.osmin
273 mount -n -t squashfs -o ro $OSMIN_SQUASHED_LOOPDEV /run/initramfs/squashfs.osmin
274 OSMIN_LOOPDEV=$( losetup -f )
275 losetup -r $OSMIN_LOOPDEV /run/initramfs/squashfs.osmin/osmin
276 umount -l /run/initramfs/squashfs.osmin
277 fi
278
279 # we might have an embedded fs image on squashfs (compressed live)
280 if [ -e /run/initramfs/live/${live_dir}/${squash_image} ]; then
281 SQUASHED="/run/initramfs/live/${live_dir}/${squash_image}"
282 fi
283 if [ -e "$SQUASHED" ]; then
284 if [ -n "$live_ram" ]; then
285 echo 'Copying live image to RAM...' > /dev/kmsg
286 echo ' (this may take a minute)' > /dev/kmsg
287 dd if=$SQUASHED of=/run/initramfs/squashed.img bs=512 2> /dev/null
288 echo 'Done copying live image to RAM.' > /dev/kmsg
289 SQUASHED="/run/initramfs/squashed.img"
290 fi
291
292 SQUASHED_LOOPDEV=$( losetup -f )
293 losetup -r $SQUASHED_LOOPDEV $SQUASHED
294 mkdir -m 0755 -p /run/initramfs/squashfs
295 mount -n -t squashfs -o ro $SQUASHED_LOOPDEV /run/initramfs/squashfs
296
297 if [ -d /run/initramfs/squashfs/LiveOS ]; then
298 if [ -f /run/initramfs/squashfs/LiveOS/rootfs.img ]; then
299 FSIMG="/run/initramfs/squashfs/LiveOS/rootfs.img"
300 elif [ -f /run/initramfs/squashfs/LiveOS/ext3fs.img ]; then
301 FSIMG="/run/initramfs/squashfs/LiveOS/ext3fs.img"
302 fi
303 elif [ -d /run/initramfs/squashfs/proc ]; then
304 FSIMG=$SQUASHED
305 if [ -z "$overlayfs" ]; then
306 overlayfs="yes"
307 [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit=":>/xor_overlayfs;"
308 fi
309 else
310 die "Failed to find a root filesystem in $SQUASHED."
311 exit 1
312 fi
313 else
314 # we might have an embedded fs image to use as rootfs (uncompressed live)
315 if [ -e /run/initramfs/live/${live_dir}/rootfs.img ]; then
316 FSIMG="/run/initramfs/live/${live_dir}/rootfs.img"
317 elif [ -e /run/initramfs/live/${live_dir}/ext3fs.img ]; then
318 FSIMG="/run/initramfs/live/${live_dir}/ext3fs.img"
319 fi
320 if [ -n "$live_ram" ]; then
321 echo 'Copying live image to RAM...' > /dev/kmsg
322 echo ' (this may take a minute or so)' > /dev/kmsg
323 dd if=$FSIMG of=/run/initramfs/rootfs.img bs=512 2> /dev/null
324 echo 'Done copying live image to RAM.' > /dev/kmsg
325 FSIMG='/run/initramfs/rootfs.img'
326 fi
327 fi
328
329 if [ -n "$FSIMG" ]; then
330 if [ -n "$writable_fsimg" ]; then
331 # mount the provided filesystem read/write
332 echo "Unpacking live filesystem (may take some time)" > /dev/kmsg
333 mkdir -m 0755 /run/initramfs/fsimg/
334 if [ -n "$SQUASHED" ]; then
335 cp -v $FSIMG /run/initramfs/fsimg/rootfs.img
336 else
337 unpack_archive $FSIMG /run/initramfs/fsimg/
338 fi
339 FSIMG=/run/initramfs/fsimg/rootfs.img
340 fi
341 opt=-r
342 # For writable DM images...
343 if [ -z "$SQUASHED" -a -n "$live_ram" -a -z "$overlayfs" ] ||
344 [ -n "$writable_fsimg" ] ||
345 [ "$overlay" = none -o "$overlay" = None -o "$overlay" = NONE ]; then
346 if [ -z "$readonly_overlay" ]; then
347 opt=''
348 setup=rw
349 else
350 setup=yes
351 fi
352 fi
353 if [ "$FSIMG" = "$SQUASHED" ]; then
354 BASE_LOOPDEV=$SQUASHED_LOOPDEV
355 else
356 BASE_LOOPDEV=$(losetup -f --show $opt $FSIMG)
357 sz=$(blockdev --getsz $BASE_LOOPDEV)
358 fi
359 if [ "$setup" = rw ]; then
360 echo 0 $sz linear $BASE_LOOPDEV 0 | dmsetup create live-rw
361 else
362 # Add a DM snapshot or OverlayFS for writes.
363 do_live_overlay
364 fi
365 fi
366
367 if [ -b "$OSMIN_LOOPDEV" ]; then
368 # set up the devicemapper snapshot device, which will merge
369 # the normal live fs image, and the delta, into a minimzied fs image
370 echo "0 $sz snapshot $BASE_LOOPDEV $OSMIN_LOOPDEV P 8" | dmsetup create --readonly live-osimg-min
371 fi
372
373 if [ -n "$reloadsysrootmountunit" ]; then
374 eval "$reloadsysrootmountunit"
375 systemctl daemon-reload
376 fi
377
378 ROOTFLAGS="$(getarg rootflags)"
379
380 if [ -n "$overlayfs" ]; then
381 mkdir -m 0755 /run/rootfsbase
382 if [ -n "$reset_overlay" ] && [ -h /run/overlayfs ]; then
383 ovlfs=$(readlink /run/overlayfs)
384 info "Resetting the OverlayFS overlay directory."
385 rm -r -- ${ovlfs}/* ${ovlfs}/.* >/dev/null 2>&1
386 fi
387 if [ -n "$readonly_overlay" ] && [ -h /run/overlayfs-r ]; then
388 ovlfs=lowerdir=/run/overlayfs-r:/run/rootfsbase
389 else
390 ovlfs=lowerdir=/run/rootfsbase
391 fi
392 mount -r $FSIMG /run/rootfsbase
393 if [ -z "$DRACUT_SYSTEMD" ]; then
394 printf 'mount -t overlay LiveOS_rootfs -o%s,%s %s\n' "$ROOTFLAGS" \
395 "$ovlfs",upperdir=/run/overlayfs,workdir=/run/ovlwork \
396 "$NEWROOT" > $hookdir/mount/01-$$-live.sh
397 fi
398 else
399 if [ -z "$DRACUT_SYSTEMD" ]; then
400 [ -n "$ROOTFLAGS" ] && ROOTFLAGS="-o $ROOTFLAGS"
401 printf 'mount %s /dev/mapper/live-rw %s\n' "$ROOTFLAGS" "$NEWROOT" > $hookdir/mount/01-$$-live.sh
402 fi
403 fi
404 [ -e "$SQUASHED" ] && umount -l /run/initramfs/squashfs
405
406 ln -s null /dev/root
407
408 need_shutdown
409
410 exit 0
411