Revert "restore support for old persistence media"
[live-boot-grml.git] / components / 9990-misc-helpers.sh
1 #!/bin/sh
2
3 #set -e
4
5 is_live_path()
6 {
7         DIRECTORY="${1}/${LIVE_MEDIA_PATH}"
8         for FILESYSTEM in squashfs ext2 ext3 ext4 xfs dir jffs
9         do
10                 if ls "${DIRECTORY}/"*.${FILESYSTEM} > /dev/null 2>&1
11                 then
12                         return 0
13                 fi
14         done
15         return 1
16 }
17
18 grml_match_bootid()
19 {
20         path="$1"
21
22         if [ -n "$IGNORE_BOOTID" ] ; then
23                 echo " * Ignoring verification of bootid.txt as requested via ignore_bootid.">>/boot.log
24                 return 0
25         fi
26
27         if [ -n "$BOOTID" ] && ! [ -r "${path}/conf/bootid.txt" ] ; then
28                 echo "  * Warning: bootid=... specified but no bootid.txt found on currently requested device.">>/boot.log
29                 return 1
30         fi
31
32         [ -r "${path}/conf/bootid.txt" ] || return 0
33
34         bootid_conf=$(cat "${path}/conf/bootid.txt")
35
36         if [ -z "$BOOTID" -a -z "$IGNORE_BOOTID" ]
37         then
38                 echo " * Warning: bootid.txt found but ignore_bootid / bootid=.. bootoption missing...">>/boot.log
39                 return 1
40         fi
41
42         if [ "$BOOTID" = "$bootid_conf" ]
43         then
44                 echo " * Successfully verified /conf/bootid.txt from ISO, continuing... ">>/boot.log
45         else
46                 echo " * Warning: BOOTID of ISO does not match. Retrying and continuing search...">>/boot.log
47                 return 1
48         fi
49
50         return 0
51 }
52
53
54 matches_uuid ()
55 {
56         if [ "${IGNORE_UUID}" ] || [ ! -e /conf/uuid.conf ]
57         then
58                 return 0
59         fi
60
61         path="${1}"
62         uuid="$(cat /conf/uuid.conf)"
63
64         for try_uuid_file in "${path}/.disk/live-uuid"*
65         do
66                 [ -e "${try_uuid_file}" ] || continue
67
68                 try_uuid="$(cat "${try_uuid_file}")"
69
70                 if [ "${uuid}" = "${try_uuid}" ]
71                 then
72                         return 0
73                 fi
74         done
75
76         return 1
77 }
78
79 get_backing_device ()
80 {
81         case "${1}" in
82                 *.squashfs|*.ext2|*.ext3|*.ext4|*.jffs2)
83                         echo $(setup_loop "${1}" "loop" "/sys/block/loop*" '0' "${LIVE_MEDIA_ENCRYPTION}" "${2}")
84                         ;;
85
86                 *.dir)
87                         echo "directory"
88                         ;;
89
90                 *)
91                         panic "Unrecognized live filesystem: ${1}"
92                         ;;
93         esac
94 }
95
96 mount_images_in_directory ()
97 {
98         directory="${1}"
99         rootmnt="${2}"
100         mac="${3}"
101
102         if is_live_path "${directory}"
103         then
104                 [ -n "${mac}" ] && adddirectory="${directory}/${LIVE_MEDIA_PATH}/${mac}"
105                 setup_unionfs "${directory}/${LIVE_MEDIA_PATH}" "${rootmnt}" "${adddirectory}"
106         else
107                 panic "No supported filesystem images found at /${LIVE_MEDIA_PATH}."
108         fi
109 }
110
111 is_nice_device ()
112 {
113         sysfs_path="${1#/sys}"
114
115         if udevadm info --query=all --path="${sysfs_path}" | egrep -q "DEVTYPE=disk"
116         then
117                 return 0
118         elif echo "${sysfs_path}" | grep -q '^/block/vd[a-z]$'
119         then
120                 return 0
121         elif echo ${sysfs_path} | grep -q "^/block/dm-"
122         then
123                 return 0
124         elif echo ${sysfs_path} | grep -q "^/block/mtdblock"
125         then
126                 return 0
127         fi
128
129         return 1
130 }
131
132 check_dev ()
133 {
134         sysdev="${1}"
135         devname="${2}"
136         skip_uuid_check="${3}"
137
138         # support for fromiso=.../isofrom=....
139         if [ -n "$FROMISO" ]
140         then
141                 ISO_DEVICE=$(dirname $FROMISO)
142                 if ! [ -b $ISO_DEVICE ]
143                 then
144                         # to support unusual device names like /dev/cciss/c0d0p1
145                         # as well we have to identify the block device name, let's
146                         # do that for up to 15 levels
147                         i=15
148                         while [ -n "$ISO_DEVICE" ] && [ "$i" -gt 0 ]
149                         do
150                                 ISO_DEVICE=$(dirname ${ISO_DEVICE})
151                                 [ -b "$ISO_DEVICE" ] && break
152                                 i=$(($i -1))
153                         done
154                 fi
155
156                 if [ "$ISO_DEVICE" = "/" ]
157                 then
158                         echo "Warning: device for bootoption fromiso= ($FROMISO) not found.">>/boot.log
159                 else
160                         fs_type=$(get_fstype "${ISO_DEVICE}")
161                         if is_supported_fs ${fs_type}
162                         then
163                                 mkdir /live/fromiso
164                                 mount -t $fs_type "$ISO_DEVICE" /live/fromiso
165                                 ISO_NAME="$(echo $FROMISO | sed "s|$ISO_DEVICE||")"
166                                 loopdevname=$(setup_loop "/live/fromiso/${ISO_NAME}" "loop" "/sys/block/loop*" "" '')
167                                 devname="${loopdevname}"
168                         else
169                                 echo "Warning: unable to mount $ISO_DEVICE." >>/boot.log
170                         fi
171                 fi
172         fi
173
174         if [ -z "${devname}" ]
175         then
176                 devname=$(sys2dev "${sysdev}")
177         fi
178
179         if [ -d "${devname}" ]
180         then
181                 mount -o bind "${devname}" $mountpoint || continue
182
183                 if is_live_path $mountpoint
184                 then
185                         echo $mountpoint
186                         return 0
187                 else
188                         umount $mountpoint
189                 fi
190         fi
191
192         IFS=","
193         for device in ${devname}
194         do
195                 case "$device" in
196                         *mapper*)
197                                 # Adding lvm support
198                                 if [ -x /scripts/local-top/lvm2 ]
199                                 then
200                                         ROOT="$device" resume="" /scripts/local-top/lvm2 >>/boot.log
201                                 fi
202                                 ;;
203
204                         /dev/md*)
205                                 # Adding raid support
206                                 if [ -x /scripts/local-top/mdadm ]
207                                 then
208                                         [ -r /conf/conf.d/md ] && cp /conf/conf.d/md /conf/conf.d/md.orig
209                                         echo "MD_DEVS=$device " >> /conf/conf.d/md
210                                         /scripts/local-top/mdadm >>/boot.log
211                                         [ -r /conf/conf.d/md.orig ] && mv /conf/conf.d/md.orig /conf/conf.d/md
212                                 fi
213                                 ;;
214                 esac
215         done
216         unset IFS
217
218         [ -n "$device" ] && devname="$device"
219
220         [ -e "$devname" ] || continue
221
222         if [ -n "${LIVE_MEDIA_OFFSET}" ]
223         then
224                 loopdevname=$(setup_loop "${devname}" "loop" "/sys/block/loop*" "${LIVE_MEDIA_OFFSET}" '')
225                 devname="${loopdevname}"
226         fi
227
228         fstype=$(get_fstype "${devname}")
229
230         if is_supported_fs ${fstype}
231         then
232                 devuid=$(blkid -o value -s UUID "$devname")
233                 [ -n "$devuid" ] && grep -qs "\<$devuid\>" /var/lib/live/boot/devices-already-tried-to-mount && continue
234                 mount -t ${fstype} -o ro,noatime "${devname}" ${mountpoint} || continue
235                 [ -n "$devuid" ] && echo "$devuid" >> /var/lib/live/boot/devices-already-tried-to-mount
236
237                 if [ -n "${FINDISO}" ]
238                 then
239                         if [ -f ${mountpoint}/${FINDISO} ]
240                         then
241                                 umount ${mountpoint}
242                                 mkdir -p /live/findiso
243                                 mount -t ${fstype} -o ro,noatime "${devname}" /live/findiso
244                                 loopdevname=$(setup_loop "/live/findiso/${FINDISO}" "loop" "/sys/block/loop*" 0 "")
245                                 devname="${loopdevname}"
246                                 mount -t iso9660 -o ro,noatime "${devname}" ${mountpoint}
247                         else
248                                 umount ${mountpoint}
249                         fi
250                 fi
251
252                 if is_live_path ${mountpoint} && \
253                         ([ "${skip_uuid_check}" ] || grml_match_bootid ${mountpoint})
254                 then
255                         echo ${mountpoint}
256                         return 0
257                 else
258                         umount ${mountpoint} 2>/dev/null
259                 fi
260         fi
261
262         if [ -n "${LIVE_MEDIA_OFFSET}" ]
263         then
264                 losetup -d "${loopdevname}"
265         fi
266
267         return 1
268 }
269
270 find_livefs ()
271 {
272         timeout="${1}"
273
274         # don't start autodetection before timeout has expired
275         if [ -n "${LIVE_MEDIA_TIMEOUT}" ]
276         then
277                 if [ "${timeout}" -lt "${LIVE_MEDIA_TIMEOUT}" ]
278                 then
279                         return 1
280                 fi
281         fi
282
283         # first look at the one specified in the command line
284         case "${LIVE_MEDIA}" in
285                 removable-usb)
286                         for sysblock in $(removable_usb_dev "sys")
287                         do
288                                 for dev in $(subdevices "${sysblock}")
289                                 do
290                                         if check_dev "${dev}"
291                                         then
292                                                 return 0
293                                         fi
294                                 done
295                         done
296                         return 1
297                         ;;
298
299                 removable)
300                         for sysblock in $(removable_dev "sys")
301                         do
302                                 for dev in $(subdevices "${sysblock}")
303                                 do
304                                         if check_dev "${dev}"
305                                         then
306                                                 return 0
307                                         fi
308                                 done
309                         done
310                         return 1
311                         ;;
312
313                 *)
314                         if [ ! -z "${LIVE_MEDIA}" ]
315                         then
316                                 if check_dev "null" "${LIVE_MEDIA}" "skip_uuid_check"
317                                 then
318                                         return 0
319                                 fi
320                         fi
321                         ;;
322         esac
323
324         # or do the scan of block devices
325         # prefer removable devices over non-removable devices, so scan them first
326         devices_to_scan="$(removable_dev 'sys') $(non_removable_dev 'sys')"
327
328         for sysblock in $devices_to_scan
329         do
330                 devname=$(sys2dev "${sysblock}")
331                 [ -e "$devname" ] || continue
332                 fstype=$(get_fstype "${devname}")
333
334                 if /lib/udev/cdrom_id ${devname} > /dev/null
335                 then
336                         if check_dev "null" "${devname}"
337                         then
338                                 return 0
339                         fi
340                 elif is_nice_device "${sysblock}"
341                 then
342                         for dev in $(subdevices "${sysblock}")
343                         do
344                                 if check_dev "${dev}"
345                                 then
346                                         return 0
347                                 fi
348                         done
349                 fi
350         done
351
352         return 1
353 }
354
355 is_in_list_separator_helper ()
356 {
357         local sep element list
358         sep=${1}
359         shift
360         element=${1}
361         shift
362         list=${*}
363         echo ${list} | grep -qe "^\(.*${sep}\)\?${element}\(${sep}.*\)\?$"
364 }
365
366 is_in_space_sep_list ()
367 {
368         local element
369         element=${1}
370         shift
371         is_in_list_separator_helper "[[:space:]]" "${element}" "${*}"
372 }
373
374 is_in_comma_sep_list ()
375 {
376         local element
377         element=${1}
378         shift
379         is_in_list_separator_helper "," "${element}" "${*}"
380 }
381
382 sys2dev ()
383 {
384         sysdev=${1#/sys}
385         echo "/dev/$(udevadm info -q name -p ${sysdev} 2>/dev/null|| echo ${sysdev##*/})"
386 }
387
388 subdevices ()
389 {
390         sysblock=${1}
391         r=""
392
393         for dev in "${sysblock}"/* "${sysblock}"
394         do
395                 if [ -e "${dev}/dev" ]
396                 then
397                         r="${r} ${dev}"
398                 fi
399         done
400
401         echo ${r}
402 }
403
404 storage_devices()
405 {
406         black_listed_devices="${1}"
407         white_listed_devices="${2}"
408
409         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "loop|ram|fd")
410         do
411                 fulldevname=$(sys2dev "${sysblock}")
412
413                 if is_in_space_sep_list ${fulldevname} ${black_listed_devices} || \
414                         [ -n "${white_listed_devices}" ] && \
415                         ! is_in_space_sep_list ${fulldevname} ${white_listed_devices}
416                 then
417                         # skip this device entirely
418                         continue
419                 fi
420
421                 for dev in $(subdevices "${sysblock}")
422                 do
423                         devname=$(sys2dev "${dev}")
424
425                         if is_in_space_sep_list ${devname} ${black_listed_devices}
426                         then
427                                 # skip this subdevice
428                                 continue
429                         else
430                                 echo "${devname}"
431                         fi
432                 done
433         done
434 }
435
436 is_supported_fs ()
437 {
438         fstype="${1}"
439
440         # Validate input first
441         if [ -z "${fstype}" ]
442         then
443                 return 1
444         fi
445
446         # get_fstype might report "unknown" or "swap", ignore it as no such kernel module exists
447         if [ "${fstype}" = "unknown" ] || [ "${fstype}" = "swap" ]
448         then
449                 return 1
450         fi
451
452         # Try to look if it is already supported by the kernel
453         if grep -q ${fstype} /proc/filesystems
454         then
455                 return 0
456         else
457                 # Then try to add support for it the gentle way using the initramfs capabilities
458                 modprobe -q -b ${fstype}
459                 if grep -q ${fstype} /proc/filesystems
460                 then
461                         return 0
462                 # Then try the hard way if /root is already reachable
463                 else
464                         kmodule="/root/lib/modules/`uname -r`/${fstype}/${fstype}.ko"
465                         if [ -e "${kmodule}" ]
466                         then
467                                 insmod "${kmodule}"
468                                 if grep -q ${fstype} /proc/filesystems
469                                 then
470                                         return 0
471                                 fi
472                         fi
473                 fi
474         fi
475
476         return 1
477 }
478
479 get_fstype ()
480 {
481         /sbin/blkid -s TYPE -o value $1 2>/dev/null
482 }
483
484 where_is_mounted ()
485 {
486         device=${1}
487         # return first found
488         grep -m1 "^${device} " /proc/mounts | cut -f2 -d ' '
489 }
490
491 trim_path ()
492 {
493         # remove all unnecessary /:s in the path, including last one (except
494         # if path is just "/")
495         echo ${1} | sed 's|//\+|/|g' | sed 's|^\(.*[^/]\)/$|\1|'
496 }
497
498 what_is_mounted_on ()
499 {
500         local dir
501         dir="$(trim_path ${1})"
502         grep -m1 "^[^ ]\+ ${dir} " /proc/mounts | cut -d' ' -f1
503 }
504
505 chown_ref ()
506 {
507         local reference targets owner
508         reference="${1}"
509         shift
510         targets=${@}
511         owner=$(stat -c %u:%g "${reference}")
512         chown -h ${owner} ${targets}
513 }
514
515 chmod_ref ()
516 {
517         local reference targets rights
518         reference="${1}"
519         shift
520         targets=${@}
521         rights=$(stat -c %a "${reference}")
522         chmod ${rights} ${targets}
523 }
524
525 lastline ()
526 {
527         while read lines
528         do
529                 line=${lines}
530         done
531
532         echo "${line}"
533 }
534
535 base_path ()
536 {
537         testpath="${1}"
538         mounts="$(awk '{print $2}' /proc/mounts)"
539         testpath="$(busybox realpath ${testpath})"
540
541         while true
542         do
543                 if echo "${mounts}" | grep -qs "^${testpath}"
544                 then
545                         set -- $(echo "${mounts}" | grep "^${testpath}" | lastline)
546                         echo ${1}
547                         break
548                 else
549                         testpath=$(dirname $testpath)
550                 fi
551         done
552 }
553
554 fs_size ()
555 {
556         # Returns used/free fs kbytes + 5% more
557         # You could pass a block device as ${1} or the mount point as ${2}
558
559         dev="${1}"
560         mountp="${2}"
561         used="${3}"
562
563         if [ -z "${mountp}" ]
564         then
565                 mountp="$(where_is_mounted ${dev})"
566
567                 if [ -z "${mountp}" ]
568                 then
569                         mountp="/mnt/tmp_fs_size"
570
571                         mkdir -p "${mountp}"
572                         mount -t $(get_fstype "${dev}") -o ro "${dev}" "${mountp}" || log_warning_msg "cannot mount -t $(get_fstype ${dev}) -o ro ${dev} ${mountp}"
573
574                         doumount=1
575                 fi
576         fi
577
578         if [ "${used}" = "used" ]
579         then
580                 size=$(du -ks ${mountp} | cut -f1)
581                 size=$(expr ${size} + ${size} / 20 ) # FIXME: 5% more to be sure
582         else
583                 # free space
584                 size="$(df -kP | grep -s ${mountp} | awk '{print $4}')"
585         fi
586
587         if [ -n "${doumount}" ]
588         then
589                 umount "${mountp}" || log_warning_msg "cannot umount ${mountp}"
590                 rmdir "${mountp}"
591         fi
592
593         echo "${size}"
594 }
595
596 load_keymap ()
597 {
598         # Load custom keymap
599         if [ -x /bin/loadkeys -a -r /etc/boottime.kmap.gz ]
600         then
601                 loadkeys --quiet /etc/boottime.kmap.gz
602         fi
603 }
604
605 setup_loop ()
606 {
607         local fspath module pattern offset encryption readonly
608         fspath=${1}
609         module=${2}
610         pattern=${3}
611         offset=${4}
612         encryption=${5}
613         readonly=${6}
614
615         # the output of setup_loop is evaluated in other functions,
616         # modprobe leaks kernel options like "libata.dma=0"
617         # as "options libata dma=0" on stdout, causing serious
618         # problems therefor, so instead always avoid output to stdout
619         modprobe -q -b "${module}" 1>/dev/null
620
621         udevadm settle
622
623         for loopdev in ${pattern}
624         do
625                 if [ "$(cat ${loopdev}/size)" -eq 0 ]
626                 then
627                         dev=$(sys2dev "${loopdev}")
628                         options=''
629
630                         if [ -n "${readonly}" ]
631                         then
632                                 if losetup --help 2>&1 | grep -q -- "-r\b"
633                                 then
634                                         options="${options} -r"
635                                 fi
636                         fi
637
638                         if [ -n "${offset}" ] && [ 0 -lt "${offset}" ]
639                         then
640                                 options="${options} -o ${offset}"
641                         fi
642
643                         if [ -z "${encryption}" ]
644                         then
645                                 losetup ${options} "${dev}" "${fspath}"
646                         else
647                                 # Loop AES encryption
648                                 while true
649                                 do
650                                         load_keymap
651
652                                         echo -n "Enter passphrase for root filesystem: " >&6
653                                         read -s passphrase
654                                         echo "${passphrase}" > /tmp/passphrase
655                                         unset passphrase
656                                         exec 9</tmp/passphrase
657                                         /sbin/losetup ${options} -e "${encryption}" -p 9 "${dev}" "${fspath}"
658                                         error=${?}
659                                         exec 9<&-
660                                         rm -f /tmp/passphrase
661
662                                         if [ 0 -eq ${error} ]
663                                         then
664                                                 unset error
665                                                 break
666                                         fi
667
668                                         echo
669                                         echo -n "There was an error decrypting the root filesystem ... Retry? [Y/n] " >&6
670                                         read answer
671
672                                         if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
673                                         then
674                                                 unset answer
675                                                 break
676                                         fi
677                                 done
678                         fi
679
680                         echo "${dev}"
681                         return 0
682                 fi
683         done
684
685         panic "No loop devices available"
686 }
687
688 try_mount ()
689 {
690         dev="${1}"
691         mountp="${2}"
692         opts="${3}"
693         fstype="${4}"
694
695         old_mountp="$(where_is_mounted ${dev})"
696
697         if [ -n "${old_mountp}" ]
698         then
699                 if [ "${opts}" != "ro" ]
700                 then
701                         mount -o remount,"${opts}" "${dev}" "${old_mountp}" || panic "Remounting ${dev} ${opts} on ${old_mountp} failed"
702                 fi
703
704                 mount -o bind "${old_mountp}" "${mountp}" || panic "Cannot bind-mount ${old_mountp} on ${mountp}"
705         else
706                 if [ -z "${fstype}" ]
707                 then
708                         fstype=$(get_fstype "${dev}")
709                 fi
710                 mount -t "${fstype}" -o "${opts}" "${dev}" "${mountp}" || \
711                 ( echo "SKIPPING: Cannot mount ${dev} on ${mountp}, fstype=${fstype}, options=${opts}" > boot.log && return 0 )
712         fi
713 }
714
715 # Try to mount $device to the place expected by live-boot. If $device
716 # is already mounted somewhere, move it to the expected place. If $device
717 # ends with a "/" this is a directory path.
718 # If we're only probing $device (to check if it has custom persistence)
719 # $probe should be set, which suppresses warnings upon failure. On
720 # success, print the mount point for $device.
721 mount_persistence_media ()
722 {
723         local device probe backing old_backing fstype mount_opts
724         device=${1}
725         probe=${2}
726
727         # get_custom_mounts() might call this with a directory path instead
728         # of a block device path. This means we have found sub-directory path
729         # underneath /lib/live/mounts/persistence, so we're done
730         if [ -d "${device}" ]
731         then
732                 echo "${device}"
733                 return 0
734         fi
735
736         if [ ! -b "${device}" ]
737         then
738                 return 1
739         fi
740
741         backing="/live/persistence/$(basename ${device})"
742
743         mkdir -p "${backing}"
744         old_backing="$(where_is_mounted ${device})"
745         if [ -z "${old_backing}" ]
746         then
747                 fstype="$(get_fstype ${device})"
748                 mount_opts="rw,noatime"
749                 if [ -n "${PERSISTENCE_READONLY}" ]
750                 then
751                         mount_opts="ro,noatime"
752                 fi
753                 if mount -t "${fstype}" -o "${mount_opts}" "${device}" "${backing}" >/dev/null
754                 then
755                         echo ${backing}
756                         return 0
757                 else
758                         [ -z "${probe}" ] && log_warning_msg "Failed to mount persistence media ${device}"
759                         rmdir "${backing}"
760                         return 1
761                 fi
762         elif [ "${backing}" != "${old_backing}" ]
763         then
764                 if ! mount --move ${old_backing} ${backing} >/dev/null
765                 then
766                         [ -z "${probe}" ] && log_warning_msg "Failed to move persistence media ${device}"
767                         rmdir "${backing}"
768                         return 1
769                 fi
770                 mount_opts="rw,noatime"
771                 if [ -n "${PERSISTENCE_READONLY}" ]
772                 then
773                         mount_opts="ro,noatime"
774                 fi
775                 if ! mount -o "remount,${mount_opts}" "${backing}" >/dev/null
776                 then
777                         log_warning_msg "Failed to remount persistence media ${device} writable"
778                         # Don't unmount or rmdir the new mountpoint in this case
779                 fi
780                 echo ${backing}
781                 return 0
782         else
783                 # This means that $device has already been mounted on
784                 # the place expected by live-boot, so we're done.
785                 echo ${backing}
786                 return 0
787         fi
788 }
789
790 close_persistence_media ()
791 {
792         local device backing
793         device=${1}
794         backing="$(where_is_mounted ${device})"
795
796         if [ -d "${backing}" ]
797         then
798                 umount "${backing}" >/dev/null 2>&1
799                 rmdir "${backing}" >/dev/null 2>&1
800         fi
801
802         if is_active_luks_mapping ${device}
803         then
804                 /sbin/cryptsetup luksClose ${device}
805         fi
806 }
807
808 open_luks_device ()
809 {
810         dev="${1}"
811         name="$(basename ${dev})"
812         opts="--key-file=-"
813         if [ -n "${PERSISTENCE_READONLY}" ]
814         then
815                 opts="${opts} --readonly"
816         fi
817
818         if /sbin/cryptsetup status "${name}" >/dev/null 2>&1
819         then
820                 re="^[[:space:]]*device:[[:space:]]*\([^[:space:]]*\)$"
821                 opened_dev=$(cryptsetup status ${name} 2>/dev/null | grep "${re}" | sed "s|${re}|\1|")
822                 if [ "${opened_dev}" = "${dev}" ]
823                 then
824                         luks_device="/dev/mapper/${name}"
825                         echo ${luks_device}
826                         return 0
827                 else
828                         log_warning_msg "Cannot open luks device ${dev} since ${opened_dev} already is opened with its name"
829                         return 1
830                 fi
831         fi
832
833         load_keymap
834
835         # check for plymouth
836         if [ -x /bin/plymouth ]
837         then
838                 _PLYMOUTH="true"
839         fi
840
841         case "${_PLYMOUTH}" in
842                 true)
843                         plymouth --ping
844
845                         cryptkeyscript="plymouth ask-for-password --prompt"
846                         # Plymouth will add a : if it is a non-graphical prompt
847                         cryptkeyprompt="Please unlock disk ${dev}"
848                         ;;
849
850                 *)
851                         cryptkeyscript="/lib/cryptsetup/askpass"
852                         cryptkeyprompt="Please unlock disk ${dev}: "
853                         ;;
854         esac
855
856         while true
857         do
858                 $cryptkeyscript "$cryptkeyprompt" | \
859                         /sbin/cryptsetup -T 1 luksOpen ${dev} ${name} ${opts}
860
861                 if [ 0 -eq ${?} ]
862                 then
863                         luks_device="/dev/mapper/${name}"
864                         echo ${luks_device}
865                         return 0
866                 fi
867
868                 echo >&6
869                 retryprompt="There was an error decrypting ${dev} ... Retry? [Y/n]"
870
871                 case "${_PLYMOUTH}" in
872                         true)
873                                 plymouth display-message --text "${retryprompt}"
874                                 answer=$(plymouth watch-keystroke --keys="YNyn")
875                                 ;;
876
877                         *)
878                                 echo -n "${retryprompt} " >&6
879                                 read answer
880                                 ;;
881                 esac
882
883                 if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
884                 then
885                         case "${_PLYMOUTH}" in
886                                 true)
887                                         plymouth display-message --text ""
888                                         ;;
889                         esac
890
891                         return 2
892                 fi
893         done
894 }
895
896 get_gpt_name ()
897 {
898     local dev
899     dev="${1}"
900     /sbin/blkid -s PART_ENTRY_NAME -p -o value ${dev} 2>/dev/null
901 }
902
903 is_gpt_device ()
904 {
905     local dev
906     dev="${1}"
907     [ "$(/sbin/blkid -s PART_ENTRY_SCHEME -p -o value ${dev} 2>/dev/null)" = "gpt" ]
908 }
909
910 probe_for_gpt_name ()
911 {
912         local overlays dev gpt_dev gpt_name
913         overlays="${1}"
914         dev="${2}"
915
916         gpt_dev="${dev}"
917         if is_active_luks_mapping ${dev}
918         then
919                 # if $dev is an opened luks device, we need to check
920                 # GPT stuff on the backing device
921                 gpt_dev=$(get_luks_backing_device "${dev}")
922         fi
923
924         if ! is_gpt_device ${gpt_dev}
925         then
926                 return
927         fi
928
929         gpt_name=$(get_gpt_name ${gpt_dev})
930         for label in ${overlays}
931         do
932                 if [ "${gpt_name}" = "${label}" ]
933                 then
934                         echo "${label}=${dev}"
935                 fi
936         done
937 }
938
939 probe_for_fs_label ()
940 {
941         local overlays dev
942         overlays="${1}"
943         dev="${2}"
944
945         for label in ${overlays}
946         do
947                 if [ "$(/sbin/blkid -s LABEL -o value $dev 2>/dev/null)" = "${label}" ]
948                 then
949                         echo "${label}=${dev}"
950                 fi
951         done
952 }
953
954 probe_for_file_name ()
955 {
956         local overlays dev ret backing
957         overlays="${1}"
958         dev="${2}"
959
960         ret=""
961         backing="$(mount_persistence_media ${dev} probe)"
962         if [ -z "${backing}" ]
963         then
964             return
965         fi
966
967         for label in ${overlays}
968         do
969                 path=${backing}/${PERSISTENCE_PATH}/${label}
970                 if [ -f "${path}" ]
971                 then
972                         local loopdev
973                         loopdev=$(setup_loop "${path}" "loop" "/sys/block/loop*")
974                         ret="${ret} ${label}=${loopdev}"
975                 fi
976         done
977
978         if [ -n "${ret}" ]
979         then
980                 echo ${ret}
981         else
982                 # unmount and remove mountpoint
983                 umount ${backing} > /dev/null 2>&1 || true
984                 rmdir ${backing} > /dev/null 2>&1 || true
985         fi
986 }
987
988 probe_for_directory_name ()
989 {
990         local overlays dev ret backing
991         overlays="${1}"
992         dev="${2}"
993
994         ret=""
995         backing="$(mount_persistence_media ${dev} probe)"
996         if [ -z "${backing}" ]
997         then
998             return
999         fi
1000
1001         for label in ${overlays}
1002         do
1003                 path=${backing}/${PERSISTENCE_PATH}/${label}
1004                 if [ -d "${path}" ]
1005                 then
1006                         # in this case the "device" ends with a "/"
1007                         ret="${ret} ${label}=${backing}/${PERSISTENCE_PATH}/${label%%/}/"
1008                 fi
1009         done
1010
1011         if [ -n "${ret}" ]
1012         then
1013                 echo ${ret}
1014         else
1015                 # unmount and remove mountpoint
1016                 umount ${backing} > /dev/null 2>&1 || true
1017                 rmdir ${backing} > /dev/null 2>&1 || true
1018         fi
1019 }
1020
1021 find_persistence_media ()
1022 {
1023         # Scans devices for overlays, and returns a whitespace
1024         # separated list of how to use them. Only overlays with a partition
1025         # label or file name in ${overlays} are returned.
1026         #
1027         # When scanning a LUKS device, the user will be asked to enter the
1028         # passphrase; on failure to enter it, or if no persistence partitions
1029         # or files were found, the LUKS device is closed.
1030         #
1031         # For all other cases (overlay partition and overlay file) the
1032         # return value is "${label}=${device}", where ${device} a device that
1033         # can mount the content. In the case of an overlay file, the device
1034         # containing the file will remain mounted as a side-effect.
1035         #
1036         # No devices in ${black_listed_devices} will be scanned, and if
1037         # ${white_list_devices} is non-empty, only devices in it will be
1038         # scanned.
1039
1040         local overlays white_listed_devices ret black_listed_devices
1041         overlays="${1}"
1042         white_listed_devices="${2}"
1043         ret=""
1044
1045         #
1046         # The devices that are hosting the actual live rootfs should not be
1047         # used for persistence storage since otherwise you might mount a
1048         # parent directory on top of a sub-directory of the same filesystem
1049         # in one union together.
1050         #
1051         black_listed_devices=""
1052         for d in /live/rootfs/* /live/findiso /live/fromiso
1053         do
1054                 black_listed_devices="${black_listed_devices} $(what_is_mounted_on d)"
1055         done
1056
1057         for dev in $(storage_devices "${black_listed_devices}" "${white_listed_devices}")
1058         do
1059                 local result luks_device
1060                 result=""
1061
1062                 luks_device=""
1063                 # Check if it's a luks device; we'll have to open the device
1064                 # in order to probe any filesystem it contains, like we do
1065                 # below. activate_custom_mounts() also depends on that any luks
1066                 # device already has been opened.
1067                 if is_in_comma_sep_list luks ${PERSISTENCE_ENCRYPTION} && is_luks_partition ${dev}
1068                 then
1069                         if luks_device=$(open_luks_device "${dev}")
1070                         then
1071                                 dev="${luks_device}"
1072                         else
1073                                 # skip $dev since we failed/chose not to open it
1074                                 continue
1075                         fi
1076                 elif ! is_in_comma_sep_list none ${PERSISTENCE_ENCRYPTION}
1077                 then
1078                         # skip $dev since we don't allow unencrypted storage
1079                         continue
1080                 fi
1081
1082                 # Probe for matching GPT partition names or filesystem labels
1083                 if is_in_comma_sep_list filesystem ${PERSISTENCE_STORAGE}
1084                 then
1085                         result=$(probe_for_gpt_name "${overlays}" ${dev})
1086                         if [ -n "${result}" ]
1087                         then
1088                                 ret="${ret} ${result}"
1089                                 continue
1090                         fi
1091
1092                         result=$(probe_for_fs_label "${overlays}" ${dev})
1093                         if [ -n "${result}" ]
1094                         then
1095                                 ret="${ret} ${result}"
1096                                 continue
1097                         fi
1098                 fi
1099
1100                 # Probe for files with matching name on mounted partition
1101                 if is_in_comma_sep_list file ${PERSISTENCE_STORAGE}
1102                 then
1103                         result=$(probe_for_file_name "${overlays}" ${dev})
1104                         if [ -n "${result}" ]
1105                         then
1106                                 local loopdevice
1107                                 loopdevice=${result##*=}
1108                                 if is_in_comma_sep_list luks ${PERSISTENCE_ENCRYPTION} && is_luks_partition ${loopdevice}
1109                                 then
1110                                         local luksfile
1111                                         luksfile=""
1112                                         if luksfile=$(open_luks_device "${loopdevice}")
1113                                         then
1114                                                 result=${result%%=*}
1115                                                 result="${result}=${luksfile}"
1116                                         else
1117                                                 losetup -d $loopdevice
1118                                                 result=""
1119                                         fi
1120                                 fi
1121                                 ret="${ret} ${result}"
1122                                 continue
1123                         fi
1124                 fi
1125
1126                 # Probe for directory with matching name on mounted partition
1127                 if is_in_comma_sep_list directory ${PERSISTENCE_STORAGE}
1128                 then
1129                         result=$(probe_for_directory_name "${overlays}" ${dev})
1130                         if [ -n "${result}" ]
1131                         then
1132                                 ret="${ret} ${result}"
1133                                 continue
1134                         fi
1135                 fi
1136
1137                 # Close luks device if it isn't used
1138                 if [ -z "${result}" ] && [ -n "${luks_device}" ] && is_active_luks_mapping "${luks_device}"
1139                 then
1140                         /sbin/cryptsetup luksClose "${luks_device}"
1141                 fi
1142         done
1143
1144         if [ -n "${ret}" ]
1145         then
1146                 echo ${ret}
1147         fi
1148 }
1149
1150 get_mac ()
1151 {
1152         mac=""
1153
1154         for adaptor in /sys/class/net/*
1155         do
1156                 status="$(cat ${adaptor}/iflink)"
1157
1158                 if [ "${status}" -eq 2 ]
1159                 then
1160                         mac="$(cat ${adaptor}/address)"
1161                         mac="$(echo ${mac} | sed 's/:/-/g' | tr '[a-z]' '[A-Z]')"
1162                 fi
1163         done
1164
1165         echo ${mac}
1166 }
1167
1168 is_luks_partition ()
1169 {
1170         device="${1}"
1171         /sbin/cryptsetup isLuks "${device}" 1>/dev/null 2>&1
1172 }
1173
1174 is_active_luks_mapping ()
1175 {
1176         device="${1}"
1177         /sbin/cryptsetup status "${device}" 1>/dev/null 2>&1
1178 }
1179
1180 get_luks_backing_device ()
1181 {
1182         device=${1}
1183         cryptsetup status ${device} 2> /dev/null | \
1184                 awk '{if ($1 == "device:") print $2}'
1185 }
1186
1187 removable_dev ()
1188 {
1189         output_format="${1}"
1190         want_usb="${2}"
1191         ret=
1192
1193         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)")
1194         do
1195                 dev_ok=
1196                 if [ "$(cat ${sysblock}/removable)" = "1" ]
1197                 then
1198                         if [ -z "${want_usb}" ]
1199                         then
1200                                 dev_ok="true"
1201                         else
1202                                 if readlink ${sysblock} | grep -q usb
1203                                 then
1204                                         dev_ok="true"
1205                                 fi
1206                         fi
1207                 fi
1208
1209                 if [ "${dev_ok}" = "true" ]
1210                 then
1211                         case "${output_format}" in
1212                                 sys)
1213                                         ret="${ret} ${sysblock}"
1214                                         ;;
1215                                 *)
1216                                         devname=$(sys2dev "${sysblock}")
1217                                         ret="${ret} ${devname}"
1218                                         ;;
1219                         esac
1220                 fi
1221         done
1222
1223         echo "${ret}"
1224 }
1225
1226 removable_usb_dev ()
1227 {
1228         output_format="${1}"
1229
1230         removable_dev "${output_format}" "want_usb"
1231 }
1232
1233 non_removable_dev ()
1234 {
1235         output_format="${1}"
1236         ret=
1237
1238         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)")
1239         do
1240                 if [ "$(cat ${sysblock}/removable)" = "0" ]
1241                 then
1242                         case "${output_format}" in
1243                                 sys)
1244                                         ret="${ret} ${sysblock}"
1245                                         ;;
1246                                 *)
1247                                         devname=$(sys2dev "${sysblock}")
1248                                         ret="${ret} ${devname}"
1249                                         ;;
1250                         esac
1251                 fi
1252         done
1253
1254         echo "${ret}"
1255 }
1256
1257 link_files ()
1258 {
1259         # create source's directory structure in dest, and recursively
1260         # create symlinks in dest to to all files in source. if mask
1261         # is non-empty, remove mask from all source paths when
1262         # creating links (will be necessary if we change root, which
1263         # live-boot normally does (into $rootmnt)).
1264         local src_dir dest_dir src_transform
1265
1266         # remove multiple /:s and ensure ending on /
1267         src_dir="$(trim_path ${1})/"
1268         dest_dir="$(trim_path ${2})/"
1269         src_transform="${3}"
1270
1271         # This check can only trigger on the inital, non-recursive call since
1272         # we create the destination before recursive calls
1273         if [ ! -d "${dest_dir}" ]
1274         then
1275                 log_warning_msg "Must link_files into a directory"
1276                 return
1277         fi
1278
1279         find "${src_dir}" -mindepth 1 -maxdepth 1 | \
1280         while read src
1281         do
1282                 local dest final_src
1283                 dest="${dest_dir}$(basename "${src}")"
1284                 if [ -d "${src}" ]
1285                 then
1286                         if [ -z "$(ls -A "${src}")" ]
1287                         then
1288                                 continue
1289                         fi
1290                         if [ ! -d "${dest}" ]
1291                         then
1292                                 mkdir -p "${dest}"
1293                                 chown_ref "${src}" "${dest}"
1294                                 chmod_ref "${src}" "${dest}"
1295                         fi
1296                         link_files "${src}" "${dest}" "${src_transform}"
1297                 else
1298                         final_src=${src}
1299                         if [ -n "${src_transform}" ]
1300                         then
1301                                 final_src="$(echo ${final_src} | sed "${src_transform}")"
1302                         fi
1303                         rm -rf "${dest}" 2> /dev/null
1304                         ln -s "${final_src}" "${dest}"
1305                         chown_ref "${src}" "${dest}"
1306                 fi
1307         done
1308 }
1309
1310 do_union ()
1311 {
1312         local unionmountpoint unionrw unionro
1313         unionmountpoint="${1}"  # directory where the union is mounted
1314         shift
1315         unionrw="${1}"          # branch where the union changes are stored
1316         shift
1317         unionro="${*}"          # space separated list of read-only branches (optional)
1318
1319         case "${UNIONTYPE}" in
1320                 aufs)
1321                         rw_opt="rw"
1322                         ro_opt="rr+wh"
1323                         noxino_opt="noxino"
1324
1325                         unionmountopts="-o noatime,${noxino_opt},dirs=${unionrw}=${rw_opt}"
1326                         if [ -n "${unionro}" ]
1327                         then
1328                                 for rofs in ${unionro}
1329                                 do
1330                                         unionmountopts="${unionmountopts}:${rofs}=${ro_opt}"
1331                                 done
1332                         fi
1333                         ;;
1334
1335                 overlay)
1336                         # XXX: can multiple unionro be used? (overlay only handles two dirs, but perhaps they can be chained?)
1337                         # XXX: and can unionro be optional? i.e. can overlay skip lowerdir?
1338                         if echo ${unionro} | grep -q " "
1339                         then
1340                                 panic "Multiple lower filesystems are currently not supported with overlay (unionro = ${unionro})."
1341                         elif [ -z "${unionro}"  ]
1342                         then
1343                                 panic "overlay needs at least one lower filesystem (read-only branch)."
1344                         fi
1345                         # overlayfs requires:
1346                         # + a workdir to become mounted
1347                         # + workdir and upperdir to reside under the same mount
1348                         # + workdir and upperdir to be in separate directories
1349                         mkdir "${unionrw}/rw"
1350                         mkdir "${unionrw}/work"
1351                         unionmountopts="-o noatime,lowerdir=${unionro},upperdir=${unionrw}/rw,workdir=${unionrw}/work"
1352                         ;;
1353         esac
1354
1355         mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
1356 }
1357
1358 get_custom_mounts ()
1359 {
1360         # Side-effect: leaves $devices with persistence.conf mounted in /live/persistence
1361         # Side-effect: prints info to file $custom_mounts
1362
1363         local custom_mounts devices bindings links
1364         custom_mounts=${1}
1365         shift
1366         devices=${@}
1367
1368         bindings="/tmp/bindings.list"
1369         links="/tmp/links.list"
1370         rm -rf ${bindings} ${links} 2> /dev/null
1371
1372         for device in ${devices}
1373         do
1374                 local device_name backing include_list
1375                 device_name="$(basename ${device})"
1376                 backing=$(mount_persistence_media ${device})
1377                 if [ -z "${backing}" ]
1378                 then
1379                         continue
1380                 fi
1381
1382                 if [ -r "${backing}/${persistence_list}" ]
1383                 then
1384                         include_list="${backing}/${persistence_list}"
1385                 else
1386                         continue
1387                 fi
1388
1389                 if [ -n "${LIVE_BOOT_DEBUG}" ] && [ -e "${include_list}" ]
1390                 then
1391                         cp ${include_list} /live/persistence/${persistence_list}.${device_name}
1392                 fi
1393
1394                 while read dir options # < ${include_list}
1395                 do
1396                         if echo ${dir} | grep -qe "^[[:space:]]*\(#.*\)\?$"
1397                         then
1398                                 # skipping empty or commented lines
1399                                 continue
1400                         fi
1401
1402                         if trim_path ${dir} | grep -q -e "^[^/]" -e "^/lib" -e "^/lib/live\(/.*\)\?$" -e "^/\(.*/\)\?\.\.\?\(/.*\)\?$"
1403                         then
1404                                 log_warning_msg "Skipping unsafe custom mount ${dir}: must be an absolute path containing neither the \".\" nor \"..\" special dirs, and cannot be \"/lib\", or \"/lib/live\" or any of its sub-directories."
1405                                 continue
1406                         fi
1407
1408                         local opt_source opt_link source full_source full_dest
1409                         opt_source=""
1410                         opt_link=""
1411                         for opt in $(echo ${options} | tr ',' ' ');
1412                         do
1413                                 case "${opt}" in
1414                                         source=*)
1415                                                 opt_source=${opt#source=}
1416                                                 ;;
1417                                         link)
1418                                                 opt_link="true"
1419                                                 ;;
1420                                         union|bind)
1421                                                 ;;
1422                                         *)
1423                                                 log_warning_msg "Skipping custom mount with unknown option: ${opt}"
1424                                                 continue 2
1425                                                 ;;
1426                                 esac
1427                         done
1428
1429                         source="${dir}"
1430                         if [ -n "${opt_source}" ]
1431                         then
1432                                 if echo ${opt_source} | grep -q -e "^/" -e "^\(.*/\)\?\.\.\?\(/.*\)\?$" && [ "${opt_source}" != "." ]
1433                                 then
1434                                         log_warning_msg "Skipping unsafe custom mount with option source=${opt_source}: must be either \".\" (the media root) or a relative path w.r.t. the media root that contains neither comas, nor the special \".\" and \"..\" path components"
1435                                         continue
1436                                 else
1437                                         source="${opt_source}"
1438                                 fi
1439                         fi
1440
1441                         full_source="$(trim_path ${backing}/${source})"
1442                         full_dest="$(trim_path ${rootmnt}/${dir})"
1443                         if [ -n "${opt_link}" ]
1444                         then
1445                                 echo "${device} ${full_source} ${full_dest} ${options}" >> ${links}
1446                         else
1447                                 echo "${device} ${full_source} ${full_dest} ${options}" >> ${bindings}
1448                         fi
1449                 done < ${include_list}
1450         done
1451
1452         # We sort the list according to destination so we're sure that
1453         # we won't hide a previous mount. We also ignore duplicate
1454         # destinations in a more or less arbitrary way.
1455         [ -e "${bindings}" ] && sort -k3 -sbu ${bindings} >> ${custom_mounts} && rm ${bindings}
1456
1457         # After all mounts are considered we add symlinks so they
1458         # won't be hidden by some mount.
1459         [ -e "${links}" ] && cat ${links} >> ${custom_mounts} && rm ${links}
1460
1461         # We need to make sure that no two custom mounts have the same sources
1462         # or are nested; if that is the case, too much weird stuff can happen.
1463         local prev_source prev_dest
1464         prev_source="impossible source" # first iteration must not match
1465         prev_dest=""
1466         # This sort will ensure that a source /a comes right before a source
1467         # /a/b so we only need to look at the previous source
1468         [ -e ${custom_mounts} ] && sort -k2 -b ${custom_mounts} |
1469         while read device source dest options
1470         do
1471                 if echo ${source} | grep -qe "^${prev_source}\(/.*\)\?$"
1472                 then
1473                         panic "Two persistence mounts have the same or nested sources: ${source} on ${dest}, and ${prev_source} on ${prev_dest}"
1474                 fi
1475                 prev_source=${source}
1476                 prev_dest=${dest}
1477         done
1478 }
1479
1480 activate_custom_mounts ()
1481 {
1482         local custom_mounts used_devices
1483         custom_mounts="${1}" # the ouput from get_custom_mounts()
1484         used_devices=""
1485
1486         while read device source dest options # < ${custom_mounts}
1487         do
1488                 local opt_bind opt_link opt_union
1489                 opt_bind="true"
1490                 opt_link=""
1491                 opt_union=""
1492                 for opt in $(echo ${options} | tr ',' ' ');
1493                 do
1494                         case "${opt}" in
1495                                 bind)
1496                                         opt_bind="true"
1497                                         unset opt_link opt_union
1498                                         ;;
1499                                 link)
1500                                         opt_link="true"
1501                                         unset opt_bind opt_union
1502                                         ;;
1503                                 union)
1504                                         opt_union="true"
1505                                         unset opt_bind opt_link
1506                                         ;;
1507                         esac
1508                 done
1509
1510                 if [ -n "$(what_is_mounted_on "${dest}")" ]
1511                 then
1512                         if [ "${dest}" = "${rootmnt}" ]
1513                         then
1514                                 umount "${dest}"
1515                         else
1516                                 log_warning_msg "Skipping custom mount ${dest}: $(what_is_mounted_on "${dest}") is already mounted there"
1517                                 continue
1518                         fi
1519                 fi
1520
1521                 if [ ! -d "${dest}" ]
1522                 then
1523                         # create the destination and delete existing files in
1524                         # its path that are in the way
1525                         path="/"
1526                         for dir in $(echo ${dest} | sed -e 's|/\+| |g')
1527                         do
1528                                 path=$(trim_path ${path}/${dir})
1529                                 if [ -f ${path} ]
1530                                 then
1531                                         rm -f ${path}
1532                                 fi
1533                                 if [ ! -e ${path} ]
1534                                 then
1535                                         mkdir -p ${path}
1536                                         if echo ${path} | grep -qe "^${rootmnt}/*home/[^/]\+"
1537                                         then
1538                                                 # if ${dest} is in /home try fixing proper ownership by assuming that the intended user is the first, which is usually the case
1539                                                 # FIXME: this should really be handled by live-config since we don't know for sure which uid a certain user has until then
1540                                                 chown 1000:1000 ${path}
1541                                         fi
1542                                 fi
1543                         done
1544                 fi
1545
1546                 # if ${source} doesn't exist on our persistence media
1547                 # we bootstrap it with $dest from the live filesystem.
1548                 # this both makes sense and is critical if we're
1549                 # dealing with /etc or other system dir.
1550                 if [ ! -d "${source}" ]
1551                 then
1552                         if [ -n "${PERSISTENCE_READONLY}" ]
1553                         then
1554                                 continue
1555                         elif [ -n "${opt_union}" ] || [ -n "${opt_link}" ]
1556                         then
1557                                 # unions and don't need to be bootstrapped
1558                                 # link dirs can't be bootstrapped in a sensible way
1559                                 mkdir -p "${source}"
1560                                 chown_ref "${dest}" "${source}"
1561                                 chmod_ref "${dest}" "${source}"
1562                         elif [ -n "${opt_bind}" ]
1563                         then
1564                                 # ensure that $dest is not copied *into* $source
1565                                 mkdir -p "$(dirname ${source})"
1566                                 cp -a "${dest}" "${source}"
1567                         fi
1568                 fi
1569
1570                 # XXX: If CONFIG_AUFS_ROBR is added to the Debian kernel we can
1571                 # ignore the loop below and set rootfs_dest_backing=$dest
1572                 local rootfs_dest_backing
1573                 rootfs_dest_backing=""
1574                 if [ -n "${opt_link}" ] || [ -n "${opt_union}" ]
1575                 then
1576                         for d in /live/rootfs/*
1577                         do
1578                                 if [ -n "${rootmnt}" ]
1579                                 then
1580                                         fs="${d}/$(echo ${dest} | sed -e "s|${rootmnt}||")"
1581                                 else
1582                                         fs="${d}/${dest}"
1583                                 fi
1584                                 if [ -d "${fs}" ]
1585                                 then
1586                                         rootfs_dest_backing="${rootfs_dest_backing} ${fs}"
1587                                 fi
1588                         done
1589                 fi
1590
1591                 local cow_dir links_source
1592                 if [ -n "${opt_link}" ] && [ -z "${PERSISTENCE_READONLY}" ]
1593                 then
1594                         link_files ${source} ${dest} "s|^/live/|/lib/live/mount/|"
1595                 elif [ -n "${opt_link}" ] && [ -n "${PERSISTENCE_READONLY}" ]
1596                 then
1597                         mkdir -p ${rootmnt}/lib/live/mount/persistence
1598                         links_source=$(mktemp -d ${rootmnt}/lib/live/mount/persistence/links-source-XXXXXX)
1599                         chown_ref ${source} ${links_source}
1600                         chmod_ref ${source} ${links_source}
1601                         # We put the cow dir in the below strange place to
1602                         # make it absolutely certain that the link source
1603                         # has its own directory and isn't nested with some
1604                         # other custom mount (if so that mount's files would
1605                         # be linked, causing breakage.
1606                         cow_dir="/live/overlay/lib/live/mount/persistence/$(basename ${links_source})"
1607                         mkdir -p ${cow_dir}
1608                         chown_ref "${source}" "${cow_dir}"
1609                         chmod_ref "${source}" "${cow_dir}"
1610                         do_union ${links_source} ${cow_dir} ${source} ${rootfs_dest_backing}
1611                         link_files ${links_source} ${dest} "s|^${rootmnt}||"
1612                 elif [ -n "${opt_union}" ] && [ -z "${PERSISTENCE_READONLY}" ]
1613                 then
1614                         do_union ${dest} ${source} ${rootfs_dest_backing}
1615                 elif [ -n "${opt_bind}" ] && [ -z "${PERSISTENCE_READONLY}" ]
1616                 then
1617                         mount --bind "${source}" "${dest}"
1618                 elif [ -n "${opt_bind}" -o -n "${opt_union}" ] && [ -n "${PERSISTENCE_READONLY}" ]
1619                 then
1620                         # bind-mount and union mount are handled the same
1621                         # in read-only mode, but note that rootfs_dest_backing
1622                         # is non-empty (and necessary) only for unions
1623                         cow_dir="/live/overlay/${dest}"
1624                         if [ -e "${cow_dir}" ] && [ -z "${opt_link}" ]
1625                         then
1626                                 # If an earlier custom mount has files here
1627                                 # it will "block" the current mount's files
1628                                 # which is undesirable
1629                                 rm -rf "${cow_dir}"
1630                         fi
1631                         mkdir -p ${cow_dir}
1632                         chown_ref "${source}" "${cow_dir}"
1633                         chmod_ref "${source}" "${cow_dir}"
1634                         do_union ${dest} ${cow_dir} ${source} ${rootfs_dest_backing}
1635                 fi
1636
1637                 PERSISTENCE_IS_ON="1"
1638                 export PERSISTENCE_IS_ON
1639
1640                 if echo ${used_devices} | grep -qve "^\(.* \)\?${device}\( .*\)\?$"
1641                 then
1642                         used_devices="${used_devices} ${device}"
1643                 fi
1644         done < ${custom_mounts}
1645
1646         echo ${used_devices}
1647 }
1648
1649 is_mountpoint ()
1650 {
1651         directory="$1"
1652
1653         [ $(stat -fc%d:%D "${directory}") != $(stat -fc%d:%D "${directory}/..") ]
1654 }