#!/usr/local/bin/cbsd
#v11.2.1
MYARG="mode"
MYOPTARG="display jname name path type quiet"
MYDESC="Operate with virtual storage media such as ISO"
CBSDMODULE="sys"
EXTHELP="wf_bhyve"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

CBSD keeps track of all hard disk and CD/ISO images that are used by VMs.
With 'cbsd media' script you can register or unlink the image.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}display=${N0_COLOR}    - list by comma for column,
               default values: 'name,path,type,jname,size';
 ${N2_COLOR}jname=${N0_COLOR}      - perform an action for the <jname> VM;
 ${N2_COLOR}mode=${N0_COLOR}       - action to be performed, options:
             - 'attach'                   - attach media to jname.
             - 'detach'                   - detach media from jname.
             - 'list'                     - list of registered media.
             - 'flushall'                 - unregister all records, without deleting.
             - 'register                  - register new media (req: name, path).
             - 'unregister                - unregister new media (req: name, path), 
                                            without delete.
             - 'delete' or 'remove'       - unregister and delete media file
                                            (req: name, path).
             - 'deleteall' or 'removeall' - unregister and delete all ISO files.
             - 'get'                      - print 'name' or 'path' for 'path=' 
                                            or 'name='.
             - 'update'                   - update type or jname by 'path=' 
                                            and 'name='.
             - 'dump'                     - dump SQL records by line.
             - 'eject'                    - eject CD/ISO from VM.
 ${N2_COLOR}type=${N0_COLOR}       - type of image: 'iso' for CD/DVD or 'hdd' for dsk,
               if the type is not specified, CBSD will try to  determine it on its own;
 ${N2_COLOR}sectorsize=${N0_COLOR} - custom sectorsize for register mode;
 ${N2_COLOR}quiet=${N0_COLOR}             - 0,1: be quiet, dont output verbose message.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd media mode=list
 # cbsd media mode=register name=virtio-win path=/usr/local/www/iso/virtio-win-0.1.208.iso

 # cbsd media mode=register name=iso-fbsd_riscv_13 path=/usr/src-jails/iso/FreeBSD-13.0-RELEASE-riscv-riscv64-dvd1.iso
 # cbsd media mode=attach name=iso-fbsd_riscv_13 path=/usr/src-jails/iso/FreeBSD-13.0-RELEASE-riscv-riscv64-dvd1.iso jname=qemu_vm1

${H3_COLOR}See also${N0_COLOR}:

 cbsd bhyve-dsk --help
 cbsd bconfig --help

 cbsd qemu-dsk --help
 cbsd qconfig --help

 cbsd xen-dsk --help
 cbsd xconfig --help

"

. ${subrdir}/nc.subr

quiet=0
oquiet=0

. ${cbsdinit}

. ${system}
. ${subrdir}/bhyve.subr
. ${subrdir}/xen.subr
. ${subrdir}/virtual.subr

if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	readconf cbsd_queue.conf
	[ -z "${cbsd_queue_backend}" ] && MOD_CBSD_QUEUE_DISABLED="1"
fi

[ -z "${display}" ] && display="name,path,type,jname,size"

#remove commas for loop action on header
mydisplay=$( echo ${display} | ${TR_CMD} ',' ' ' )

# upper for header
myheader=$( echo ${mydisplay} | ${TR_CMD} '[:lower:]' '[:upper:]' )

show_header()
{
	local _header="${H1_COLOR}${BOLD}${myheader}${N0_COLOR}"
	[ ${header} -eq 1 ] && ${ECHO} "${_header}"
}

# dummy function when no $emulator
dummy_remove_dsk()
{
	true
}

# construct and print full path or $1 is relative
normalize_full_path()
{
	local _path_pref _tmp_path

	# is full path?
	_path_pref=$( substr --pos=0 --len=1 --str=${1} )

	if [ "${_path_pref}" = "/" ]; then
		_tmp_path="${1}"
	else
		if [ -z "${jname}" ]; then
			err 1 "media: normalize_full_path: jname is empty for init ${1} full path"
		fi
			_tmp_path="${jaildatadir}/${jname}-data/${1}"
	fi

	printf "${_tmp_path}"
}


# 1) if -n name -p path -t type exist for jail='-' than UPDATE this records to -j jname
# 2) if -n name -p path -t type not exist for jail='-', remove records for -j jname
unregister_or_remove()
{
	local rec_num
	local exist
	local name path type jname

	while getopts "n:p:t:j:" opt; do
		case "${opt}" in
			n) name="${OPTARG}" ;;
			p) path="${OPTARG}" ;;
			t) type="${OPTARG}" ;;
			j) jname="${OPTARG}" ;;
		esac
		shift $(($OPTIND - 1))
	done

	path=$( normalize_full_path ${path} )

	if [ -z "${jname}" -o "${jname}" = "-" ]; then
		cbsdsqlrw storage_media "DELETE FROM media WHERE jname='${jname}' AND name='${name}' AND path='${path}' AND type='${type}'"
		return 0
	fi

	rec_num=$( cbsdsqlro storage_media "SELECT COUNT(path) FROM media WHERE name='${name}' AND path='${path}' AND type='${type}' AND jname != '${jname}'" )

	if [ "${rec_num}" = "0" ]; then
		# this is last one, clean ISO register and drop to unassigned stage
		cbsdsqlrw storage_media "UPDATE media SET jname='-' WHERE jname='${jname}' AND type='${type}' AND name='${name}' AND path='${path}'"
	else
		# delete iso registered when we have greater then 1 records with path= name=
		cbsdsqlrw storage_media "DELETE FROM media WHERE jname='${jname}' AND name='${name}' AND path='${path}' AND type='${type}'"
	fi

	# delete from domain local db
	cbsdsqlrw ${jailsysdir}/${jname}/local.sqlite "DELETE FROM ${emulator}dsk WHERE dsk_path='hdd-${name}' AND dsk_type='${type}'"

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
	fi
	return 0
}

# 1) if -n name -p path -t type exist for jail='-' than UPDATE this records to -j jname
# 2) if -n name -p path -t type not exist for jail='-', add records for -j jname
register_or_add()
{
	local rec_num
	local exist
	local name path type jname
	local size
	local dsk_sectorsize=

	while getopts "n:p:t:j:z:" opt; do
		case "${opt}" in
			n) name="${OPTARG}" ;;
			p) path="${OPTARG}" ;;
			t) type="${OPTARG}" ;;
			j) jname="${OPTARG}" ;;
			z) dsk_sectorsize="${OPTARG}" ;;
		esac
		shift $(($OPTIND - 1))
	done

	path=$( normalize_full_path ${path} )

	populate_dsk_size ${path}
	size=${dsk_bsize}
	[ -z "${size}" ] && size=0

	if [ -z "${jname}" -o "${jname}" = "-" ]; then
		rec_num=$( cbsdsqlro storage_media "SELECT COUNT(path) FROM media WHERE name='${name}' AND path='${path}' AND type='${type}' AND jname='-'" )
		[ "${rec_num}" != "0" ] && return 0
		cbsdsqlrw storage_media "INSERT INTO media ( name, path, type, jname, size ) VALUES ( '${name}', '${path}', '${type}', '${jname}', '${size}' )"
		return 0
	fi

	rec_num=$( cbsdsqlro storage_media SELECT "COUNT(path) FROM media WHERE name='${name}' AND path='${path}' AND type='${type}' AND jname='-'" )

	if [ "${rec_num}" = "1" ]; then
		cbsdsqlrw storage_media "UPDATE media SET jname='${jname}' WHERE jname='-' AND name='${name}' AND path='${path}' AND type='${type}'"
	else
		cbsdsqlrw storage_media "INSERT INTO media ( name, path, type, jname, size ) VALUES ( '${name}', '${path}', '${type}', '${jname}', '${size}' )"
	fi

	# add to domain local db
	cbsdsqlrw ${jailsysdir}/${jname}/local.sqlite "DELETE FROM ${emulator}dsk WHERE dsk_path='hdd-${name}' AND dsk_type='${type}'"

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
	fi

	return 0
}

# if $1 = "Unregister" then overwrite status to "Unregister"
populate_output_data()
{
	local _i _val

	_status=

	#populate values for in output string
	for _i in ${mydisplay}; do
		case "${_i}" in
			size)
				_val=
				eval _val=\$$_i

				if conv2human "${_val}"; then
					_val=${convval}
				fi
				;;
			*)
				_val=
				eval _val=\$$_i
				[ -z "${_val}" ] && _val="\-"
				prefix=$( substr --pos=0 --len=1 --str=${_val} )
				[ "${prefix}" = "-" ] && _val="\-"
				;;
		esac
		if [ -z "${_status}" ]; then
			_status="${N0_COLOR}${_val}"
		else
			_status="${_status} ${_val}"
		fi
	done
}


# $1 - which file from. Eg: local
show_data_from_sql()
{
	local _i

	_sql="SELECT name,path,type,jname,size FROM media"

	cbsdsqlro storage_media ${_sql} | while read name path type jname size; do
		populate_output_data
		printf "${N2_COLOR}"
		printf "${_status}"
		printf "${N0_COLOR}\n"
	done

	IFS=" "
}


show_local()
{
	local _errcode _status

	show_header
	show_data_from_sql local
}

show_vhid()
{
	show_local
}


# select into $vm_res variable path of media by name
# return 0 if data exist
# $1 - alternative jname
select_by_name()
{
	local j="${jname}"

	[ -n "${1}" ] && j="${1}"

	vm_res=$( cbsdsqlro storage_media "SELECT path FROM media WHERE name='${name}' AND jname='${j}'" )

	[ -z "${vm_res}" ] && return 1

	return 0
}

# select into $vm_res variable name of media by path
# return 0 if data exist
# $1 - alternative jname
select_by_path()
{
	local j="${jname}"

	[ -n "${1}" ] && j="${1}"
	vm_res=$( cbsdsqlro storage_media "SELECT name FROM media WHERE path='${path}' AND jname='${j}'" )

	[ -z "${vm_res}" ] && return 1

	return 0
}

update_jname()
{
	cbsdsqlrw storage_media "UPDATE media SET jname='${jname}' WHERE name='${name}' AND path='${path}'"
}

update_type()
{
	cbsdsqlrw storage_media "UPDATE media SET type='${type}' WHERE name='${name}' AND path='${path}' AND jname='${jname}'"
}

check_protected()
{
	local _emulator
	local _table

	[ "${jname}" = "-" ] && return 0

	_emulator=$( cbsdsqlro local "SELECT emulator FROM jails WHERE jname='${jname}'" )

	case "${_emulator}" in
		jail)
			_table="jails"
			;;
		bhyve)
			_table="bhyve"
			;;
		xen)
			_table="xen"
			;;
	esac

	protected=$( cbsdsqlro local "SELECT protected FROM ${_table} WHERE jname='${jname}'" )

	[ -z "${protected}" ] && protected="0"	# by default - is not protected
	[ "${protected}" = "1" ] && err 1 "${N1_COLOR}Environment is protected to delete: ${N2_COLOR}${jname}${N0_COLOR}"
}


storage_attach()
{
	local _data_dir_path _tmp_dir_path= _tmp_dsk_path= _res

	[ -z "${name}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}name=${N0_COLOR}"
	[ -z "${path}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}path=${N0_COLOR}"
	[ -z "${jname}" ] && err 1 "${N1_COLOR}Give me ${N2_COLOR}jname=${N0_COLOR}"

	local attached_to_name dsk_path dsk_name
	local mydb virtio_type already_attached_to_me

	attached_to_jname=$( cbsdsqlro storage_media "SELECT jname FROM media WHERE path='${path}' AND name='${name}' AND jname!='${jname}' LIMIT 1" )

	# not attached?
	if [ "${attached_to_jname}" = "-" ]; then
		by_path="-"
		by_name="-"
		attached_to_jname=
	else
		by_path="${path}"
		by_name="${name}"
	fi

	# todo: shared disk
	if [ "${type}" = "hdd" ]; then
		[ -n "${attached_to_jname}" ] && err 1 "${N1_COLOR}disk ${name} with path ${path} already attached to: ${N2_COLOR}${test_jname}${N0_COLOR}"
		select_by_path "${by_path}"
		[ $? -ne 0 ] && err 1 "${N1_COLOR}Path not exist for jname by path ${by_path}: ${N2_COLOR}${path}${N0_COLOR}"
		select_by_name "${by_name}"
		[ $? -ne 0 ] && err 1 "${N1_COLOR}Name not exist for jname by name ${by_name}: ${N2_COLOR}${name}${N0_COLOR}"
	fi

	# save variables before rcconf init
	dsk_path="${path}"
	dsk_name="${name}"

	. ${subrdir}/rcconf.subr
	[ $? -eq 1 ] && err 1 "${N1_COLOR}attachzfs: no such jail: ${N2_COLOR}${jname}${N0_COLOR}"

	if [ -z "${type}" ]; then
		type=$( imgtype path=${dsk_path} 2>&1 )
		${ECHO} "${N1_COLOR}media: auto-detected image type for ${dsk_path}: ${N2_COLOR}${type}${N0_COLOR}"
	fi

	case "${type}" in
		iso|shared)
			;;
		hdd)
			mydb="${jailsysdir}/${jname}/local.sqlite"
			virtio_type="virtio-blk"
			# simplify if the file is located in the data directory
			_data_dir_path="${jaildatadir}/${jname}-data"
			_tmp_dir_path=$( ${DIRNAME_CMD} ${dsk_path} )
			if [ "${_data_dir_path}" = "${_tmp_dir_path}" ]; then
				_tmp_dsk_path=$( ${BASENAME_CMD} ${dsk_path} )
			else
				_tmp_dsk_path="${dsk_path}"
			fi
			_res=$( cbsdsqlro ${mydb} "SELECT dsk_path FROM bhyvedsk WHERE jname='${jname}' AND dsk_path='${_tmp_dsk_path}' LIMIT 1" 2>/dev/null )
			if [ -n "${_res}" ]; then
				[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}dsk_path already exist for ${jname}: ${N2_COLOR}${_tmp_dsk_path}${N0_COLOR}"
				return 1
			fi
			cbsdsqlrw ${mydb} "INSERT INTO ${emulator}dsk ( jname,dsk_controller,dsk_path,dsk_slot ) VALUES ( '${jname}','${virtio_type}','${_tmp_dsk_path}','0' )"
			;;
	esac

	# test for already attached
	already_attached_to_me=$( cbsdsqlro storage_media "SELECT jname FROM media WHERE path='${dsk_path}' AND name='${dsk_name}' AND jname='${jname}' LIMIT 1" )

	[ -n "${already_attached_to_me}" ] && err 1 "${N1_COLOR}storage with name:${name} and path:${path} already attached for instance: ${N2_COLOR}${jname}${N0_COLOR}"

	if [ -n "${attached_to_jname}" ]; then
		#shared disk: INSERT
		sql="INSERT INTO media ( name, path, type, jname ) VALUES ( '${dsk_name}', '${dsk_path}', '${type}', '${jname}' )"
	else
		sql="UPDATE media SET jname='${jname}' WHERE name='${dsk_name}' AND path='${dsk_path}'"
	fi

	[ ${quiet} -ne 1 ] && echo "${sql}"
	cbsdsqlrw ${dbdir}/storage_media.sqlite "${sql}"

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
	fi

	return 0
}


storage_detach()
{
	[ -z "${name}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}name=${N0_COLOR}"
	[ -z "${path}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}path=${N0_COLOR}"
	[ -z "${jname}" ] && err 1 "${N1_COLOR}Give me ${N2_COLOR}jname=${N0_COLOR}"

	local dsk_path= dsk_name=
	local mydb= virtio_type= already_attached_to_me=

	attached_to_me=$( cbsdsqlro storage_media "SELECT jname FROM media WHERE path='${path}' AND ( name='${name}' OR NAME='${name}.vhd' ) AND jname='${jname}' LIMIT 1" )
	[ "${attached_to_me}" != "${jname}" ] && err 1 "${N1_COLOR}disk ${name} with name:${name} and path:${path} is not attached to: ${N2_COLOR}${jname}${N0_COLOR}"

	attached_to_jname=$( cbsdsqlro storage_media "SELECT jname FROM media WHERE path='${path}' AND ( name='${name}' OR NAME='${name}.vhd' ) AND jname!='${jname}' LIMIT 1" )

	# not attached?
	if [ "${attached_to_jname}" = "-" ]; then
		by_path="-"
		by_name="-"
		attached_to_jname=
	else
		by_path="${path}"
		by_name="${name}"
	fi

	# save variables before rcconf init
	dsk_path="${path}"
	dsk_name="${name}"

	. ${subrdir}/rcconf.subr
	[ $? -eq 1 ] && err 1 "${N1_COLOR}attachzfs: no such jail: ${N2_COLOR}${jname}${N0_COLOR}"

	case "${type}" in
		iso|shared)
			;;
		hdd)
			mydb="${jailsysdir}/${jname}/local.sqlite"
			cbsdsqlrw ${mydb} "DELETE FROM ${emulator}dsk WHERE dsk_path='${dsk_path}' AND ( name='${dsk_name} OR name='${dsk_name}.vhd' )"
			;;
	esac

	if [ -n "${attached_to_jname}" ]; then
		# shared disk: delete record with my jname
		sql="DELETE FROM media WHERE ( name='${dsk_name}' name='${dsk_name}.vhd' )  AND path='${dsk_path}' AND jname='${jname}'"
	else
		# disk is orphaned now: drop to '-' jname
		sql="UPDATE media SET jname='-' WHERE jname='${jname}' AND ( name='${dsk_name}' OR name='${dsk_name}.vhd' ) AND path='${dsk_path}'"
	fi

	[ ${quiet} -ne 1 ] && echo "${sql}"
	cbsdsqlrw ${dbdir}/storage_media.sqlite "${sql}"

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
	fi

	case "${type}" in
		hdd)
			mydb="${jailsysdir}/${jname}/local.sqlite"
			cbsdsqlrw ${mydb} "DELETE FROM ${emulator}dsk WHERE dsk_path='${dsk_path}'"
			;;
		iso)
			bset quiet=${quiet} jname=${jname} vm_iso_path=''
			;;
	esac

	return 0
}


eject()
{
	cbsdsqlrw storage_media "UPDATE media SET jname='-' WHERE jname='${jname}' AND type='iso'"
}

which_vm_depens_on_zvol()
{
	local _vm_list _vol="${1}"

	[ -z "${_vol}" ] && return 0

	_vm_list=$( ${ZFS_CMD} list -H -r -t snapshot -o name ${_vol} | ${CUT_CMD} -d '@' -f 2 | ${CUT_CMD} -d '-' -f 2 | ${XARGS_CMD} )

	[ -z "${_vm_list}" ] && return 0
	printf "${_vm_list}"
	return 1
}


# try to remove ISO file
try_to_rm()
{
	local path="${1}"
	local _vm_list

	[ -z "${path}" ] && err 1 "${N1_COLOR}media: try_to_rm: empty path${N0_COLOR}"

	. ${subrdir}/zfs.subr
	if is_getzvol ${path}; then
		${ZFS_CMD} list ${is_zvol} > /dev/null 2>&1
		if [ $? -eq 0 ]; then

			_vm_list=$( which_vm_depens_on_zvol ${is_zvol} )

			[ -n "${_vm_list}" ] && err 1 "${N1_COLOR}Current vm depends from ${is_zvol}: ${N2_COLOR}${_vm_list}${N0_COLOR}"

			# zvol exist
			${ZFS_CMD} destroy ${is_zvol}
			_ret=$?
			[ ${_ret} -ne 0 ] && err 1 "${N1_COLOR}Unable to destroy zvol, please remove it by hand: ${N2_COLOR}${is_zvol}${N0_COLOR}"
		fi
	fi
	${RM_CMD} -f ${path}
	return 0
}


#### MAIN
[ -z "${header}" ] && header=1
sqldelimer=" "
vm_res=

if [ -n "${jname}" ]; then
	emulator=$( cbsdsqlro local "SELECT emulator FROM jails WHERE jname='${jname}'" )
else
	emulator="dummy"
fi

case "${mode}" in
	attach)
		storage_attach
		[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Attached to: ${N2_COLOR}${jname}${N0_COLOR}"
		exit 0
		;;
	detach)
		storage_detach
		[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Detach to: ${N2_COLOR}${jname}${N0_COLOR}"
		exit 0
		;;
	eject)
		[ -z "${jname}" ] && err 1 "${N1_COLOR}Please specify ${N2_COLOR}jname=${N0_COLOR}"
		eject
		[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}All CD/ISO ejected: ${N2_COLOR}${jname}${N0_COLOR}"
		exit 0
		;;
	list)
		show_local | ${COLUMN_CMD} -t
		;;
	get)
		[ -z "${name}" -a -z "${path}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}name=${N1_COLOR} or ${N2_COLOR}path=${N1_COLOR} value is reguired${N0_COLOR}"
		[ -n "${name}" -a -n "${path}" ] && err 1 "${N1_COLOR}media: Please specify ${N2_COLOR}name=${N1_COLOR} OR ${N2_COLOR}path=${N1_COLOR}, not both${N0_COLOR}"
		[ -n "${name}" ] && select_by_name
		[ -n "${path}" ] && select_by_path
		err 0 "${vm_res}"
		;;
	register)
		[ -z "${name}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}name=${N1_COLOR} is mandatory${N0_COLOR}"
		[ -z "${path}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}path=${N1_COLOR} is mandatory${N0_COLOR}"
		select_by_path
		_ret=$?
		if [ ${_ret} -eq 0 ]; then
			[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Path already exist for: ${N2_COLOR}${vm_res}${N0_COLOR}"
			exit 1
		fi
		select_by_name
		_ret=$?
		if [ ${_ret} -eq 0 ]; then
			[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Name already exist for: ${N2_COLOR}${vm_res}${N0_COLOR}"
			exit 1
		fi

		if [ -z "${type}" ]; then
			type=$( imgtype path=${path} 2>&1 )
			[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}media: auto-detected image type for ${path}: ${N2_COLOR}${type}${N0_COLOR}"
		fi

		[ -z "${jname}" ] && jname="-"

		register_or_add -n "${name}" -p "${path}" -t "${type}" -j "${jname}"

		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
		fi

		${ECHO} "${N1_COLOR}Updated${N0_COLOR}" 1>&2
		exit 0
		;;
	unregister)
		[ -z "${type}" ] && type="hdd"
		[ -z "${jname}" ] && jname="-"

		check_protected

		[ -z "${name}" -a -z "${path}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}name=${N1_COLOR} or ${N2_COLOR}path=${N1_COLOR} value is reguired${N0_COLOR}"

		if [ -n "${name}" -a -n "${path}" ]; then
			unregister_or_remove -n "${name}" -p "${path}" -t "${type}" -j "${jname}"
		elif [ -n "${name}" ]; then
			cbsdsqlrw storage_media "DELETE FROM media WHERE name='${name}' AND jname='${jname}'"
		elif [ -n "${path}" ]; then
			cbsdsqlrw storage_media "DELETE FROM media WHERE path='${path}' AND jname='${jname}'"
		fi

		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
		fi

		err 0 "${N1_COLOR}Unregistered${N0_COLOR}"
		;;
	flushall)
		# test for protected by select jname ???
		cbsdsqlrw storage_media "DELETE FROM media WHERE type != 'hdd'"

		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
		fi

		err 0 "${N1_COLOR}Flushed${N0_COLOR}"
		;;
	delete|remove)
		[ -z "${type}" ] && err 1 "${N2_COLOR}type= ${N1_COLOR}is mandatory${N0_COLOR}"
		[ -z "${jname}" ] && jname="-"

		check_protected

		[ -z "${name}" -a -z "${path}" ] && err 1 "${N1_COLOR}media: ${N2_COLOR}name=${N1_COLOR} or ${N2_COLOR}path=${N1_COLOR} value is reguired${N0_COLOR}"

		if [ -n "${name}" -a -n "${path}" ]; then

			# need before actual delete from SQL due to zvol deps check
			[ "${type}" = "iso" ] && try_to_rm ${path}

			if [ "${jname}" = "-" ]; then
				cbsdsqlrw storage_media "DELETE FROM media WHERE name='${name}' AND path='${path}' AND type='${type}'"
			else
				cbsdsqlrw storage_media "DELETE FROM media WHERE name='${name}' AND path='${path}' AND type='${type}' AND jname='${jname}'"
			fi

		else
			if [ -n "${name}" ]; then
				select_by_name
				path="${vm_res}"
				cbsdsqlrw storage_media "DELETE FROM media WHERE name='${name}' AND jname='${jname}'"
			elif [ -n "${path}" ]; then
				# need before actual delete from SQL due to zvol deps check
				[ "${type}" = "iso" ] && try_to_rm ${path}
				cbsdsqlrw storage_media "DELETE FROM media WHERE path='${path}' AND jname='${jname}'"
			fi
		fi

		[ -z "${path}" ] && err 1 "${N1_COLOR}media delete: empty path variable${N0_COLOR}"

		short_dsk_path=$( ${BASENAME_CMD} ${path} )

		_res=$( substr --pos=0 --len=5 --str="${path}" )
		if [ "${_res}" = "/dev/" ]; then
			type="raw"
		fi

		case "${type}" in
			iso)
				try_to_rm -f ${path}
				;;
			vhd|hdd)
				if [ "${jname}" != "-" ]; then
					mydb="${jailsysdir}/${jname}/local.sqlite"
					cbsdsqlrw ${mydb} "DELETE FROM ${emulator}dsk WHERE dsk_path='${short_dsk_path}'"
				fi
				${emulator}_remove_dsk ${short_dsk_path}
				;;
			raw)
				if [ "${jname}" != "-" ]; then
					mydb="${jailsysdir}/${jname}/local.sqlite"
					cbsdsqlrw ${mydb} "DELETE FROM ${emulator}dsk WHERE dsk_path='${path}'"
				fi
				${FIND_CMD} ${jaildatadir}/${jname}-${jaildatapref}/ -mindepth 1 -maxdepth 1 -name dsk\*.vhd -type l | while read _link; do
					_realpath=$( ${READLINK_CMD} ${_link} )
					[ "${_realpath}" = "${path}" ] && ${RM_CMD} ${_link}
				done
				;;
		esac

		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_media_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_media_queue_name} cmd=refresh
		fi

		err 0 "${N1_COLOR}Deleted${N0_COLOR}"
		;;
	deleteall|removeall)
		for i in $( cbsdsqlro storage_media SELECT path FROM media WHERE type != 'hdd' ); do
			${ECHO} "${N1_COLOR}removing: ${N2_COLOR}${i}${N1_COLOR} ...${N0_COLOR}"
			media mode=remove path="${i}" type="iso"
		done
		exit 0
		;;
	update)
		[ -n "${type}" ] && update_type
		[ -n "${jname}" ] && update_jname
		;;
	dump)
		# export media data to ascii file
		[ ! -r ${dbdir}/storage_media.sqlite ] && err 1 "${N1_COLOR}Not readable: ${N2_COLOR}${dbdir}/storage_media.sqlite${N0_COLOR}"
		if [ -n "${jname}" ]; then
			_sql="SELECT name,path,type,size,jname FROM media WHERE jname='${jname}'"
		else
			_sql="SELECT name,path,type,size,jname FROM media"
		fi
		osqldelimer=${sqldelimer}
		sqldelimer="|"
		OIFS=${IFS}
		IFS="|"
		cbsdsqlrw storage_media ${_sql} | while read name path type size jname; do
			normalize_path=$( echo "${path}" | ${SED_CMD} s:${workdir}:%%workdir%%:g )
			_mysql="INSERT INTO media ( name, path, type, size, jname ) VALUES ( '${name}', '${normalize_path}', '${type}', '${size}', '${jname}' );"
			echo "${_mysql}"
		done
		IFS=${OIFS}
		sqldelimer=${osqldelimer}
		;;
	*)

		err 1 "${N1_COLOR}Unknown mode: ${N2_COLOR}${mode}${N0_COLOR}"
		;;
esac

exit 0
