Re-factor imgcreate/fs.py module
[livecd/EL-5.git] / tools / livecd-iso-to-disk.sh
blob48ae40bd1a6d4fd599cc6757b57063e1c45b6230
1 #!/bin/bash
2 # Convert a live CD iso so that it's bootable off of a USB stick
3 # Copyright 2007 Red Hat, Inc.
4 # Jeremy Katz <katzj@redhat.com>
6 # overlay/persistence enhancements by Douglas McClendon <dmc@viros.org>
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; version 2 of the License.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Library General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 export PATH=/sbin:/usr/sbin:$PATH
24 usage() {
25 echo "$0 [--reset-mbr] [--noverify] [--overlay-size-mb <size>] [--home-size-mb <size>] [--unencrypted-home] <isopath> <usbstick device>"
26 exit 1
29 cleanup() {
30 [ -d "$CDMNT" ] && umount $CDMNT && rmdir $CDMNT
31 [ -d "$USBMNT" ] && umount $USBMNT && rmdir $USBMNT
34 exitclean() {
35 echo "Cleaning up to exit..."
36 cleanup
37 exit 1
40 getdisk() {
41 DEV=$1
43 if [[ "$DEV" =~ "/dev/loop*" ]]; then
44 device="$DEV"
45 return
48 p=$(udevinfo -q path -n $DEV)
49 if [ -e /sys/$p/device ]; then
50 device=$(basename /sys/$p)
51 else
52 device=$(basename $(readlink -f /sys/$p/../))
54 if [ ! -e /sys/block/$device -o ! -e /dev/$device ]; then
55 echo "Error finding block device of $DEV. Aborting!"
56 exitclean
59 device="/dev/$device"
60 # FIXME: weird dev names could mess this up I guess
61 p=/dev/`basename $p`
62 partnum=${p##$device}
65 resetMBR() {
66 if [[ "$DEV" =~ "/dev/loop*" ]]; then
67 return
69 getdisk $1
70 if [ -f /usr/lib/syslinux/mbr.bin ]; then
71 cat /usr/lib/syslinux/mbr.bin > $device
72 elif [ -f /usr/share/syslinux/mbr.bin ]; then
73 cat /usr/share/syslinux/mbr.bin > $device
74 else
75 exitclean
79 checkMBR() {
80 getdisk $1
82 bs=$(mktemp /tmp/bs.XXXXXX)
83 dd if=$device of=$bs bs=512 count=1 2>/dev/null || exit 2
85 mbrword=$(hexdump -n 2 $bs |head -n 1|awk {'print $2;'})
86 rm -f $bs
87 if [ "$mbrword" = "0000" ]; then
88 echo "MBR appears to be blank."
89 echo "Do you want to replace the MBR on this device?"
90 echo "Press Enter to continue or ctrl-c to abort"
91 read
92 resetMBR $1
95 return 0
98 checkPartActive() {
99 dev=$1
100 getdisk $dev
102 # if we're installing to whole-disk and not a partition, then we
103 # don't need to worry about being active
104 if [ "$dev" = "$device" ]; then
105 return
107 if [[ "$dev" =~ "/dev/loop*" ]]; then
108 return
111 if [ "$(/sbin/fdisk -l $device 2>/dev/null |grep $dev |awk {'print $2;'})" != "*" ]; then
112 echo "Partition isn't marked bootable!"
113 echo "You can mark the partition as bootable with "
114 echo " # /sbin/parted $device"
115 echo " (parted) toggle N boot"
116 echo " (parted) quit"
117 exitclean
121 createGPTLayout() {
122 dev=$1
123 getdisk $dev
125 echo "WARNING: THIS WILL DESTROY ANY DATA ON $device!!!"
126 echo "Press Enter to continue or ctrl-c to abort"
127 read
129 /sbin/parted --script $device mklabel gpt
130 partinfo=$(/sbin/parted --script -m $device "unit b print" |grep ^$device:)
131 size=$(echo $partinfo |cut -d : -f 2 |sed -e 's/B$//')
132 /sbin/parted --script $device unit b mkpart '"EFI System Partition"' fat32 17408 $(($size - 17408)) set 1 boot on
133 USBDEV=${device}1
134 /sbin/udevsettle
135 /sbin/mkdosfs -n LIVE $USBDEV
138 checkGPT() {
139 dev=$1
140 getdisk $dev
142 if [ "$(/sbin/fdisk -l $device 2>/dev/null |grep -c GPT)" -eq "0" ]; then
143 echo "EFI boot requires a GPT partition table."
144 echo "This can be done manually or you can run with --reset-mbr"
145 exitclean
148 partinfo=$(/sbin/parted --script -m $device "print" |grep ^$partnum:)
149 volname=$(echo $partinfo |cut -d : -f 6)
150 flags=$(echo $partinfo |cut -d : -f 7)
151 if [ "$volname" != "EFI System Partition" ]; then
152 echo "Partition name must be 'EFI System Partition'"
153 echo "This can be set in parted or you can run with --reset-mbr"
154 exitclean
156 if [ "$(echo $flags |grep -c boot)" = "0" ]; then
157 echo "Partition isn't marked bootable!"
158 echo "You can mark the partition as bootable with "
159 echo " # /sbin/parted $device"
160 echo " (parted) toggle N boot"
161 echo " (parted) quit"
162 exitclean
166 checkFilesystem() {
167 dev=$1
169 USBFS=$(/lib/udev/vol_id -t $dev)
170 if [ "$USBFS" != "vfat" -a "$USBFS" != "msdos" -a "$USBFS" != "ext2" -a "$USBFS" != "ext3" ]; then
171 echo "USB filesystem must be vfat or ext[23]"
172 exitclean
175 USBLABEL=$(/lib/udev/vol_id -u $dev)
176 if [ -n "$USBLABEL" ]; then
177 USBLABEL="UUID=$USBLABEL" ;
178 else
179 USBLABEL=$(/lib/udev/vol_id -l $dev)
180 if [ -n "$USBLABEL" ]; then
181 USBLABEL="LABEL=$USBLABEL"
182 else
183 echo "Need to have a filesystem label or UUID for your USB device"
184 if [ "$USBFS" = "vfat" -o "$USBFS" = "msdos" ]; then
185 echo "Label can be set with /sbin/dosfslabel"
186 elif [ "$USBFS" = "ext2" -o "$USBFS" = "ext3" ]; then
187 echo "Label can be set with /sbin/e2label"
189 exitclean
193 if [ "$USBFS" = "vfat" -o "$USBFS" = "msdos" ]; then
194 mountopts="-o shortname=winnt,umask=0077"
198 checkSyslinuxVersion() {
199 if [ ! -x /usr/bin/syslinux ]; then
200 echo "You need to have syslinux installed to run this script"
201 exit 1
203 if ! syslinux 2>&1 | grep -qe -d; then
204 SYSLINUXPATH=""
205 else
206 SYSLINUXPATH="syslinux"
210 checkMounted() {
211 dev=$1
212 if grep -q "^$dev " /proc/mounts ; then
213 echo "$dev is mounted, please unmount for safety"
214 exitclean
216 if grep -q "^$dev " /proc/swaps; then
217 echo "$dev is in use as a swap device, please disable swap"
218 exitclean
222 if [ $(id -u) != 0 ]; then
223 echo "You need to be root to run this script"
224 exit 1
227 cryptedhome=1
228 keephome=1
229 while [ $# -gt 2 ]; do
230 case $1 in
231 --overlay-size-mb)
232 overlaysizemb=$2
233 shift
235 --home-size-mb)
236 homesizemb=$2
237 shift
239 --crypted-home)
240 cryptedhome=1
242 --unencrypted-home)
243 cryptedhome=""
245 --delete-home)
246 keephome=""
248 --noverify)
249 noverify=1
251 --reset-mbr|--resetmbr)
252 resetmbr=1
254 --mactel)
255 mactel=1
257 --extra-kernel-args)
258 kernelargs=$2
259 shift
262 usage
264 esac
265 shift
266 done
268 ISO=$(readlink -f "$1")
269 USBDEV=$(readlink -f "$2")
271 if [ -z "$ISO" ]; then
272 usage
275 if [ ! -b "$ISO" -a ! -f "$ISO" ]; then
276 usage
279 if [ -z "$USBDEV" -o ! -b "$USBDEV" ]; then
280 usage
283 if [ -z "$noverify" ]; then
284 # verify the image
285 echo "Verifying image..."
286 checkisomd5 --verbose "$ISO"
287 if [ $? -ne 0 ]; then
288 echo "Are you SURE you want to continue?"
289 echo "Press Enter to continue or ctrl-c to abort"
290 read
294 # do some basic sanity checks.
295 checkFilesystem $USBDEV
296 checkMounted $USBDEV
297 if [ -z "$mactel" ]; then
298 checkSyslinuxVersion
299 checkPartActive $USBDEV
300 [ -n "$resetmbr" ] && resetMBR $USBDEV
301 checkMBR $USBDEV
302 else
303 [ -n "$resetmbr" ] && createGPTLayout $USBDEV
304 checkGPT $USBDEV
308 if [ -n "$overlaysizemb" -a "$USBFS" = "vfat" ]; then
309 if [ "$overlaysizemb" -gt 2047 ]; then
310 echo "Can't have an overlay of 2048MB or greater on VFAT"
311 exitclean
315 if [ -n "$homesizemb" -a "$USBFS" = "vfat" ]; then
316 if [ "$homesizemb" -gt 2047 ]; then
317 echo "Can't have a home overlay greater than 2048MB on VFAT"
318 exitclean
322 # FIXME: would be better if we had better mountpoints
323 CDMNT=$(mktemp -d /media/cdtmp.XXXXXX)
324 mount -o loop,ro "$ISO" $CDMNT || exitclean
325 USBMNT=$(mktemp -d /media/usbdev.XXXXXX)
326 mount $mountopts $USBDEV $USBMNT || exitclean
328 trap exitclean SIGINT SIGTERM
330 if [ -f "$USBMNT/LiveOS/home.img" -a -n "$keephome" -a -n "$homesizemb" ]; then
331 echo "ERROR: Requested keeping existing /home and specified a size for /home"
332 echo "Please either don't specify a size or specify --delete-home"
333 exitclean
336 # let's try to make sure there's enough room on the stick
337 if [ -d $CDMNT/LiveOS ]; then
338 check=$CDMNT/LiveOS
339 else
340 check=$CDMNT
342 if [ -d $USBMNT/LiveOS ]; then
343 tbd=$(du -s -B 1M $USBMNT/LiveOS | awk {'print $1;'})
344 [ -f $USBMNT/LiveOS/home.img ] && homesz=$(du -s -B 1M $USBMNT/LiveOS/home.img | awk {'print $1;'})
345 [ -n "$homesz" -a -n "$keephome" ] && tbd=$(($tbd - $homesz))
346 else
347 tbd=0
349 livesize=$(du -s -B 1M $check | awk {'print $1;'})
350 free=$(df -B1M $USBDEV |tail -n 1 |awk {'print $4;'})
352 if [ $(($overlaysizemb + $homesizemb + $livesize)) -gt $(($free + $tbd)) ]; then
353 echo "Unable to fit live image + overlay on available space on USB stick"
354 echo "Size of live image: $livesize"
355 [ -n "$overlaysizemb" ] && echo "Overlay size: $overlaysizemb"
356 [ -n "$homesizemb" ] && echo "Home overlay size: $homesizemb"
357 echo "Available space: $(($free + $tbd))"
358 exitclean
361 if [ -d $USBMNT/LiveOS ]; then
362 echo "Already set up as live image."
363 if [ -z "$keephome" -a -e $USBMNT/LiveOS/home.img ]; then
364 echo "WARNING: Persistent /home will be deleted!!!"
365 echo "Press Enter to continue or ctrl-c to abort"
366 read
367 else
368 echo "Deleting old OS in fifteen seconds..."
369 sleep 15
371 [ -e "$USBMNT/LiveOS/home.img" -a -n "$keephome" ] && mv $USBMNT/LiveOS/home.img $USBMNT/home.img
374 rm -rf $USBMNT/LiveOS
377 echo "Copying live image to USB stick"
378 [ -z "$mactel" -a ! -d $USBMNT/$SYSLINUXPATH ] && mkdir -p $USBMNT/$SYSLINUXPATH
379 [ -n "$mactel" -a ! -d $USBMNT/EFI/boot ] && mkdir -p $USBMNT/EFI/boot
380 [ ! -d $USBMNT/LiveOS ] && mkdir $USBMNT/LiveOS
381 [ -n "$keephome" -a -f "$USBMNT/home.img" ] && mv $USBMNT/home.img $USBMNT/LiveOS/home.img
382 # cases without /LiveOS are legacy detection, remove for F10
383 if [ -f $CDMNT/LiveOS/squashfs.img ]; then
384 cp $CDMNT/LiveOS/squashfs.img $USBMNT/LiveOS/squashfs.img || exitclean
385 elif [ -f $CDMNT/squashfs.img ]; then
386 cp $CDMNT/squashfs.img $USBMNT/LiveOS/squashfs.img || exitclean
387 elif [ -f $CDMNT/LiveOS/ext3fs.img ]; then
388 cp $CDMNT/LiveOS/ext3fs.img $USBMNT/LiveOS/ext3fs.img || exitclean
389 elif [ -f $CDMNT/ext3fs.img ]; then
390 cp $CDMNT/ext3fs.img $USBMNT/LiveOS/ext3fs.img || exitclean
392 if [ -f $CDMNT/LiveOS/osmin.img ]; then
393 cp $CDMNT/LiveOS/osmin.img $USBMNT/LiveOS/osmin.img || exitclean
396 if [ -z "$mactel" ]; then
397 cp $CDMNT/isolinux/* $USBMNT/$SYSLINUXPATH
398 BOOTCONFIG=$USBMNT/$SYSLINUXPATH/isolinux.cfg
399 else
400 if [ -d $CDMNT/EFI/boot ]; then
401 cp $CDMNT/EFI/boot/* $USBMNT/EFI/boot
402 else
403 # whee! this image wasn't made with grub.efi bits. so we get to create
404 # them here. isn't life grand?
405 cp $CDMNT/isolinux/* $USBMNT/EFI/boot
406 mount -o loop,ro -t squashfs $CDMNT/LiveOS/squashfs.img $CDMNT
407 mount -o loop,ro -t ext3 $CDMNT/LiveOS/ext3fs.img $CDMNT
408 cp $CDMNT/boot/efi/EFI/redhat/grub.efi $USBMNT/EFI/boot/boot.efi
409 cp $CDMNT/boot/grub/splash.xpm.gz $USBMNT/EFI/boot/splash.xpm.gz
410 if [ -d $CDMNT/lib64 ]; then efiarch="x64" ; else efiarch="ia32"; fi
411 umount $CDMNT
412 umount $CDMNT
414 # magic config...
415 cat > $USBMNT/EFI/boot/boot.conf <<EOF
416 default=0
417 splashimage=/EFI/boot/splash.xpm.gz
418 timeout 10
419 hiddenmenu
421 title Live
422 kernel /EFI/boot/vmlinuz0 root=CDLABEL=live rootfstype=iso9660 ro quiet liveimg
423 initrd /EFI/boot/initrd0.img
426 cp $USBMNT/EFI/boot/boot.conf $USBMNT/EFI/boot/boot${efiarch}.conf
427 cp $USBMNT/EFI/boot/boot.efi $USBMNT/EFI/boot/boot${efiarch}.efi
430 # this is a little ugly, but it gets the "interesting" named config file
431 BOOTCONFIG=$USBMNT/EFI/boot/boot?*.conf
434 echo "Updating boot config file"
435 # adjust label and fstype
436 sed -i -e "s/CDLABEL=[^ ]*/$USBLABEL/" -e "s/rootfstype=[^ ]*/rootfstype=$USBFS/" $BOOTCONFIG
437 if [ -n "$kernelargs" ]; then sed -i -e "s/liveimg/liveimg ${kernelargs}/" $BOOTCONFIG.cfg ; fi
439 if [ -n "$overlaysizemb" ]; then
440 echo "Initializing persistent overlay file"
441 OVERFILE="overlay-$( /lib/udev/vol_id -l $USBDEV )-$( /lib/udev/vol_id -u $USBDEV )"
442 if [ "$USBFS" = "vfat" ]; then
443 # vfat can't handle sparse files
444 dd if=/dev/zero of=$USBMNT/LiveOS/$OVERFILE count=$overlaysizemb bs=1M
445 else
446 dd if=/dev/null of=$USBMNT/LiveOS/$OVERFILE count=1 bs=1M seek=$overlaysizemb
448 sed -i -e "s/liveimg/liveimg overlay=${USBLABEL}/" $BOOTCONFIG
449 sed -i -e "s/\ ro\ /\ rw\ /" $BOOTCONFIG
452 if [ -n "$homesizemb" ]; then
453 echo "Initializing persistent /home"
454 HOMEFILE=home.img
455 if [ "$USBFS" = "vfat" ]; then
456 # vfat can't handle sparse files
457 dd if=/dev/zero of=$USBMNT/LiveOS/$HOMEFILE count=$homesizemb bs=1M
458 else
459 dd if=/dev/null of=$USBMNT/LiveOS/$HOMEFILE count=1 bs=1M seek=$homesizemb
461 if [ -n "$cryptedhome" ]; then
462 loop=$(losetup -f)
463 losetup $loop $USBMNT/LiveOS/$HOMEFILE
464 echo "Encrypting persistent /home"
465 cryptsetup luksFormat -y -q $loop
466 echo "Please enter the password again to unlock the device"
467 cryptsetup luksOpen $loop EncHomeFoo
468 mke2fs -j /dev/mapper/EncHomeFoo
469 tune2fs -c0 -i0 -ouser_xattr,acl /dev/mapper/EncHomeFoo
470 cryptsetup luksClose EncHomeFoo
471 losetup -d $loop
472 else
473 echo "Formatting unencrypted /home"
474 mke2fs -F -j $USBMNT/LiveOS/$HOMEFILE
475 tune2fs -c0 -i0 -ouser_xattr,acl $USBMNT/LiveOS/$HOMEFILE
479 echo "Installing boot loader"
480 if [ -n "$mactel" ]; then
481 # replace the ia32 hack
482 if [ -f "$USBMNT/EFI/boot/boot.conf" ]; then cp -f $USBMNT/EFI/boot/bootia32.conf $USBMNT/EFI/boot/boot.conf ; fi
483 cleanup
484 elif [ "$USBFS" = "vfat" -o "$USBFS" = "msdos" ]; then
485 # syslinux expects the config to be named syslinux.cfg
486 # and has to run with the file system unmounted
487 mv $USBMNT/$SYSLINUXPATH/isolinux.cfg $USBMNT/$SYSLINUXPATH/syslinux.cfg
488 cleanup
489 if [ -n "$SYSLINUXPATH" ]; then
490 syslinux -d $SYSLINUXPATH $USBDEV
491 else
492 syslinux $USBDEV
494 elif [ "$USBFS" = "ext2" -o "$USBFS" = "ext3" ]; then
495 # extlinux expects the config to be named extlinux.conf
496 # and has to be run with the file system mounted
497 mv $USBMNT/$SYSLINUXPATH/isolinux.cfg $USBMNT/$SYSLINUXPATH/extlinux.conf
498 extlinux -i $USBMNT/syslinux
499 cleanup
502 echo "USB stick set up as live image!"