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