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>
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
25 echo "$0 [--reset-mbr] [--noverify] [--overlay-size-mb <size>] [--home-size-mb <size>] [--unencrypted-home] <isopath> <usbstick device>"
30 [ -d "$CDMNT" ] && umount
$CDMNT && rmdir $CDMNT
31 [ -d "$USBMNT" ] && umount
$USBMNT && rmdir $USBMNT
35 echo "Cleaning up to exit..."
43 if [[ "$DEV" =~
"/dev/loop*" ]]; then
48 p
=$
(udevinfo
-q path
-n $DEV)
49 if [ -e /sys
/$p/device
]; then
50 device
=$
(basename /sys
/$p)
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!"
60 # FIXME: weird dev names could mess this up I guess
66 if [[ "$DEV" =~
"/dev/loop*" ]]; then
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
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;'})
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"
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
107 if [[ "$dev" =~
"/dev/loop*" ]]; then
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"
125 echo "WARNING: THIS WILL DESTROY ANY DATA ON $device!!!"
126 echo "Press Enter to continue or ctrl-c to abort"
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
135 /sbin
/mkdosfs
-n LIVE
$USBDEV
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"
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"
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"
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]"
175 USBLABEL
=$
(/lib
/udev
/vol_id
-u $dev)
176 if [ -n "$USBLABEL" ]; then
177 USBLABEL
="UUID=$USBLABEL" ;
179 USBLABEL
=$
(/lib
/udev
/vol_id
-l $dev)
180 if [ -n "$USBLABEL" ]; then
181 USBLABEL
="LABEL=$USBLABEL"
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"
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"
203 if ! syslinux
2>&1 |
grep -qe -d; then
206 SYSLINUXPATH
="syslinux"
212 if grep -q "^$dev " /proc
/mounts
; then
213 echo "$dev is mounted, please unmount for safety"
216 if grep -q "^$dev " /proc
/swaps
; then
217 echo "$dev is in use as a swap device, please disable swap"
222 if [ $
(id
-u) != 0 ]; then
223 echo "You need to be root to run this script"
229 while [ $# -gt 2 ]; do
251 --reset-mbr|
--resetmbr)
268 ISO
=$
(readlink
-f "$1")
269 USBDEV
=$
(readlink
-f "$2")
271 if [ -z "$ISO" ]; then
275 if [ ! -b "$ISO" -a ! -f "$ISO" ]; then
279 if [ -z "$USBDEV" -o ! -b "$USBDEV" ]; then
283 if [ -z "$noverify" ]; then
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"
294 # do some basic sanity checks.
295 checkFilesystem
$USBDEV
297 if [ -z "$mactel" ]; then
299 checkPartActive
$USBDEV
300 [ -n "$resetmbr" ] && resetMBR
$USBDEV
303 [ -n "$resetmbr" ] && createGPTLayout
$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"
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"
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"
336 # let's try to make sure there's enough room on the stick
337 if [ -d $CDMNT/LiveOS
]; then
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))
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))"
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"
368 echo "Deleting old OS in fifteen seconds..."
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
400 if [ -d $CDMNT/EFI
/boot
]; then
401 cp $CDMNT/EFI
/boot
/* $USBMNT/EFI
/boot
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
415 cat > $USBMNT/EFI
/boot
/boot.conf
<<EOF
417 splashimage=/EFI/boot/splash.xpm.gz
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
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"
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
459 dd if=/dev
/null of
=$USBMNT/LiveOS
/$HOMEFILE count
=1 bs
=1M seek
=$homesizemb
461 if [ -n "$cryptedhome" ]; then
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
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
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
489 if [ -n "$SYSLINUXPATH" ]; then
490 syslinux
-d $SYSLINUXPATH $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
502 echo "USB stick set up as live image!"