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