#!/bin/bash # $HeadURL$ $LastChangedRevision$ # Modules . $(miniade) || { echo "${0##*/}: ERROR: miniade failed (hint: run 'miniade' to see error)" >&2; exit 1; } # Configurable stuff # Other globals main() { local MY_ARGS # Defaults for options # Process options miniade_process_options --help-handler=help MY_ARGS "$@" && set -- "${MY_ARGS[@]}" # Process arguments [ $# = 1 ] || miniade_bad_usage type encode > /dev/null 2>&1 || miniade_internal "encode: command not found (hint: is PATH set correctly?)" ENCODE_OUTPUT=$(encode --decode "$1") || miniade_internal "encode: failed (hint: see messages above)" eval set -- "$ENCODE_OUTPUT" [ $# -ge 6 ] || miniade_bad_usage VOL_NAME="$1" VOL_SOURCE_TYPE="$2" VOL_SOURCE_NAME="$3" VOL_SIZE="$4" FS_TYPE="$5" ENC_FLAG="$6" shift 6 miniade_debug 10 "main: VOL_NAME=$VOL_NAME, VOL_SOURCE_TYPE=$VOL_SOURCE_TYPE, VOL_SOURCE_NAME=$VOL_SOURCE_NAME, VOL_SIZE=$VOL_SIZE, FS_TYPE=$FS_TYPE, ENC_FLAG=$ENC_FLAG" if [ "X$ENC_FLAG" = Xtrue ]; then [ $# = 1 ] || miniade_bad_usage PASSWD="$1" shift else [ $# = 0 ] || miniade_bad_usage fi # Sanity checks and derivations miniade_debug 10 "main: sanity checks ..." [[ $VOL_SOURCE_TYPE =~ ^(lvm|zfs)$ ]] || miniade_error "$VOL_SOURCE_TYPE: bad vol-source-type" [[ $VOL_SIZE =~ ^([1-9][0-9]*)(|[MG])$ ]] || miniade_error "$VOL_SIZE: bad vol-size" [[ $FS_TYPE =~ ^(ext4|swap|ext4|xfs|zfs)$ ]] || miniade_error "$FS_TYPE: bad fs-type" [[ $ENC_FLAG =~ ^(true|false)$ ]] || miniade_error "$ENC_FLAG: had enc-flag" { ! $ENC_FLAG; } || [ $VOL_SOURCE_TYPE != zfs ] || miniade_internal "support for encrypted ZFS filesystems is not implemented yet" convert_size_mb $VOL_SIZE VOL_SIZE_MB || miniade_internal "if convert_size_mb detected an error it should have exited itself" convert_logical_onoff $ENC_FLAG ENC_ONOFF || miniade_internal "if convert_logical_onoff detected and error it should have exited itself" OPENED_FLAG=false # Check vol-source-name exists miniade_debug 10 "main: checking $VOL_SOURCE_NAME exists ..." case $VOL_SOURCE_TYPE in lvm) vgs $VOL_SOURCE_NAME > /dev/null 2>&1 || miniade_error "$VOL_SOURCE_NAME: no such volume group" ;; zfs) zpool list $VOL_SOURCE_NAME > /dev/null 2>&1 || miniade_error "$VOL_SOURCE_NAME: no such zpool" ;; *) miniade_internal "unhandled" ;; esac # Check if vol-name exists within vol-source-name and create if not. miniade_debug 10 "main: checking $VOL_NAME exists and creating if not ..." case $VOL_SOURCE_TYPE in lvm) lvs $VOL_SOURCE_NAME/$VOL_NAME > /dev/null 2>&1 || miniade_evaler "lvcreate -y --name=$VOL_NAME --size=${VOL_SIZE_MB}M $VOL_SOURCE_NAME" || miniade_error "failed to create LV" ;; zfs) zfs list $VOL_SOURCE_NAME/$VOL_NAME > /dev/null 2>&1 || miniade_evaler "zfs create -o quota=${VOL_SIZE_MB}M -o mountpoint=legacy -o encryption=$ENC_ONOFF $VOL_SOURCE_NAME/$VOL_NAME" || miniade_error "failed to create zfs dataset" ;; *) miniade_internal "unhandled" ;; esac # Check size (really only applies in the case that we didn't just create # the volume because it aalready existing) miniade_debug 10 "main: checking vol-size ..." case $VOL_SOURCE_TYPE in lvm) LVS_OUTPUT=$(lvs $VOL_SOURCE_NAME/$VOL_NAME -o size --noheadings --units m) || miniade_internal "lvs: failed" convert_size_mb $LVS_OUTPUT ACTUAL_SIZE_MB ;; zfs) ZFS_OUTPUT=$(zfs get -H -o value quota $VOL_SOURCE_NAME/$VOL_NAME) || miniade_internal "zfs-get: failed" convert_size_mb $ZFS_OUTPUT ACTUAL_SIZE_MB ;; *) miniade_internal "unhandled" ;; esac miniade_debug 10 "main: ACTUAL_SIZE_MB=$ACTUAL_SIZE_MB" [ $ACTUAL_SIZE_MB = $VOL_SIZE_MB ] || miniade_error "$VOL_NAME: exists but wrong size (hint: fix manually)" # Set MKFS_FLAG and MKFS_DEVICE and, in the process, handle encrypted LVM-based volumes. if $ENC_FLAG && [ $VOL_SOURCE_TYPE = zfs ]; then case $FS_TYPE in zfs) MKFS_FLAG=false ;; swap) miniade_internal "swap on zfs (encrypted or otherwise) is prone to lockups!" ;; ext4|xfs) miniade_error "$FS_TYPE on an (encrypted or otherwise) zvol is overly complex!" ;; *) miniade_internal "this shouldn't happen" ;; esac elif $ENC_FLAG && [ $VOL_SOURCE_TYPE = lvm ]; then case $FS_TYPE in zfs) miniade_internal "can only put zfs filesystem on zfs volume source type" ;; swap) miniade_internal "encrypted swap is stupid" ;; ext4|xfs) # Format the device. if ! cryptsetup isLuks /dev/$VOL_SOURCE_NAME/$VOL_NAME; then miniade_debug 10 "main: /dev/$VOL_SOURCE_NAME/$VOL_NAME: device is not LUKS, so formatting ..." echo -n "$PASSWD" | cryptsetup -d - -q luksFormat /dev/$VOL_SOURCE_NAME/$VOL_NAME # After the format, the disk remains briefly open. STILL_OPEN_FLAG=true for I in $(seq 1 5); do sleep 1 lvs -o attr /dev/$VOL_SOURCE_NAME/$VOL_NAME --noheadings | grep -q o || { STILL_OPEN_FLAG=false; break; } done ! $STILL_OPEN_FLAG || miniade_error "/dev/$VOL_SOURCE_NAME/$VOL_NAME: is still open after ${I}s timeout!" else miniade_debug 10 "main: /dev/$VOL_SOURCE_NAME/$VOL_NAME: device is already LUKS, so not formatting" fi # Generate 8 char name to refer to decryted device. ID=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 8) # Open device so it can be formatted. echo -n "$PASSWD" | cryptsetup -d - -q luksOpen /dev/$VOL_SOURCE_NAME/$VOL_NAME $ID OPENED_FLAG=true MKFS_FLAG=true MKFS_DEVICE=/dev/mapper/$ID ;; *) miniade_internal "this shouldn't happen" ;; esac elif { ! $ENC_FLAG; } && [ $VOL_SOURCE_TYPE = zfs ]; then case $FS_TYPE in zfs) MKFS_FLAG=false ;; swap) miniade_internal "swap on zfs (unencrypted or otherwise) is prone to lockups!" ;; ext4|xfs) miniade_internal "$FS_TYPE on an (unencrypted or otherwise) zvol is overly complex!" ;; *) miniade_internal "this shouldn't happen" ;; esac elif { ! $ENC_FLAG; } && [ $VOL_SOURCE_TYPE = lvm ]; then case $FS_TYPE in zfs) miniade_internal "can only put zfs filesystem on zfs volume source type" ;; swap) MKFS_FLAG=true MKFS_DEVICE=/dev/$VOL_SOURCE_NAME/$VOL_NAME ;; ext4|xfs) MKFS_FLAG=true MKFS_DEVICE=/dev/$VOL_SOURCE_NAME/$VOL_NAME ;; *) miniade_internal "this shouldn't happen" ;; esac else miniade_internal "this shouldn't happen" fi # Guts # Make filesystem if $MKFS_FLAG; then miniade_debug 10 "main: checking existing blkid of VOL_NAME/device ..." EXISTING_TYPE=$(file -bsL $MKFS_DEVICE) case $FS_TYPE in ext4) if ! [[ $EXISTING_TYPE =~ ext4 ]]; then miniade_debug 10 "main: $MKFS_DEVICE: device is not ext4, so formatting ..." mkfs -t ext4 -F -q $MKFS_DEVICE else miniade_debug 10 "main: $MKFS_DEVICE: device is already ext4, so not formatting" fi ;; xfs) if ! [[ $EXISTING_TYPE =~ XFS ]]; then miniade_debug 10 "main: $MKFS_DEVICE: device is not xfs, so formatting ..." mkfs -t xfs -f -q $MKFS_DEVICE else miniade_debug 10 "main: $MKFS_DEVICE: device is already xfs, so not formatting" fi ;; swap) [[ $EXISTING_TYPE =~ swap ]] || mkswap $MKFS_DEVICE ;; *) miniade_internal "this shouldn't happen" ;; esac fi # Close the device if necessary { ! $OPENED_FLAG; } || cryptsetup close $ID } help() { local PROGNAME ade_get_progname PROGNAME echo "Usage: $PROGNAME [ ] @@@@@[@" echo echo "Args: : { lvm | zfs }" echo " : { | }" echo " : [M|G]" echo " : { ext4 | swap | xfs | zfs }" echo " : { true | false }" echo " : (only if == true)" echo exit 0 } convert_size_mb() { local SIZE SIZE_REF SIZE_MULTIPLIER [ $# = 2 ] || miniade_internal "convert_size_mb: invalid arg count ($#)" SIZE=$1 SIZE_REF=$2 miniade_debug 10 "convert_size_mb: SIZE=$SIZE, SIZE_REF=$SIZE_REF" # Sanity checks and derivations [[ $SIZE =~ ^([1-9][0-9]*)(|\.0+)(|[MGmg])$ ]] || miniade_error "$SIZE: bad size" SIZE=${BASH_REMATCH[1]} SIZE_MULTIPLIER=${BASH_REMATCH[3]^^} if [ "X$SIZE_MULTIPLIER" = X ]; then miniade_warning "$SIZE: size without unit suffix; assuming 'M'" SIZE_MULTIPLIER=M fi # Guts case $SIZE_MULTIPLIER in M) : ;; G) ((SIZE*=1024)) ;; *) miniade_internal "unhandled" ;; esac eval "$SIZE_REF=\"$SIZE\"" } convert_logical_onoff() { local LOGICAL ONOFF_REF [ $# = 2 ] || miniade_internal "convert_logical_onoff: invalid arg count ($#)" LOGICAL=$1 ONOFF_REF=$2 # Sanity checks and derivations [[ $LOGICAL =~ ^(true|false)$ ]] || miniade_error "$LOGICAL: bad logical" # Guts if $LOGICAL; then eval "$ONOFF_REF=on" else eval "$ONOFF_REF=off" fi } main "$@"