#!/bin/sh
#
# This file is part of OpenMediaVault.
#
# @license   http://www.gnu.org/licenses/gpl.html GPL Version 3
# @author    Volker Theile <volker.theile@openmediavault.org>
# @copyright Copyright (c) 2009-2012 Volker Theile
#
# OpenMediaVault is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# OpenMediaVault 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 OpenMediaVault. If not, see <http://www.gnu.org/licenses/>.

# Documentation/Howto:
# http://wiki.linuxquestions.org/wiki/Fstab

set -e

. /etc/default/openmediavault
. /usr/share/openmediavault/scripts/helper-functions

# Defaults
OMV_INITFS_PID_PATH=${OMV_INITFS_PID_PATH:-"/var/run/openmediavault"}
OMV_INITFS_OWNGRP_PERM=${OMV_INITFS_OWNGRP_PERM:-"openmediavault:openmediavault"}
OMV_INITFS_OPTIONS_EXT3=${OMV_INITFS_OPTIONS_EXT3:-"-b 4096"}
OMV_INITFS_OPTIONS_EXT4=${OMV_INITFS_OPTIONS_EXT4:-"-b 4096"}
OMV_INITFS_OPTIONS_JFS=${OMV_INITFS_OPTIONS_JFS:-"-q"}
OMV_INITFS_OPTIONS_XFS=${OMV_INITFS_OPTIONS_XFS:-"-b size=4096 -f"}

usage() {
	cat <<EOF
Usage:
  $(basename $0) [options] <device>

  device - The name of the device where to create the filesystem.

Options:
  -b  Build the filesystem
  -t  Specifies the type of filesystem to be built
  -L  Set the volume label of the filesystem
  -h  Print a help text
EOF
}

finalize() {
	case ${success} in
	1)
		# Log the exit status of the failed command
		echo "Exit status=${?}" >> ${logfile}

		exitcode=255
		touch "${failfile}"
		rm -f "${buildfile}"
		omv_log "Failed to build the filesystem on ${device}. Please see ${logfile} for more details."
		;;
	0)
		omv_log "The filesystem has been built successful on ${device}."
		exitcode=0
		;;
	esac

	# Remove pid file
	rm -f "${pidfile}";

	exit ${exitcode};
}

cmdargs=$@
build=0
success=1
fstype=
label=
filesys=

# Parse command line
while getopts 'bt:L:?h' option
do
	case ${option} in
	b)
		build=1
		;;
	t)
		fstype="${OPTARG}"
		;;
	L)
		label="${OPTARG}"
		;;
	h|?)
		usage >&2;
		exit 2
		;;
	esac
done

shift $((OPTIND-1))
device=$1

if [ -z "${fstype}" -o -z "${device}" ]; then
	usage >&2;
	exit 2
fi

# Transform the device name to an id that can be used to name the following
# log files
deviceid=$(echo ${device} | tr "/" "_")
# Generate the log file names
pidfile="${OMV_INITFS_PID_PATH}/$(basename $0)@${deviceid}.pid"
logfile="${OMV_LOG_DIR}/$(basename $0)@${deviceid}.log"
failfile="/tmp/$(basename $0)@${deviceid}.fail"
buildfile="/tmp/$(basename $0)@${deviceid}.build"

# Ensure the necessary directories exists
[ ! -d "${OMV_INITFS_PID_PATH}" ] && mkdir -p "${OMV_INITFS_PID_PATH}"

# Cleanup old data
[ -e "${failfile}" ] && rm -f "${failfile}"

# Initialize trap to cleanup in error case
trap finalize INT TERM EXIT

# Check whether a build process is already running for the given device
if [ -e "${pidfile}" ]; then
	echo "The filesystem on ${device} is currently processed"
	exit 1
fi

# Create pid file. Change file permission to allow WebGUI/Webmin to access
# the file.
echo $$ > ${pidfile}
chown ${OMV_INITFS_OWNGRP_PERM} ${pidfile}

# Create log file.
cat /dev/null > ${logfile}
chown ${OMV_INITFS_OWNGRP_PERM} ${logfile}
echo "Command line arguments=${cmdargs}" >${logfile}

# Get the device name of the filesystem
case $(readlink -e "${device}") in
\/dev\/md*)
	# Software RAID
	filesys=${device}
	;;
\/dev\/dm*)
	# Device mapper (LVM2)
	filesys=${device}
	;;
\/dev\/cciss\/*)
	filesys=${device}p1
	;;
*)
	filesys=${device}1
	;;
esac

# Build the filesystem?
if [ 1 -eq ${build} ]; then
	# Create a file that contains the details of the filesystem being
	# initialized. The file is parsed by the 'FileSystemMgmt.getList' RPC
	# to display the state of the filesystem initialization process. There
	# is no other way to detect filesystems being initialized (blkid detects
	# them after the initialization has been finished).
	cat <<EOF > ${buildfile}
{"devicefile":"${filesys}","type":"${fstype}","label":"${label}"}
EOF
	chown ${OMV_INITFS_OWNGRP_PERM} ${buildfile}

	# Create partitions if necessary.
	case $(readlink -e "${device}") in
	\/dev\/md*)
		# Wipe existing filesystems.
		wipefs -a ${device} 1>>${logfile} 2>&1
		# No need to create a partition.
		;;
	\/dev\/dm*)
		# Wipe existing filesystems.
		wipefs -a ${device} 1>>${logfile} 2>&1
		# No need to create a partition.
		;;
	*)
		# Wipe existing filesystems.
		sgdisk --zap-all ${device} 1>>${logfile} 2>&1
		# Use entire device. Get the start and end sectors of the largest
		# block. This is necessary to workaround a bug in sgdisk, otherwise
		# partitions with only 700GiB will be created on a 3TiB device.
		# sgdisk --new=1:0:0 --typecode=1:8300 --print ${device}
		start=$(sgdisk --first-aligned-in-largest ${device} | tail -n 1)
		end=$(sgdisk --end-of-largest ${device} | tail -n 1)
		sgdisk --new=1:${start}:${end} --typecode=1:8300 --print ${device} 1>>${logfile} 2>&1
		sleep 2
		;;
	esac

	# Get the mkfs command options
	fsoptions=""
	case ${fstype} in
	ext3)
		fsoptions="${OMV_INITFS_OPTIONS_EXT3}"
		;;
	ext4)
		fsoptions="${OMV_INITFS_OPTIONS_EXT4}"
		;;
	xfs)
		fsoptions="${OMV_INITFS_OPTIONS_XFS}"
		;;
	jfs)
		fsoptions="${OMV_INITFS_OPTIONS_JFS}"
		;;
	esac
	[ -n "${label}" ] && fsoptions="${fsoptions} -L ${label}"

	# Create the filesystem
	mkfs -V -t ${fstype} ${fsoptions} ${filesys} 1>>${logfile} 2>&1
	sleep 1
fi

# Set success flag (to handle exit code correctly in trap)
success=0

exit 0
