Re: Bug in7.4.0 flash-knoppix script.
Hello again,
For the special case of "repartition flash disk and use read-only like
DVD without overlay", I just added a fix into flash-knoppix. If you
would like to try, check out the attached file (detached PGP signature
included).
If I didnt mention this before: flash-knoppix also has a non-interactive
"batch-mode" now, and can use .iso-images directly (as parameter to the
script) for creating a bootable USB flash disk, so you don't need the
intermediate DVD boot anymore. Just a Linux system capable of running
the script, zenity, syslinux, parted, sfdisk and sudo are required.
Regards
-Klaus
On Fri, Sep 12, 2014 at 11:35:31AM +0200, Klaus Knopper wrote:
> Hello Eric,
>
> On Thu, Sep 11, 2014 at 04:18:17PM -0700, Eric Kudzin wrote:
> > I think I found a bug in the v7.4.0 flash-knoppix script that it doesn't
> > set the "boot" flag in the MBR partition table, so the card never boots.
> > I believe:
> > MAKE_BOOTABLE="true"
> > is not set when you select:
> > n No Overlay (read-only like CD/DVD)
> > so:
> > # Finally mark partition 1 as bootable, if not already done.
> > # this may cause another udev run, which we can ignore here
> > if [ -n "$MAKE_BOOTABLE" ]; then
> > sfdisk -A1 "${FLASH}" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2;
> > }
> > blockdev --flushbufs "${FLASH}"
> > fi
> > is never called
> > Screenshots of steps at:
> > [1]https://www.flickr.com/photos/126934570@N05/sets/72157647506682635/
> > This has happen to me twice on 2 different cards.
> > Eric
>
> The "MAKE_BOOTABLE" is only used for pre-existing FAT32 partitions when
> selecting "No" to the question whether or not to reformat. For all other
> options that require repartitioning, parted does this job. Look for the
> lines that say:
>
> set 1 boot on
>
> which does the same thing that sfdisk -A1 did in ALL cases in older
> Knoppix versions, adding a flag for "bootability". The code you quoted
> is just needed in the case that the devices partition wasn't changed.
>
> So, in either case, the first partition should have always been marked
> as bootable by the script.
>
> But, looking at the code, there is another bug I missed which explains
> your observation: In the case of the "like DVD" selection with no
> overlay, the flash disk is not repartitioned and reformatted even if you
> selected "n" in the previous dialog, i.e. an existing FAT filesystem is
> just reused and not overwritten. In this case, the "don't reformat" does
> not apply, and the boot flag is not set because parted was not called.
>
> This is minor problem, since most BIOSes ignore the "boot" flag and
> just happily load the MBR. On the other side, I had one old IBM notebook that
> required the "boot" flag, though, and ignored disks or flash pens in the
> boot menu otherwise.
>
> Regards
> -Klaus
#!/bin/bash
# flash-knoppix - install KNOPPIX on flash disk
# (C) Klaus Knopper 2008-2014
# License: GPL V2
#
# Changes for Knoppix 7.0:
# - Replacing Xdialog (GTK1) by accessible zenity
# - Skip copy of persistent home when installing from flash to flash
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin"
export PATH
[ -r /etc/default/locale ] && . /etc/default/locale
[ -r /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n
case "$LANG" in
de*)
MSG_INTRO="flash-knoppix: Mit diesem Programm wird eine bootfähige Kopie von\nKNOPPIX auf einem USB-Datenspeicher oder einer Festplatte und\noptional ein Overlay zur Speicherung persönlicher Daten auf dem\nZielmedium erzeugt, als Container-Datei oder separate Partition,\nmit oder ohne Verschlüsselung.\n\nBitte wählen Sie die Optionen aus:"
MSG_ALLOWHD="Installation auch auf internen Festplatten erlauben"
MSG_NOALLOWHD="Installation nur auf Wechselmedien erlauben"
MSG_TARGET="flash-knoppix: KNOPPIX komprimiert auf Flash Disk installieren.\n\nBitte das gewünschte Ziel angeben:"
INFO_TARGET="Ziel:"
MSG_READY="Fertig.
Sie können den Datenträger jetzt entfernen."
MSG_MOUNTED="ist noch gemountet."
MSG_CHECKING="Untersuche"
MSG_SELECT="Bitte das Verzeichnis angeben, in dem sich die KNOPPIX-Daten befinden."
MSG_BOOTREC="Bootrecord einrichten auf"
MSG_NOTFOUND="Keine Bootkonfiguration gefunden (weder boot/isolinux/isolinux.cfg noch boot/syslinux/syslinux.cfg), der Bootlader wird vermutlich nicht funktionieren."
MSG_WRITING="Schreibe Daten..."
MSG_SIZE_OVERLAY="KNOPPIX kann eine \"Overlay\"-Datei verwenden, um Daten permanent zu speichern.\nWenn gewünscht, bitte Größe angeben (mindestens 200MB, frei: %sMB)."
MSG_SIZE_OVERLAY_ADVANCED="Bitte die Größe der Overlay-Partition angeben, auf der Ihre\nDaten permanent gespeichert werden.\n(mindestens 400MB, frei: %sMB)."
MSG_CRYPT_OVERLAY="Sollen Ihre eigenen Daten mit AES256 (=Advanced Encryption Standard 256bit, s.a.\nhttp://csrc.nist.gov/encryption/aes/) verschlüsselt werden?\n\nHierzu ist die Eingabe eines Passwortes beim Einrichten sowie beim\nSystemstart erforderlich.\n\nOhne Kenntnis des korrekten Passwortes ist der Zugriff auf die Daten\nnicht möglich, dadurch sind die möglicherweise sensiblen Daten einerseits bei\nVerlust des Datenträgers vor unbefugtem Zugriff geschützt, andererseits sind\nsie bei vergessenem Passwort auch nicht mehr vefügbar."
MSG_PASSWORD="AES256 Verschlüsselungs Passwort (mindestens 8 Zeichen):"
MSG_PASSWORD2="Bitte Passwort zur Sicherheit noch einmal eingeben:"
MSG_PASSWORDS_NOMATCH="Die beiden Passwörter stimmen nicht überein oder sind zu kurz.\nBitte noch einmal versuchen."
MSG_OVERLAY="Erzeuge Overlay [%s MB]..."
MSG_QUESTION_PARTITION="Datenträger partitionieren und formatieren?\nWARNUNG: Alle Daten werden dabei gelöscht!\nNein = nur KNOPPIX-Daten auf ggf. vorhandene Partition kopieren"
MSG_QUESTION_PARTITION_ADVANCED="Datenträger neu partitionieren und formatieren?
WARNUNG: Alle Daten werden dabei gelöscht!\nNein = Abbrechen"
MSG_QUESTION_REALLY_FORMAT="Möchten Sie dies wirklich tun?
WARNUNG: Alle Daten auf dem Datenträger werden dabei gelöscht!"
MSG_FORMAT="Formatiere"
MSG_PARTITION="Partitioniere"
MSG_ERROR_NODISK="Keine Flashdisk(s) gefunden."
MSG_ERROR_NODISK="Keine Flashdisk(s) gefunden."
MSG_ERROR_INCOMPATIBLE="Das Flash-Medium ist nicht richtig partitioniert.\nDie erste (primäre) Partition muss DOS/FAT32 sein."
MSG_FAT_EXISTS="Ein FAT32-Dateisystem existiert auf"
MSG_KNOPPIX_EXISTS="Ein installiertes KNOPPIX-System existiert auf"
MSG_OVERLAY_IMAGE_EXISTS="Ein Overlay-Image ist vorhanden."
MSG_ENCRYPTED_OVERLAY_IMAGE_EXISTS="Ein verschlüsseltes Overlay-Image ist vorhanden."
MSG_OVERLAY_PARTITION_EXISTS="Eine Overlay-Partition ist vorhanden."
MSG_UPDATE_SELECT="Möchten Sie die bestehende KNOPPIX-Installation aktualisieren?"
MSG_UPDATE_CLEAN="NUR persönliche Daten und Einstellungen (\$HOME) behalten. (empfohlen)"
MSG_UPDATE_KEEP="ALLE, auch inkompatible Modifikationen behalten (nicht empfohlen)"
MSG_UPDATE_DELETE="Alles löschen / Neu (alle alten Daten gehen verloren!)"
MSG_METHOD_SELECT="Bitte wählen Sie die Installationsmethode:"
METHOD_NEW_IMAGE="Installation auf FAT32 mit (optionaler) Overlay-Datei <4GB."
METHOD_NEW_PARTITION="Installation auf FAT32 mit zusätzlicher Overlay-Partition. (empfohlen)"
METHOD_NOTHING="Kein Overlay (read-only wie CD/DVD)."
MSG_SIZE_OVERLAY_PARTITION="Bitte geben Sie die gewünschte Größe der Overlay-Partition ein (MB)."
MSG_ERROR_TOOSMAL="Die Overlay-Größe ist zu klein!\n(mindestens 400MB erforderlich)"
MSG_ERROR_BOOT_TOOSMAL="Die Größe der Bootpartition ist zu klein für das Update!"
MSG_ERROR_CANNOT_MOUNT_OVERLAY="Kann das Overlay auf dem Zieldatenträger nicht einbinden!\nFalsches Passwort?"
;;
*)
MSG_INTRO="flash-knoppix: This program creates a bootable copy of KNOPPIX\non an USB flash disk or hard disk, optionally with an overlay\nfor storing personal data in form of a container or separate\npartition on the target media, with or without encryption.\n\nPlease select options:"
MSG_ALLOWHD="Allow installation also on fixed hard disks"
MSG_NOALLOWHD="Allow installation only on removable devices"
MSG_TARGET="flash-knoppix: Install KNOPPIX compressed to flash disk.\n\nPlease select desired target device:"
INFO_TARGET="Target:"
MSG_READY="Finished.
You can now remove device from drive."
MSG_MOUNTED="is already mounted."
MSG_CHECKING="Checking"
MSG_SELECT="Please enter directory containing KNOPPIX files."
MSG_BOOTREC="Creating boot record on"
MSG_NOTFOUND="No boot configuration found (no boot/isolinux/isolinux.cfg), bootloader will probably not work."
MSG_WRITING="Writing data..."
MSG_SIZE_OVERLAY="KNOPPIX can use an \"Overlay\"-file for storing data permanently.\nIf you want this, please enter desired size (minimum 200MB, free: %sMB)."
MSG_SIZE_OVERLAY_ADVANCED="Please enter the size of the Overlay partition\nfor storing your data permanently.\n(minimum 400MB, free: %sMB)."
MSG_CRYPT_OVERLAY="Would you like to encrypt the overlay using AES256 (=Advanced Encryption\nStandard 256bit, http://csrc.nist.gov/encryption/aes/)?\n\nFor this type of encryption, entering a password for creation as well as\nat system start is necessary.\n\nWithout knowing this password, reading saved data is not possible.\nBecause of that, encrypted data is still safe against unauthorized\naccess in case the storage device containig the data gets lost or stolen.\nOn the other hand, all saved data is inaccessible if you forget the password,\nand there is no way to recover."
MSG_PASSWORD="AES256 Encryption Key (minimum 8 chars):"
MSG_PASSWORD2="Please enter the same password again, just to be sure:"
MSG_PASSWORDS_NOMATCH="Passwords are not identical, or just too short.\nPlease try again."
MSG_OVERLAY="Creating overlay [%s MB]..."
MSG_QUESTION_PARTITION="Partition and format device?\nCAUTION: All data will be erased!\nNo = only copy KNOPPIX data to existing partition"
MSG_QUESTION_PARTITION_ADVANCED="Repartition and format device?\nCAUTION: All data will be erased!\nNo = Exit program"
MSG_QUESTION_REALLY_FORMAT="Do you really want to do this?\nWARNING: ALL DATA ON WILL BE ERASED!"
MSG_FORMAT="Formatting"
MSG_PARTITION="Partitioning"
MSG_ERROR_NODISK="No flash disk(s) found."
MSG_ERROR_INCOMPATIBLE="Flashdisk is not partitioned properly.\nThe first (primary) partition must be DOS/FAT32."
MSG_FAT_EXISTS="A FAT32 file system exists on"
MSG_KNOPPIX_EXISTS="An installed KNOPPIX system exists on"
MSG_OVERLAY_IMAGE_EXISTS="An Overlay image is present."
MSG_ENCRYPTED_OVERLAY_IMAGE_EXISTS="An encrypted Overlay image is present."
MSG_OVERLAY_PARTITION_EXISTS="An overlay partition is present."
MSG_METHOD_SELECT="Please select installation method:"
MSG_UPDATE_SELECT="Do you want to update the currently installed KNOPPIX installation?"
MSG_UPDATE_CLEAN="Keep ONLY personal data and settings (\$HOME) (recommended)"
MSG_UPDATE_KEEP="Keep ALL modifications, even if incompatible (not recommended)"
MSG_UPDATE_DELETE="Delete everything / New (all old data will be lost!)"
METHOD_NEW_IMAGE="Installation on FAT32 with (optional) overlay file <4GB."
METHOD_NEW_PARTITION="Installation on FAT32 with additional overlay partition."
METHOD_NOTHING="No Overlay (read-only like CD/DVD)."
MSG_SIZE_OVERLAY_PARTITION="Please enter desired size of overlay partition (MB)."
MSG_ERROR_BOOT_TOOSMAL="Size of boot partition is too small for update!"
MSG_ERROR_TOOSMAL="Overlay size is too small!\n(minimum 400MB required)"
MSG_ERROR_CANNOT_MOUNT_OVERLAY="Cannot mount overlay from target device!\nWrong password?"
;;
esac
TMP="/tmp/flash-knoppix.$$.tmp"
TMPMOUNT="/tmp/flash-knoppix.$$.tmpmount"
TMPMOUNT2="/tmp/flash-knoppix.$$.tmpmount2"
TMPSRCMOUNT="/tmp/flash-knoppix.$$.src.tmpmount"
PARTTYPE=msdos
# PARTTYPE=gpt
FLASH=""
TITLE="flash-knoppix"
if [ -n "$DISPLAY" ] && type -p zenity >/dev/null 2>&1; then
ICON="/usr/share/icons/flash-knoppix.xpm"
[ -r "$ICON" ] && ICON="--window-icon=$ICON" || ICON=""
fi
# dialog_yesno title info
function dialog_yesno(){
local title="$1" info="$2"
if [ -n "$DISPLAY" ]; then
zenity $ICON --question --no-wrap --width=600 --title="$title" --text="$info" 1>&2 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --yesno "$info" 23 75
fi
}
# dialog_info title info
function dialog_info(){
local title="$1" info="$2"
if [ -n "$DISPLAY" ]; then
zenity $ICON --info --no-wrap --width=600 --title="$title" --text="$info" 1>&2 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --msgbox "$info" 23 65
fi
}
# dialog_info_timeout title info
function dialog_info_timeout(){
local title="$1" info="$2"
if [ -n "$DISPLAY" ]; then
zenity $ICON --timeout=5 --info --no-wrap --width=600 --title="$title" --text="$info" 1>&2 2>/dev/null
else
dialog --timeout 5 --backtitle "$TITLE" --title "$title" --msgbox "$info" 23 65
fi
}
# dialog_scale title info [min [max [current]]]
function dialog_scale(){
local title="$1" info="$2" min="$3" max="$4" current="$5"
if [ -n "$DISPLAY" ]; then
zenity $ICON --scale --width=550 --title="$title" --text="$info" --min-value="$min" --max-value="$max" --step=50 --value="$current" 1>&2 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --inputbox "$info" 23 75 "$current"
fi
}
function dialog_password(){
local title="$1" info="$2"
if [ -n "$DISPLAY" ]; then
zenity $ICON --entry --width=550 --title="$title" --text="$info" 1>&2 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --inputbox "$info" 23 75 "$5"
fi
}
# dialog_error title info
function dialog_error(){
local title="$1" info="$2"
if [ -n "$DISPLAY" ]; then
zenity $ICON --error --no-wrap --width=600 --title="$title" --text="$info" 1>&2 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --msgbox "$info" 23 65
fi
}
# dialog_menu title wrapped_text menuitem1 description1 ...
function dialog_menu(){
local title="$1" info="$2"
shift 2
if [ -n "$DISPLAY" ]; then
for item in "$@"; do echo "$item"; done | { zenity $ICON --list --width=550 --height=280 --hide-header --title="$title" --text="$info" --column="" --column="" 1>&2 2>/dev/null; }
else
dialog --backtitle "$TITLE" --title "$title" --menu "$info" 23 75 8 "$@"
fi
}
# dialog_gauge title info
function dialog_gauge(){
local title="$1" info="$2"
shift 2
if [ -n "$DISPLAY" ]; then
zenity $ICON --progress --width=550 --title="$title" --auto-close --no-cancel --text="$info" 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --gauge "$info" 23 75 8 "$@"
fi
}
# dialog_dselect title info
function dialog_dselect(){
local title="$1" info="$2"
if [ -n "$DISPLAY" ]; then
zenity $ICON --file-selection --filename=. --directory --width=550 --title="$title" 1>&2 2>/dev/null
else
dialog --backtitle "$TITLE" --title "$title" --dselect . 23 75
fi
}
# dialog_options title info checked1 option1 checked2 option2 ...
# zenity --list --checklist --hide-header --text="Bitte Option angeben:" --column=option --column=beschreibung TRUE Eins FALSE Zwei TRUE Drei
function dialog_options(){
local title="$1" info="$2"
shift 2
if [ -n "$DISPLAY" ]; then
for item in "$@"; do echo "$item"; done | { zenity $ICON --list --checklist --width=550 --height=280 --hide-header --title="$title" --text="$info" --column="" --column="" 1>&2 2>/dev/null; }
else
dialog --backtitle "$TITLE" --title "$title" --menu "$info" 23 75 8 "$@"
fi
}
ERROR=""
bailout(){
cd $HOME
umount "$TMPMOUNT" 2>/dev/null
umount -d "$TMPMOUNT2" 2>/dev/null
umount -d "$TMPSRCMOUNT" 2>/dev/null
for i in /dev/loop*; do losetup -d "$i"; done >/dev/null 2>&1
# eject "$FLASH" 2>/dev/null
rmdir "$TMPMOUNT" 2>/dev/null
rmdir "$TMPSRCMOUNT" 2>/dev/null
killgauge
case "$1" in
0) # Normal end of program
dialog_info "$TITLE" "$DEVICE_INFO\n\n$MSG_READY";;
1) # Cancel with no message
true;;
*) # Error
dialog_error "$TITLE" "$DEVICE_INFO\n\n$ERROR";;
esac
rm -f "$TMP" "$TMP.done" "$TMP.err"
exit $1
}
function gauge(){
rm -f "$TMP.done"
status=0
while [ ! -e "$TMP.done" ]; do echo "$((status / 100))" ; status="`expr \( 10000 - $status \) / 100 + $status`"; sleep 1; done | dialog_gauge "$TITLE" "$1" &
}
# Stop status bar
function killgauge(){
touch "$TMP.done" ; wait ; rm -f "$TMP.done"
}
DEVICE_VENDOR=""
DEVICE_MODEL=""
DEVICE_SIZE=""
DEVICE_DEV=""
DEVICE_INFO=""
FAT_EXISTS=""
KNOPPIX_EXISTS=""
OVERLAY_EXISTS=""
OVERLAY_PARTITION=""
OVERLAY_ENCRYPTED=""
# getstatus /dev/device - reports current flash disk status in variables
function getstatus(){
local dev="${1##*/}"
DEVICE_DEV="$1"
DEVICE_VENDOR="$(cat /sys/block/$dev/device/vendor 2>/dev/null)"
DEVICE_INFO="$dev:"
[ -n "$DEVICE_VENDOR" ] && DEVICE_INFO="$DEVICE_INFO $(echo $DEVICE_VENDOR)"
DEVICE_MODEL="$(cat /sys/block/$dev/device/model 2>/dev/null)"
[ -n "$DEVICE_MODEL" ] && DEVICE_INFO="$DEVICE_INFO $(echo $DEVICE_MODEL)"
DEVICE_SIZE="$(awk '{print ($1 / 2048)}' /sys/block/$dev/size 2>/dev/null)"
[ -n "$DEVICE_SIZE" ] && DEVICE_INFO="$DEVICE_INFO ($(echo "${DEVICE_SIZE}MB"))"
[ "$DEVICE_SIZE" -lt 10 ] >/dev/null 2>&1 || DEVICE_SIZE=0
mkdir -p "$TMPMOUNT"
mount -r -t vfat -o shortname=winnt "${1}1" "$TMPMOUNT" >/dev/null 2>&1
sleep 1
if mountpoint -q "$TMPMOUNT"; then
FAT_EXISTS="true"
if [ -r "$TMPMOUNT"/KNOPPIX/KNOPPIX ]; then
KNOPPIX_EXISTS="true"
local ext
for ext in aes img inf; do
local datafile="$TMPMOUNT/KNOPPIX/knoppix-data.$ext"
if [ -r "$datafile" ]; then
local mp="" fs="" opts=""
OVERLAY_EXISTS="$ext"
if [ "$ext" = "inf" ]; then
while read OVERLAY_PARTITION mp fs opts; do
if [ -z "$mp" -o "$mp" = "/KNOPPIX-DATA" -o "$mp" = "KNOPPIX-DATA" ]; then
case "$opts" in *encryption*) OVERLAY_ENCRYPTED="true" ;; esac
break
else
OVERLAY_PARTITION=""
fi
done < "$datafile"
elif [ "$ext" = "aes" ]; then
OVERLAY_ENCRYPTED="true"
fi
break
fi
done
fi
umount "$TMPMOUNT" >/dev/null 2>&1
fi
}
function read_method(){
local TEXT="$DEVICE_INFO\n"
[ -n "$FAT_EXISTS" ] && TEXT="${TEXT}\n${MSG_FAT_EXISTS} ${DEVICE_DEV}1"
[ -n "$KNOPPIX_EXISTS" ] && TEXT="${TEXT}\n${MSG_KNOPPIX_EXISTS} ${DEVICE_DEV}1"
case "$OVERLAY_EXISTS" in
img) TEXT="${TEXT}\n${MSG_OVERLAY_IMAGE_EXISTS}" ;;
aes) TEXT="${TEXT}\n${MSG_ENCRYPTED_OVERLAY_IMAGE_EXISTS}" ;;
inf) TEXT="${TEXT}\n${MSG_OVERLAY_PARTITION_EXISTS}" ;;
esac
TEXT="${TEXT}\n\n$MSG_METHOD_SELECT"
local LIST=( "p" "$METHOD_NEW_PARTITION" "i" "$METHOD_NEW_IMAGE" "n" "$METHOD_NOTHING" )
rm -f "$TMP"
dialog_menu "$TITLE" "$TEXT" "${LIST[@]}" 2>"$TMP" || { rm -f "$TMP"; return 1; }
read "$1" <"$TMP"; rm -f "$TMP"
}
function read_update(){
local TEXT="$DEVICE_INFO\n"
[ -n "$FAT_EXISTS" ] && TEXT="${TEXT}\n${MSG_FAT_EXISTS} ${DEVICE_DEV}1"
[ -n "$KNOPPIX_EXISTS" ] && TEXT="${TEXT}\n${MSG_KNOPPIX_EXISTS} ${DEVICE_DEV}1"
case "$OVERLAY_EXISTS" in
img) TEXT="${TEXT}\n${MSG_OVERLAY_IMAGE_EXISTS}" ;;
aes) TEXT="${TEXT}\n${MSG_ENCRYPTED_OVERLAY_IMAGE_EXISTS}" ;;
inf) TEXT="${TEXT}\n${MSG_OVERLAY_PARTITION_EXISTS}" ;;
esac
TEXT="${TEXT}\n\n$MSG_UPDATE_SELECT"
local LIST=( "h" "$MSG_UPDATE_CLEAN" "a" "$MSG_UPDATE_KEEP" "n" "$MSG_UPDATE_DELETE" )
rm -f "$TMP"
dialog_menu "$TITLE" "$TEXT" "${LIST[@]}" 2>"$TMP" || { rm -f "$TMP"; return 1; }
read "$1" <"$TMP"; rm -f "$TMP"
}
function intro_read_allow_hd(){
local LIST=("r" "$MSG_NOALLOWHD" "h" "$MSG_ALLOWHD")
rm -f "$TMP"
dialog_menu "$TITLE" "$MSG_INTRO" "${LIST[@]}" 2>"$TMP" || { rm -f "$TMP"; return 1; }
read "$1" <"$TMP"; rm -f "$TMP"
}
# setup_loop file_or_blockdevice [encrypted]
# Returns true and saves loopback device in global variable LOOP
# expects password from stdin
function setup_loop(){
LOOP=""
LOOP="$(/sbin/losetup -f 2>>"$TMP.err")" || { ERROR="$(<$TMP.err)"; bailout 2; }
if [ -n "$2" ]; then # Encrypted
local m mods=""
for m in loop cryptoloop aes_generic aes_i586 cbc; do
[ -d /sys/module/"$m" ] || mods="$mods $m"
done
[ -n "$mods" ] && /sbin/modprobe $mods >/dev/null 2>&1
tr -d '\n\r' | /sbin/losetup -p 0 -e aes -k 256 "$LOOP" "$1" 2>>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
else # No encryption
/sbin/losetup "$LOOP" "$1" 2>>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
fi
return 0
}
usage(){
echo "Usage: $0 [-a] [-f] [-m i|p|n] [-p mb] [image|dir] [target_device]" >&2
echo " -a Allow fixed disks" >&2
echo " -f Force overwrite, no questions (batch mode)" >&2
echo " -m i Method: Create overlay image" >&2
echo " -m p Method: Create overlay partition (recommended)" >&2
echo " -m n Method: No overlay (read only)" >&2
echo " -p mb Overlay partition or image size in MB >= 200" >&2
echo " image.iso Loopmount source ISO file" >&2
echo " dir Source data directory containing files" >&2
echo " target_device Destination block device (flash disk)" >&2
exit 1
}
### MAIN ###
[ "`id -u`" != "0" ] && exec sudo "$0" "$@"
unset SUDO_COMMAND
ALLOWHD=""
SIZE=""
FORCE=""
METHOD=""
# Ask for method, i=overlay image, p=overlay partition
# Parse options
while [ -n "$1" ]; do
case "$1" in
--help|-h) usage ;;
-a) ALLOWHD="true" ;;
-f) FORCE="true" ;;
-m) shift; case "$1" in i|p|n) METHOD="$1";; *) usage;; esac ;;
-p) shift; [ "$1" -ge 200 ] && SIZE="$1" ;;
*) # ISO file, SRC dir or destination device
if [ -b "$1" ]; then # Block device, destination
FLASH="$1"
elif [ -r "$1" ]; then # It may be an ISO, mount it.
mkdir -p "$TMPSRCMOUNT"
mount -o loop,ro "$1" "$TMPSRCMOUNT" && cd "$TMPSRCMOUNT"
elif [ -d "$1" ]; then
cd "$1"
else
usage
fi
;;
esac
shift || break
done
if [ ! -n "$FLASH" -o ! -b "$FLASH" ]; then
if [ -z "$ALLOWHD" ]; then
intro_read_allow_hd hd || bailout 1
[ "$hd" = "h" ] && ALLOWHD="true" || ALLOWHD=""
fi
DEVICELIST=()
count=0
for i in $(ls -1d /sys/block/sd? 2>/dev/null); do
device="${i##/sys/block/}"
# Safety check
if [ "$(cat /sys/block/$device/removable)" = "0" ] && [ -z "$ALLOWHD" -a -z "$FORCE" -a -z "$OVERRIDE" ]; then
# This is a fixed disk!
continue
fi
# Don't show the USB stick we are running from
grep -q "$i .* /mnt-system" /proc/mounts && continue
DEVICELIST[$((count++))]="$device"
DEVICELIST[$((count++))]="$(cat $i/device/vendor 2>/dev/null) $(cat $i/device/model 2>/dev/null) ($(awk '{print ($1 / 2048) "MB"}' $i/size 2>/dev/null))"
done
rm -f "$TMP"
if [ -n "${DEVICELIST[*]}" ]; then
while ! [ -b "$FLASH" ]; do
dialog_menu "$TITLE" "
$MSG_TARGET
" "${DEVICELIST[@]}" 2>"$TMP" || bailout 1
read FLASH <"$TMP"; rm -f "$TMP"
FLASH="/dev/$FLASH"
done
else
ERROR="$MSG_ERROR_NODISK"
bailout 2
fi
fi
if grep -q "^${FLASH}" /proc/mounts && ! umount "${FLASH}1"; then
ERROR="$FLASH $MSG_MOUNTED"
bailout 2
fi
if [ ! -r KNOPPIX/KNOPPIX -a -r /mnt-system/KNOPPIX/KNOPPIX ]; then
SRC=/mnt-system
cd "$SRC"
else
while [ ! -r KNOPPIX/KNOPPIX ]; do
dialog_dselect "$MSG_SELECT" "$MSG_SELECT" 2>"$TMP" || bailout 1
SRC="$(<$TMP)"
[ -d "$SRC" ] && cd "$SRC"
done
fi
# Get flash status
gauge "$MSG_CHECKING $FLASH..."
getstatus "${FLASH}"
killgauge
UPDATE=""
# If already installed, ask about update
if [ -z "$FORCE" -a -n "$KNOPPIX_EXISTS" ]; then
echo "Ask for update" >&2
read_update UPDATE || bailout 1
fi
if [ -n "$UPDATE" -a "$UPDATE" != "n" ]; then
METHOD="$UPDATE"
# (Re-) check size of boot partition
total="$(awk '{print int($1 / 2048)}' /sys/block/"${FLASH##*/}/${FLASH##*/}1"/size 2>/dev/null)"
# Add 10% filesystem overhead
ksize="$(du -sm --exclude='knoppix-data.*' . 2>/dev/null | awk '{size=$1}END{print int(size*1.1)}')"
let avail=total-ksize
if [ "$avail" -lt 100 ]; then
ERROR="${FLASH}1:\n$MSG_ERROR_BOOT_TOOSMAL"
bailout 2
fi
elif [ -z "$METHOD" ]; then
echo "Ask for install method" >&2
# Ask for method, i=overlay image, p=overlay partition n=likeDVD
while true; do
read_method METHOD || bailout 1
[ -n "$METHOD" ] && break
done
fi
mkdir -p "$TMPMOUNT"
# Use ionice, be friendly to our multitasking
IONICE=""
type -p ionice >/dev/null 2>&1 && IONICE="ionice -c 3"
echo "Ask for partitioning" >&2
if [ "i" = "$METHOD" -o "n" = "$METHOD" ]; then
# Overlay image or "no overlay" method selected
if [ -n "$FORCE" ] || { dialog_yesno "$TITLE" "$DEVICE_INFO\n\n$MSG_QUESTION_PARTITION" && dialog_yesno "$TITLE" "$DEVICE_INFO\n\n$MSG_QUESTION_REALLY_FORMAT"; }; then
gauge "$DEVICE_INFO\n\n$MSG_PARTITION $FLASH..."
dd if=/dev/zero of="$FLASH" bs=4M count=1 >/dev/null 2>&1
blockdev --flushbufs "$FLASH"
parted "$FLASH" 2>"$TMP.err" <<EOT
mktable $PARTTYPE
mkpart primary fat32 2048s -0
set 1 boot on
quit
EOT
# sfdisk -u M "$FLASH" 2>"$TMP.err" <<EOT
#,,c,*
#EOT
if [ "$?" != 0 ]; then
ERROR="$(<$TMP.err)"; bailout 2
fi
rm -f "$TMP.err"
blockdev --flushbufs "$FLASH"
sleep 10
# udev may need some additional time to settle down after repartitioning
udevadm settle --timeout=20
$IONICE mkdosfs -F32 -n "KNOPPIX" "${FLASH}1" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
$IONICE blockdev --flushbufs "${FLASH}1"
killgauge
elif [ -n "$FAT_EXISTS" ]; then # FAT exists -> just set bootable later
MAKE_BOOTABLE="true"
else # fail
ERROR="${FLASH}:\n$MSG_ERROR_INCOMPATIBLE"; bailout 2
fi
elif [ "p" = "$METHOD" ]; then
total="$(awk '{print int($1 / 2048)}' /sys/block/"${FLASH##*/}"/size 2>/dev/null)"
# Add 10% filesystem overhead
ksize="$(du -sm --exclude='knoppix-data.*' . 2>/dev/null | awk '{size=$1}END{print int(size*1.1)}')"
let avail=total-ksize
let avail-=200
if [ "$avail" -lt 400 ]; then
ERROR="${FLASH}:\n$MSG_ERROR_TOOSMAL"
bailout 2
fi
if [ -n "$FORCE" ] || { dialog_yesno "$TITLE" "$DEVICE_INFO\n\n$MSG_QUESTION_PARTITION_ADVANCED" && dialog_yesno "$TITLE" "$DEVICE_INFO\n\n$MSG_QUESTION_REALLY_FORMAT"; }; then
if [ -z "$SIZE" ]; then
rm -f "$TMP"
dialog_scale "$TITLE" "$(printf "$MSG_SIZE_OVERLAY_ADVANCED" "$avail")" 400 "$avail" "$avail" 2>"$TMP" || bailout 1
read SIZE <"$TMP"
[ "$SIZE" -ge 400 ] 2>/dev/null || SIZE="400"
fi
[ "$SIZE" -gt "$avail" ] && SIZE="$avail"
gauge "$DEVICE_INFO\n$MSG_PARTITION $FLASH..."
dd if=/dev/zero of="$FLASH" bs=4M count=1 >/dev/null 2>&1
blockdev --flushbufs "$FLASH"
parted "$FLASH" 2>"$TMP.err" <<EOT
mktable $PARTTYPE
mkpart primary fat32 2048s $((total-SIZE))M
set 1 boot on
mkpart primary reiserfs $((total-SIZE))M -0
quit
EOT
# sfdisk -u M "$FLASH" 2>"$TMP.err" <<EOT
#,$((total-SIZE)),c,*
#,,83,
#EOT
if [ "$?" != 0 ]; then
ERROR="$(<$TMP.err)"; bailout 2
fi
rm -f "$TMP.err"
blockdev --flushbufs "$FLASH"
sleep 10
# udev may need some additional time to settle down after repartitioning
udevadm settle --timeout=20
killgauge
gauge "$DEVICE_INFO\n$MSG_FORMAT $FLASH partition 1..."
$IONICE mkdosfs -F32 -n "KNOPPIX" "${FLASH}1" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
$IONICE blockdev --flushbufs "${FLASH}1"
killgauge
else
bailout 1
fi
fi
echo "(Re-)create boot loader, first remove the old one" >&2
# (Re-)create boot loader, first remove the old one
gauge "$DEVICE_INFO\n$MSG_BOOTREC $FLASH..."
rm -f "$TMP.err"
mount -t vfat -o shortname=winnt "${FLASH}1" "$TMPMOUNT" 2>"$TMP.err" || { killgauge; ERROR="${FLASH}:\n$MSG_ERROR_INCOMPATIBLE"; bailout 2; }
[ -f "$TMPMOUNT"/ldlinux.sys ] && rm -f "$TMPMOUNT"/ldlinux.sys
blockdev --flushbufs "${FLASH}1"
sleep 2
umount "$TMPMOUNT"
rm -f "$TMP.err"
syslinux "${FLASH}1" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
blockdev --flushbufs "${FLASH}1"
sleep 2
killgauge
echo "Mount boot partition" >&2
if [ -r boot/syslinux/syslinux.cfg -o -r boot/isolinux/isolinux.cfg ]; then
mount -t vfat -o shortname=winnt "${FLASH}1" "$TMPMOUNT" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
# Update methods
if [ "$METHOD" = "h" -a -n "$OVERLAY_EXISTS" ]; then
# Need to mount overlay image or partition and delete all but home
echo "Mount KNOPPIX overlay" >&2
mkdir -p "$TMPMOUNT2"
while true; do # Stay here until mount of overlay succeeds (never lose data)
rm -f "$TMP"
if [ -n "$OVERLAY_ENCRYPTED" ]; then
dialog_password "$TITLE" "$MSG_PASSWORD" 2>"$TMP" || { rm -f "$TMP"; CRYPT=""; break; }
else
touch "$TMP"
fi
fs=auto
case "$OVERLAY_EXISTS" in
img|aes) setup_loop "$TMPMOUNT"/KNOPPIX/knoppix-data."$OVERLAY_EXISTS" "$OVERLAY_ENCRYPTED" <"$TMP"; fs=ext2;;
inf) setup_loop "${FLASH}$OVERLAY_PARTITION" "$OVERLAY_ENCRYPTED" <"$TMP"; fs=reiserfs;;
esac
mount -t "$fs" "$LOOP" "$TMPMOUNT2" && break
dialog_info_timeout "$TITLE" "$DEVICE_INFO\n\n$MSG_ERROR_CANNOT_MOUNT_OVERLAY"
[ -n "$OVERLAY_ENCRYPTED" ] || bailout 1
done
echo "Delete overlay data except /home" >&2
for i in "$TMPMOUNT2"/* "$TMPMOUNT2"/.??*; do
[ -e "$i" ] || continue
case "$i" in */home|*/home/) true;; *) rm -rff "$i";; esac
done
sleep 2
umount -d "$TMPMOUNT2" 2>/dev/null
fi
echo "Now copy all the files (except for overlays)" >&2
gauge "$DEVICE_INFO\n$MSG_WRITING"
[ "$METHOD" = "h" ] && rm -ff "$TMPMOUNT"/KNOPPIX/[Kk][Nn][Oo][Pp][Pp][Ii][Xx][0-9] 2>/dev/null
$IONICE cp -Lrf boot "$TMPMOUNT"/ 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
if [ -r index.html -a ! -e "$TMPMOUNT"/index.html ]; then
$IONICE cp -Lf index.html "$TMPMOUNT"/ 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
fi
if [ -d efi ]; then
$IONICE cp -Lrf efi "$TMPMOUNT"/ 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
fi
mkdir "$TMPMOUNT"/KNOPPIX 2>/dev/null
for i in KNOPPIX/*; do
# Skip knoppix-data.*
case "$i" in KNOPPIX/[Kk][Nn][Oo][Pp][Pp][Ii][Xx]-[Dd][Aa][Tt][Aa].*) true;; *)
$IONICE cp -Lrf "$i" "$TMPMOUNT"/KNOPPIX/ 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; } ;;
esac
done
if [ ! -r boot/syslinux/syslinux.cfg -a -r boot/isolinux/isolinux.cfg ]; then
[ -d "$TMPMOUNT"/boot/syslinux ] && rm -rf "$TMPMOUNT"/boot/syslinux
mv -f "$TMPMOUNT"/boot/isolinux "$TMPMOUNT"/boot/syslinux
mv -f "$TMPMOUNT"/boot/syslinux/isolinux.cfg "$TMPMOUNT"/boot/syslinux/syslinux.cfg
rm -f "$TMPMOUNT"/boot/syslinux/isolinux.* "$TMPMOUNT"/boot/syslinux/*.cat "$TMPMOUNT"/boot/isolinux.* "$TMPMOUNT"/boot/*.cat
fi
killgauge
else
ERROR="$MSG_NOTFOUND"
bailout 3
fi
# If we don't already have an overlay, ask to create one
if [ "$METHOD" = "n" ]; then
rm -f "$TMPMOUNT"/KNOPPIX/knoppix-data.*
elif [ ! -e "$TMPMOUNT"/KNOPPIX/knoppix-data.img -a ! -e "$TMPMOUNT"/KNOPPIX/knoppix-data.aes -a ! -e "$TMPMOUNT"/KNOPPIX/knoppix-data.inf ]; then
if [ "i" = "$METHOD" ]; then # Image creation: Ask for size
avail="$(df -m "$TMPMOUNT" | awk '{size=$4}END{print size - 1}')"
# At least 200MB, but not more than 4GB is allowed on a FAT32 file system
[ "$avail" -ge 200 ] 2>/dev/null || bailout 0
[ "$avail" -le 4000 ] || avail=4000
rm -f "$TMP"
if [ -z "$SIZE" ]; then
dialog_scale "$TITLE" "$(printf "$MSG_SIZE_OVERLAY" "$avail")" 200 "$avail" "$avail" 2>"$TMP" || bailout 1
read SIZE <"$TMP"
fi
[ "$SIZE" -ge 200 ] 2>/dev/null || SIZE="200"
[ "$SIZE" -le 4000 ] 2>/dev/null || SIZE="$avail"
else
SIZE="$(awk '{print int($1 / 2048)}' /sys/block/"${FLASH##*/}"/"${FLASH##*/}2"/size 2>/dev/null)"
fi
if [ -z "$FORCE" ]; then
dialog_yesno "$TITLE" "$MSG_CRYPT_OVERLAY" && CRYPT=yes || CRYPT=""
fi
if [ -n "$CRYPT" ]; then
pw1=""; pw2=""; len=0
while [ -z "$pw1" -o -z "$pw2" -o x"$pw1" != x"$pw2" -o "$len" -lt 4 ]; do
rm -f "$TMP"
[ -n "$pw1" ] && dialog_info_timeout "$TITLE" "$MSG_PASSWORDS_NOMATCH"
dialog_password "$TITLE" "$MSG_PASSWORD" 2>"$TMP" || { rm -f "$TMP"; CRYPT=""; break; }
read pw1 <"$TMP"; rm -f "$TMP"
dialog_password "$TITLE" "$MSG_PASSWORD2" 2>"$TMP"
read pw2 <"$TMP"; len="$(wc -c "$TMP" | awk '{print $1}')"
# Don't delete $TMP yet, we need it for losetup
done
fi
gauge "$DEVICE_INFO\n$(printf "$MSG_OVERLAY" "$SIZE")"
if [ -n "$CRYPT" ]; then
if [ "i" = "$METHOD" ]; then # Image creation: Create random data
$IONICE dd if=/dev/urandom of="$TMPMOUNT"/KNOPPIX/knoppix-data.aes bs=1M count="$SIZE" >/dev/null 2>"$TMP.err"
setup_loop "$TMPMOUNT"/KNOPPIX/knoppix-data.aes encrypted <"$TMP"
rm -f "$TMP"
$IONICE mke2fs -F -m 0 "$LOOP" 2>>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
$IONICE blockdev --flushbufs "$LOOP"
sleep 2
/sbin/losetup -d "$LOOP"
elif [ "p" = "$METHOD" ]; then # Data partition
# $IONICE dd if=/dev/urandom of="$LOOP" bs=1M >/dev/null 2>"$TMP.err"
# Overwriting the entire partition with random data may be a waste of time,
# so let's just format it.
setup_loop "${FLASH}2" encrypted <"$TMP"
rm -f "$TMP"
$IONICE mkreiserfs -s 513 -f -f -l "KNOPPIX-DATA" "$LOOP" 2>>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
$IONICE blockdev --flushbufs "$LOOP"
/sbin/losetup -d "$LOOP"
# Create fstab style entry
echo "2 /KNOPPIX-DATA reiserfs encryption=aes" >> "$TMPMOUNT"/KNOPPIX/knoppix-data.inf
fi
else # No encryption
if [ "i" = "$METHOD" ]; then
$IONICE dd if=/dev/zero of="$TMPMOUNT"/KNOPPIX/knoppix-data.img bs=1M count="$SIZE" >/dev/null 2>"$TMP.err"
$IONICE mke2fs -F -m 0 "$TMPMOUNT"/KNOPPIX/knoppix-data.img 2>>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
elif [ "p" = "$METHOD" ]; then
$IONICE mkreiserfs -s 513 -f -f -l "KNOPPIX-DATA" "${FLASH}2" 2>>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
$IONICE blockdev --flushbufs "${FLASH}2"
echo "2 /KNOPPIX-DATA reiserfs" >> "$TMPMOUNT"/KNOPPIX/knoppix-data.inf
fi
fi
fi
# Flush and umount file system
blockdev --flushbufs "${FLASH}1"
sleep 2
umount "$TMPMOUNT"
# Create MBR
ms-sys -s "${FLASH}" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
blockdev --flushbufs "${FLASH}"
sleep 2
# Finally mark partition 1 as bootable, if not already done.
# this may cause another udev run, which we can ignore here
if [ -n "$MAKE_BOOTABLE" ]; then
sfdisk -A1 "${FLASH}" 2>"$TMP.err" || { ERROR="$(<$TMP.err)"; bailout 2; }
blockdev --flushbufs "${FLASH}"
fi
# Give block layer time to settle down
udevadm settle --timeout=20
sleep 4
bailout 0
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
iEYEABECAAYFAlQS96AACgkQN5jj11fjcIcRswCgmUu9SwPFfrwH/5jddKzC1ug5
evkAoLTKwMt/PeijEQWNDFtBUKz8craE
=4zVm
-----END PGP SIGNATURE-----
Reply to: