[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: