#!/exec/ash
#
# LIBMOL -- This file contains some functions for Make One Linux
# Copyright (C) 2007 Keicho Kondo <dgel@users.sourceforge.jp>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

UNION="union"
MEMORY="memory"
MOUNTDIR="mnt"
CHANGES="${MEMORY}/changes" # old /MOL+
IMAGES="${MEMORY}/images" # old /MOL
COPYTO="${MOUNTDIR}/copyto"
INITRAM="${MOUNTDIR}/live"
ISOMOUNT="${MOUNTDIR}/iso" # old /BASE
DATA="$ISOMOUNT"
LIVECDSGN="livecd.sgn"

KERNEL_MODULE="/modules"   # Kernel module directory

RESET="]R"       # Reset fb color mode
CRE="
[K"       # Erase to end of line
CLEAR="c"        # Clear and reset Screen
NORMAL="[0;39m"  # Normal Color
RED="[1;31m"     # Failure or error message
GREEN="[1;32m"   # Success message
YELLOW="[1;33m"  # Descriptions
BLUE="[1;34m"    # System message
MAGENTA="[1;35m" # Found devices or drivers
CYAN="[1;36m"    # Questions
WHITE="[1;37m"   # Hint


# ===========================================================
# mount, umount functions
# ===========================================================

# Probe and mount filesystems
# $1 = device
# $2 = directory
# $3 = mount options
pmount()
{
	local BUILTIN_FS="iso9660 ext3 vfat ntfs ext2 reiserfs"
	for FOUND_FS in ${BUILTIN_FS}; do
		if [ -b "${1}" ] && mount -t ${FOUND_FS} ${3} ${1} ${2} >/dev/null 2>&1; then
			return 0
		fi
	done
	return 1
}

# Force unmount of all parameters
# $1..$n = directories to be unmounted
#
fumount()
{
   while [ "$1" ]; do
      umount "$1" >/dev/null 2>&1
      if [ 0$? -ne 0 ]; then
         umount -l "$1" >/dev/null 2>&1
      fi
      shift
   done
}


# ===========================================================
# boot parameter functions
# ===========================================================

# Check boot parameter
# $1 = parameter
#
checkbootparam()
{
	local CMDLINE="$(cat /proc/cmdline)"
	case "${CMDLINE}" in
		*\ ${1}*) return 0 ;;
		${1}*)    return 0 ;;
	esac
	return 1
}

# Get boot parameter
# $1 = parameter
#
getbootparam()
{
	local CMDLINE="$(cat /proc/cmdline)"
	local result=""
	case "${CMDLINE}" in
		*\ ${1}=*) ;;
		${1}=*) ;;
		*) return 1 ;;
	esac
	result="${CMDLINE##*$1=}"
	result="${result%%[     ]*}"
	echo "${result}"
	return 0
}


# ===========================================================
# kernel module functions
# ===========================================================

# Load kernel module with exist check
# $1 = kernel module
#
chkinsmod()
{
	if [ -f "$1" ]; then
		insmod "$1" >/dev/null 2>&1
	fi
}

# Ask user whether specified kernel modules should be loaded, or not
# $1 = module type
# $* = module name...
# output: MODULES variable (answered modules in it)
#
askmodules()
{
	# probe module type
	local TYPE="$1"; shift

	# probe available modules
	echo "${BLUE}${TYPE} modules available:${WHITE}"
	local FLAG= ; local m=
	for m in "$@"; do
		if [ -f "${KERNEL_MODULE}/scsi/${m}" ]; then
			[ -z "$FLAG" ] && { echo -n "	${m}"; FLAG="on"; } || { echo "		${m}"; FLAG=""; }
		fi
	done
	[ -n "$FLAG" ] && echo

	# asking
	echo "${CYAN}Load ${TYPE} Modules?${NORMAL}"
	echo "${CYAN}[Enter full filename(s) (space-separated), Return for autoprobe, ${WHITE}n${CYAN} for none] ${NORMAL}"
	echo -n "${CYAN}insmod module(s)> ${NORMAL}"
	read MODULES
	case "$MODULES" in n|N) MODULES=""; ;; y|"") MODULES="$*"; ;; esac
}

# Load given kernel modules
# $1 = module type
# $* = module name
# output: FOUND_SCSI variable (whether scsi module is loaded, or not)
#
loadmodules()
{
    # probe module type
	local TYPE="$1"; shift

	# for interactive
	checkbootparam "expert" && echo "6">/proc/sys/kernel/printk

	# load given modules
	local m=
	for m in "$@"; do
		echo -n "${CRE}${BLUE}Probing ${TYPE}... ${MAGENTA}${m}${NORMAL}"
		if [ -f "${KERNEL_MODULE}/scsi/${m}" ] && insmod -f ${KERNEL_MODULE}/scsi/${m} >/dev/null 2>&1; then
			case "$TYPE" in scsi|SCSI) FOUND_SCSI="yes"; ;; esac
		fi
	done
	echo -n "${CRE}"

	# for interactive
	checkbootparam "expert" && echo "0" > /proc/sys/kernel/printk
}

# Mount kernel modules floppy disk
# $1 = module type
#
mountmodules()
{
	local TYPE="${1}"
	echo -n "${CRE}${CYAN}Please insert ${TYPE} modules floppy disk and hit Return. ${NORMAL}"
	read a
	echo -n "${CRE}${BLUE}Mounting ${TYPE} modules disk... ${NORMAL}"
	if pmount /dev/fd0 ${KERNEL_MODULE}/scsi "-o ro"; then
		echo "${GREEN}OK.${NORMAL}"
		return 0
	fi
	echo "${RED}NOT FOUND.${NORMAL}"
	return 1
}

# Unmount kernel modules floppy disk
# $1 = module type
#
umountmodules()
{
	local TYPE="${1}"
	echo -n "${CRE}${BLUE}Unmounting ${TYPE} modules floppy disk... ${NORMAL}"
	umount ${KERNEL_MODULE}/scsi 2>/dev/null
	echo "${GREEN}DONE.${NORMAL}"
}


# ===========================================================
# live module functions
# ===========================================================

# Mountpoint exits with 0 if $1 is mountpoint, else exits with 1
# $1 = directory
#
mountpoint()
{
   cat /proc/mounts | cut -d " " -f 2 | egrep "^$1\$" >/dev/null 2>&1
}

# Mount .mo module to destination directory
# $1 = path to .mo livecd compressed module
# $2 = destination folder
#
mount_module()
{
   mount -t squashfs -o loop,ro "$1" "$2"
   err=$?
   if [ 0$err -eq 0 ]; then
      echo "$1 $2" >>/tmp/_mounts
   fi
   return $err
}

# Insert a directory tree $2 to an union specified by $1
# Top-level read-write branch is specified by it's index 0
# $1 = union absolute path (starting with /)
# $2 = path to data directory
# $3 = filesystem (unionfs/aufs)
#
union_insert_dir()
{
	if [ "$3" == "aufs" ]; then
		mount -n -o remount,add:1:$2=ro aufs $1
	else
		unionctl "$1" --add --after 0 --mode ro "$2"
	fi
}

# List all modules in all directories (base, modules, optional)
# and filter out unneeded optional modules (not specified by load= kernel parameter)
# separator for load and noload arguments is "," or ";"
# $1 = root directory of mounted DATAdir
#
list_modules()
{
   LOAD="`getbootparam load | sed -r 's/\*/.\*/g' | sed -r 's/,|;/|/g'`"
   NOLOAD="`getbootparam noload | sed -r 's/\*/.\*/g' | sed -r 's/,|;/|/g'`"
   find $1/base $1/modules $1/optional -name "*.mo" 2>/dev/null | sort | while read LINE; do
      MODNAME="`echo $LINE | cut -b ${#1}- | cut -b 2-`"
      if [ "`echo $LINE | grep /optional/`" ]; then
         if [ ! "$LOAD" -o ! "`echo $MODNAME | egrep -i \"$LOAD\"`" ]; then continue; fi
      fi
      if [ "$NOLOAD" -a "`echo $MODNAME | egrep -i \"$NOLOAD\"`" ]; then continue; fi
      echo $LINE
   done
}

# Insert one single .mo module to the union
# $1 = union absolute path
# $2 = module.mo full path
# $3 = destination folder, where images will be mounted to
# $4 = preffix length strip (number of characters)
# $5 = filesystem (unionfs/aufs)
#
union_insert_module()
{
   TARGET="$3/`basename $2`"
   if mountpoint $TARGET >/dev/null 2>&1; then return; fi # skip mounted modules
   mkdir -p $TARGET
   mount_module $2 $TARGET
   if [ 0$? -ne 0 ]; then echo "Cannot read module data. corrupted download?" >&2; return 1; fi
   union_insert_dir $1 $TARGET $5
   if [ 0$? -ne 0 ]; then echo "can't insert module to union" >&2; return 2; fi
   echo "$2" | cut -b $4- | cut -b 2-
   echolog "$2" >/dev/null
   return 0
}

# Insert all .mo modules, in $2 directory and subdirectories, to the union
# $1 = union absolute path (starting with /)
# $2 = LiveCD data dir (with directories /base, /modules, etc.)
# $3 = destination folder, where images will be mounted to
# $4 = filesystem (unionfs/aufs)
#
union_insert_modules()
{
   list_modules $2 | while read MODULE; do
      echolog -n " -> "
      union_insert_module $1 $MODULE $3 ${#2} $4
   done
}


# ===========================================================
# user interface functions
# ===========================================================

# echogreen will echo $@ in green color
# $1 = text
#
echogreen()
{
   echo -ne "[0;32m""$@""[0;39m"
}

# echolog
# $1 = text to show and to write to /var/log/messages
#
echolog()
{
   if [ "$1" != "" ]; then
      echogreen "* "
      echo "LIVECD:" "$@" >>/var/log/livedbg
      echo "$@"
   fi
}

# debug
# commands executed when debug boot parameter is present
#
debug()
{
   echo
   echo "====="
   echo ": Debugging started. Here is the root shell for you."
   echo ": Type your desired command or hit Ctrl+D to continue booting."
   echo
   ash < /dev/console
   echo
}

# header
# $1 = text to show
#
header()
{
   echo "[0;1m""$@""[0;0m"
}

fatal()
{
   echolog
   header "Fatal error occured - $1"
   echolog "Something went wrong and we can't continue. This should never happen."
   echolog "Please reboot your computer with Ctrl+Alt+Delete ..."
   echolog
   umount -a -r
   mount -t proc proc /proc
   mount -t sysfs sysfs /sys
   ash < /dev/console
}

allow_only_root()
{
  # test if the script is started by root user. If not, exit
  if [ "0$UID" -ne 0 ]; then
     echo "Only root can run `basename $0`"; exit 1
  fi
}


# ===========================================================
# Tools functions
# ===========================================================

# Emergency shell
# $1 = error message
#
startash()
{
	echo "${CRE}"
	[ -n "${1}" ] && echo "${RED}${1}${NORMAL}"
	echo "${RED}Can't boot ${MAGENTA}Make One Linux System${RED}, sorry.${NORMAL}"
	echo "${RED}Dropping you to a (very limited) shell.${NORMAL}"
	echo "${RED}Press reset button to quit.${NORMAL}"
	echo

	PS1=" mod # "
	export PS1
	echo "6" >/proc/sys/kernel/printk
	trap 1 2 3 15

	exec /exec/ash
}


# ===========================================================
# discovery functions
# ===========================================================

# List all CD-ROMs
# by using /proc entries
#
list_cdrom_devices()
{
   if checkbootparam "nocd"; then return 1; fi
   #for CDDEVICE in `cat /proc/sys/dev/cdrom/info 2>/dev/null | head -n 3 | tail -n 1 | cut -d ":" -f 2`; do
   for CDDEVICE in $(grep "^drive\ name:" /proc/sys/dev/cdrom/info | awk -F: '{print $2}');do
      echo "/dev/$CDDEVICE"
   done
}

# List all devices with filesystems
# Return empty result when nohd parameter was given.
#
list_partition_devices()
{
   if checkbootparam "nohd"; then return 1; fi
   cat /proc/partitions | grep -v loop |grep -v major | grep -v "^\$" | sed -r "s/^[0-9 ]+/\\/dev\\//"
}

# List all disk devices
#
list_disk_devices()
{
   list_partition_devices | egrep -v "[0-9]"
}

# List all partitions marked as Linux Swap
#
list_swap_devices()
{
   if checkbootparam "nohd" || checkbootparam "noswap"; then return 1; fi
   blkid -t TYPE="swap" | cut -d : -f 1
}

# List all block devices
#
list_block_devices()
{
   list_cdrom_devices
   list_partition_devices
}


# ===========================================================
# hardware preparation functions
# ===========================================================

# load kernel modules needed for the LiveCD
#
load_essential_kernel_modules()
{
	echo "${BLUE}Loading Essential Modules${NORMAL}"
	## for scsi
	chkinsmod ${KERNEL_MODULE}/scsi/scsi_mod.*o
	chkinsmod ${KERNEL_MODULE}/cdrom.*o
	chkinsmod ${KERNEL_MODULE}/scsi/sr_mod.*.o
	## for usb storage
	chkinsmod ${KERNEL_MODULE}/usbcore.*o
	checkbootparam "nousb2" || chkinsmod ${KERNEL_MODULE}/ehci-hcd.*o
	chkinsmod ${KERNEL_MODULE}/uhci-hcd.*o
	chkinsmod ${KERNEL_MODULE}/ohci-hcd.*o
	chkinsmod ${KERNEL_MODULE}/storage/usb-storage.*o
	chkinsmod ${KERNEL_MODULE}/storage/sd_mod.*o
	## for usb keyboard
	chkinsmod ${KERNEL_MODULE}/usbhid.*o
	## for loop
	chkinsmod ${KERNEL_MODULE}/loop.*o
	## for cdrom
	chkinsmod ${KERNEL_MODULE}/ide-cd.*o
	chkinsmod ${KERNEL_MODULE}/isofs.*o
	chkinsmod ${KERNEL_MODULE}/generic.*o
	chkinsmod ${KERNEL_MODULE}/ide-generic.*o
	## for native language support
	chkinsmod ${KERNEL_MODULE}/nls_cp437.*o
	chkinsmod ${KERNEL_MODULE}/nls_utf8.*o
	# for filesystems
	chkinsmod ${KERNEL_MODULE}/fat.*o
	chkinsmod ${KERNEL_MODULE}/vfat.*o
	chkinsmod ${KERNEL_MODULE}/ntfs.*o
	chkinsmod ${KERNEL_MODULE}/jbd.*o
	chkinsmod ${KERNEL_MODULE}/ext3.*o
	chkinsmod ${KERNEL_MODULE}/reiserfs.*o
	chkinsmod ${KERNEL_MODULE}/squashfs.*o
	chkinsmod ${KERNEL_MODULE}/unionfs.*o
	chkinsmod ${KERNEL_MODULE}/aufs.*o
}

# load kernel modules needed for SCSI devices
#
load_scsi_kernel_modules()
{
	echo -n "${CRE}${BLUE}Checking for SCSI...${NORMAL}"
	# probing scsi modules
	if checkbootparam "expert"; then
		# Let the user select interactively
		askmodules SCSI $(cd ${KERNEL_MODULE}/scsi; echo *.*o)
	else
		# trying to do kind of /proc/pci hardware detection
		PROCPCI="$(cat /proc/pci 2>/dev/null)"
		ISA_SCSI="aha1740.*o aha1542.*o aha152x.*o pas16.*o psi240i.*o qlogicfas.*o qlogicfc.*o seagate.*o t128.*o u14-34f.*o wd7000.*o"
		SCSI_PROBE="${ISA_SCSI}"
		case "${PROCPCI}" in *[Aa][Ii][Cc]-|*[Aa][Hh][Aa]-*) SCSI_PROBE="${SCSI_PROBE} aic7xxx.*o" ;; esac
		case "${PROCPCI}" in *[Bb][Uu][Ss][Ll][Oo][Gg][Ii][Cc]*) SCSI_PROBE="${SCSI_PROBE} BusLogic.*o" ;; esac
		case "${PROCPCI}" in *53[Cc]8*) SCSI_PROBE="${SCSI_PROBE} ncr53c8xx.*o" ;; esac
		case "${PROCPCI}" in *53[Cc]406*) SCSI_PROBE="${SCSI_PROBE} NCR53c406a.*o" ;; esac
		case "${PROCPCI}" in *[Ii][Nn][Ii][Tt][Ii][Oo]\ *|*[Ii][Nn][Ii]-[Aa]100[Uu]2[Ww]*) SCSI_PROBE="${SCSI_PROBE} initio.*o" ;; esac
		case "${PROCPCI}" in *[Mm][Pp][Tt]*[Ss][Cc][Ss][Ii]*) SCSI_PROBE="${SCSI_PROBE} mptscsih.*o" ;; esac
		case "${PROCPCI}" in *[Aa][Dd][Vv][Aa][Nn][Cc][Ee][Dd]\ [Ss][Yy][Ss]*) SCSI_PROBE="${SCSI_PROBE} advansys.*o" ;; esac
		case "${PROCPCI}" in *[Aa][Tt][Pp]8|*[Aa][Ee][Cc]6*) SCSI_PROBE="${SCSI_PROBE} atp870u.*o" ;; esac
		case "${PROCPCI}" in *[Dd][Tt][Cc]*) SCSI_PROBE="${SCSI_PROBE} dtc.*o" ;; esac
		case "${PROCPCI}" in *[Ee][Aa][Tt][Aa]*) SCSI_PROBE="${SCSI_PROBE} eata.*o" ;; esac
		case "${PROCPCI}" in *[Ff]*[Dd][Oo][Mm][Aa][Ii][Nn]*) SCSI_PROBE="${SCSI_PROBE} fdomain.*o" ;; esac
		case "${PROCPCI}" in *[Gg][Dd][Tt]\ *) SCSI_PROBE="${SCSI_PROBE} gdth.*o" ;; esac
		case "${PROCPCI}" in *[Mm][Ee][Gg][Aa][Rr][Aa][Ii][Dd]*) SCSI_PROBE="${SCSI_PROBE} megaraid.*o" ;; esac
		case "${PROCPCI}" in *[Pp][Cc][Ii]-22*) SCSI_PROBE="${SCSI_PROBE} pci2220i.*o" ;; esac
		case "${PROCPCI}" in *[Pp][Cc][Ii]-2000*) SCSI_PROBE="${SCSI_PROBE} pci2000.*o" ;; esac
		case "${PROCPCI}" in *[Qq][Ll][Oo][Gg][Ii][Cc]*) SCSI_PROBE="${SCSI_PROBE} qlogicisp.*o" ;; esac
		case "${PROCPCI}" in *53[Cc]974*) SCSI_PROBE="${SCSI_PROBE} tmscsim.*o" ;; esac
		case "${PROCPCI}" in *[Uu][Ll][Tt][Rr][Aa][Ss][Tt][Oo][Rr]*) SCSI_PROBE="${SCSI_PROBE} ultrastor.*o" ;; esac
		case "${PROCPCI}" in *3[Ww][Aa][Rr][Ee]*) SCSI_PROBE="${SCSI_PROBE} 3w-xxxx.*o" ;; esac
		# these are the autoprobe-safe modules
		MODULES="${SCSI_PROBE}"
	fi

	# loading scsi modules
	[ -n "$MODULES" ] && loadmodules SCSI $MODULES
	echo -n "${CRE}"
}

# load kernel modules needed for raid devices
#
load_raid_kernel_modules()
{
	echo -n "${CRE}${BLUE}Checking for RAID...${NORMAL}"
	FLAG=""
	[ -z "${FLAG}" ] && chkinsmod ${KERNEL_MODULE}/scsi/ataraid.*o && chkinsmod ${KERNEL_MODULE}/scsi/silraid.*o && FLAG="on"
	[ -z "${FLAG}" ] && chkinsmod ${KERNEL_MODULE}/scsi/medley.*o  && FLAG="on"
	[ -z "${FLAG}" ] && chkinsmod ${KERNEL_MODULE}/scsi/pdcraid.*o
	unset FLAG
	echo -n "${CRE}"
}

# load kernel modules needed for firewire devices
#
load_firewire_kernel_modules()
{
	echo -n "${CRE}${BLUE}Checking for Firewire...${NORMAL}"
	FLAG=""
	[ -z "${FLAG}" ] && chkinsmod ${KERNEL_MODULE}/storage/ieee1394.*o || FLAG="on"
	[ -z "${FLAG}" ] && chkinsmod ${KERNEL_MODULE}/storage/ohci1394.*o || FLAG="on"
	[ -z "${FLAG}" ] && chkinsmod ${KERNEL_MODULE}/storage/sbp2.*o sbp2_serialize_io=1
	unset FLAG
	echo -n "${CRE}"
}

# load additional kernel modules
#
load_additional_kernel_modules()
{
	echo -n "${CRE}${BLUE}Checking for Additional Modules...${NORMAL}"
	chkinsmod ${KERNEL_MODULE}/add/*.*o
	echo -n "${CRE}"
}

# load misc kernel modules in expert mode
load_kernel_modules_from_floppy()
{
	another=""
	answer=""
	while [ "${answer}" != "n" -a "${answer}" != "N" ]; do
		echo -n "${CYAN}Do you want to load additional modules from ${another} floppy disk? [${WHITE}Y${CYAN}/n] ${NORMAL}"
		another="another"
		read answer
		case "${answer}" in n*|N*) break; ;; esac
		if mountmodules new; then
			askmodules new $(cd ${KERNEL_MODULE}/scsi; echo *.*o)
			[ -n "${MODULES}" ] && loadmodules new ${MODULES}
			umountmodules current
		fi
	done
}


# enable/disable CD autoejecting when unmounted
# $1 = 1|0 ... enable|disable
#
cd_autoeject()
{
   echo $1 >/proc/sys/dev/cdrom/autoeject
}

# enable/disable DMA support
# $1 = on/off
#
setup_dma()
{
	echo "${BLUE}Setting DMA support...${NORMAL}"
	for d in $(cd /proc/ide 2>/dev/null && echo hd[a-z]); do
		if [ -d "/proc/ide/${d}" ]; then
			MODEL="$(cat /proc/ide/${d}/model 2>/dev/null)"
			[ -z "${MODEL}" ] && MODEL="[GENERIC IDE DEVICE]"
			if [ "$1" == "on" ]; then
				echo " ${GREEN}Enabling DMA acceleration for: ${MAGENTA}${d} 	${YELLOW}[${MODEL}]${NORMAL}"
				echo "using_dma:1" >/proc/ide/${d}/settings
			else
				echo " ${GREEN}Disabling DMA acceleration for: ${MAGENTA}${d} 	${YELLOW}[${MODEL}]${NORMAL}"
				echo "using_dma:0" >/proc/ide/${d}/settings
			fi
		fi
	done
}

# update given line in fstab, add new values only if the device is not found
# $1 = fstab file to parse
# $2 = device name
# $3 = mountpoint
# $4 = filesystem
# $5 = mount options
#
fstab_update_line()
{
   if [ "`cat \"$1\" | sed -r \"s/#.*//\" | egrep \"^[[:space:]]*[^[:space:]]+[[:space:]]+$2[[:space:]]+\"`" = "" ]; then
      echo "$2" "$3" "$4" "$5" 0 0 "$FSTABLLFLAG" >>$1
   fi
}

# create correct fstab file in $1/etc/fstab and create apropriate
# mount directories in $1/mnt. Check for iocharset boot option,
# if present, add iocharset to all DOS/Win filesystems (vfat,ntfs)
# $1 = root directory (union)
#
fstab_update()
{
   IOCHARSET="$(getbootparam iocharset)"
   checkbootparam "noauto" && AUTO="noauto"
   if [ "$AUTO" = "" ]; then AUTO="auto"; fi

   FSTAB="$1/etc/fstab"
   mkdir -p $1/etc $1/mnt
   cat $FSTAB 2>/dev/null | grep -v "$FSTABLLFLAG" >$FSTAB~

   fstab_update_line $FSTAB~ tmpfs / tmpfs defaults
   fstab_update_line $FSTAB~ devpts /dev/pts devpts gid=5,mode=620
   fstab_update_line $FSTAB~ proc /proc proc defaults
   list_cdrom_devices | while read DEVICE; do
      MOUNTDIR="/mnt/`basename $DEVICE`_cdrom"
      mkdir -p $1/$MOUNTDIR
      fstab_update_line $FSTAB~ $DEVICE $MOUNTDIR iso9660 noauto,users,exec
   done
   list_partition_devices | while read DEVICE; do
      unset REMOVABLE; unset OPT; DEV="`basename $DEVICE`"; DEV0="`echo $DEV | cut -b 1-3`"
      if [ "0`cat /sys/block/$DEV0/removable 2>/dev/null`" -ne 0 ]; then
         REMOVABLE="_removable"
      fi

      MOUNTDIR="/mnt/$DEV$REMOVABLE"
      FS="`blkid -s TYPE $DEVICE | cut -d = -f 2 | tr -d ' \"'`"

      # add special options for NTFS
      if [ "$FS" = "ntfs" ]; then
         OPT=",ro"
         if [ "$IOCHARSET" != "" ]; then OPT="$OPT,nls=$IOCHARSET"; fi
      fi

      # add special options for VFAT
      if [ "$FS" = "vfat" -a "$IOCHARSET" != ""  ]; then OPT=",iocharset=$IOCHARSET"; fi

      # if the partition has filesystem, add it to fstab
      if [ "$FS" != "" ]; then
         if [ "$FS" = "swap" ]; then
            checkbootparam "noswap" || fstab_update_line $FSTAB~ $DEVICE swap swap defaults
         else
            fstab_update_line $FSTAB~ $DEVICE $MOUNTDIR $FS $AUTO,users,suid,dev,exec$OPT
            mkdir -p "$1/$MOUNTDIR"
         fi
      fi
   done

   fstab_update_line $FSTAB~ /dev/fd0 /mnt/floppy vfat,msdos noauto,users,suid,dev,exec
   mkdir -p $1/mnt/floppy
   
   mv -f $FSTAB~ $FSTAB
}
