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