Here is the new ehdd SHELL version (final version I suppose). Added functionality to list device names, better UI, better help messages, and some other tweaks are included in this version. I hope it works for you
:
Code: Select all
#!/bin/bash
check_sudo() {
if [ "$(id -u)" != "0" ]; then
printf "\033[31mError:\033[37m "
printf "\033[1m%s\033[0m not run as root. Run \033[1msudo %s\033[0m.\n" "$0" "$0"
exit 1
fi
}
print_help() {
echo "Usage: sudo ehdd [OPTIONS] or [DEVICE NAMES]"
echo
echo "Option Meaning"
echo "-h, --help Show this text."
echo "-v, --version Provide version information."
echo "-l, --list List available devices. (less information)"
echo "-lA Same as -l. (more information)"
echo "-V, --verbose Do not suppress error messages."
echo "-E, --ejectonly Only eject the device."
echo "-S, --shutdownonly Only shutdown the device."
echo "-bN, --byname Use device NAME. Same as ehdd NAME."
echo "-bL, --bylabel Use device LABEL. Same as ehdd /dev/disk/by-label/LABEL."
echo "-bU, --byuuid Use device UUID. Same as ehdd /dev/disk/by-uuid/UUID."
echo "-bPL, --bypartlabel Use device PARTLABEL. Same as ehdd /dev/disk/by-partlabel/PARTLABEL."
echo "-bPU, --bypartuuid Use device PARTUUID. Same as ehdd /dev/disk/by-partuuid/PARTUUID."
echo
echo "NOTES:"
echo
echo "1. Certain disks need to be shut off after ejecting, but not all must. To avoid shutting down devices that are not in need, ehdd attempts to identify which ones need to be shut down. Nevertheless, it is advisable to execute 'ehdd -l' to verify if the device is still listed. In this instance, ehdd should be used again with the device since it is not yet safe to remove the device physically."
echo
echo "2. Partition names like sda1, sda2, sdb1, etc. may only be unmounted (assuming they are on an ejectable drive) by passing them to ehdd. Even while this is helpful in certain situations, the device's other partition may be still in use. Therefore, it is still not safe to remove the gadget physically. Always provide device names (such sda, sdb, sdc, etc.) to ehdd instead of partition names before physically removing the device to make sure it's safe to do so."
echo
echo "3. Though LABEL and PARTLABEL serve nearly identical functions, they are two distinct partition variables. For some partitions, just one may be set. The same goes for UUID and PARTUUID. Thus, any of these can be passed to the ehdd of a device. You may also run 'ehdd -lA' to verify the variables for all devices on your PC."
echo
echo "4. --list utilises the 'lsblk' command to list devices whose column values may differ from those needed by ehdd. For example, on my system, LABEL of one partition is 'NEW VOLUME', but the actual block file name is 'NEW\x20VOLUME' in '/dev/disk/by-label/' (i.e. the space character was replaced with '\x20' characters by the OS for this label). So in this case, I should run \"ehdd 'NEW\x20VOLUME'\" instead of \"ehdd 'NEW VOLUME'\". However, this is OS (distribution) specific; other OSes may not substitute the space character."
echo
echo "EXAMPLES:"
echo "1. ehdd -lA"
echo " List NAME, UUID, PARTUUID (PARTITION UUID), LABEL, and PARTLABEL (PARTITION LABEL) of all devices."
echo "2. ehdd sdb"
echo " Eject and shutdown device 'sdb'."
echo "3. ehdd --bylabel 'My_Device' --ejectonly"
echo " Only eject the device with label 'My_Device'."
echo "4. ehdd sdb -bL 'My_Device' -bPU 'xxxx-xxxx' -bN sdc -S"
echo " Only shutdown devices with name 'sdb' and 'sdc', with label 'My_Device', and with PARTUUID 'xxxx-xxxx'."
}
print_version() {
echo "ehdd version: SHELL VERSION 1.0"
}
is_block_dev() {
if ! test -b "$1"; then
return 1
fi
}
ERROR_OCCURED="false"
eject_block_dev() {
DEV_NAME="$1"
printf "\033[0m a) Ejecting device.."
EJECT_MSG=$(eject "$DEV_NAME" 2>&1)
EJECT_STATUS=$?
if [ $EJECT_STATUS != 0 ]; then
ERROR_OCCURED="true"
printf "\033[31m Error\n"
if [ "$VERBOSE" = "true" ]; then
printf "eject returned with error code %s\n" "$EJECT_STATUS"
printf "Message returned by eject command:\n%s\n" "$EJECT_MSG"
fi
printf "\033[0m"
return 1
fi
printf "\033[32m Successful\033[0m\n"
}
shutdown_block_dev() {
DEV_NAME="$1"
printf "\033[0m b) Shutdown device.."
if ! is_block_dev "$DEV_NAME"; then
# seems that ejecting the device was enough and it doesn't need to shutdown
echo " (not required)"
return 0
fi
UDISKS_MSG=$(udisksctl power-off -b "$DEV_NAME" 2>&1)
UDISKS_STATUS=$?
if [ $UDISKS_STATUS != 0 ]; then
ERROR_OCCURED="true"
printf "\033[31m Error\n"
if [ "$VERBOSE" = "true" ]; then
printf "eject returned with error code %s\n" "$UDISKS_STATUS"
printf "Message returned by eject command:\n%s\n" "$UDISKS_MSG"
fi
printf "\033[0m"
return 1
fi
printf "\033[32m Successful\033[0m\n"
}
list_devices() {
if ! lsblk --help 1>/dev/null 2>&1; then
printf "\033[31mError:\033[0m command 'lsblk' not found.\n"
exit 1
fi
LIST_ALL=$1 # a boolean value
if [ "$LIST_ALL" = "false" ]; then
echo "NOTE: UUID and LABEL are currently hidden. Use 'ehdd -lA' to list them as well."
echo
lsblk -o "NAME,PARTUUID,PARTLABEL" -e7
else
lsblk -o "NAME,UUID,PARTUUID,LABEL,PARTLABEL" -e7
fi
}
declare -a DEV_NAMES
VERBOSE="false"
EJECTONLY="false"
SHUTDOWNONLY="false"
DEV_PREFIX="/dev/"
for arg in "$@"; do
case $arg in
--help|-h)
print_help
exit
;;
--version|-v)
print_version
exit
;;
--list|-l)
list_devices "false"
exit
;;
-lA)
list_devices "true"
exit
;;
--verbose|-V)
VERBOSE="true"
;;
--ejectonly|-E)
EJECTONLY="true"
;;
--shutdownonly|-S)
SHUTDOWNONLY="true"
;;
--byname|-bN)
DEV_PREFIX="/dev/"
;;
--bylabel|-bL)
DEV_PREFIX="/dev/disk/by-label/"
;;
--byuuid|-bU)
DEV_PREFIX="/dev/disk/by-uuid/"
;;
--bypartlabel|-bPL)
DEV_PREFIX="/dev/disk/by-partlabel/"
;;
--bypartuuid|-bPU)
DEV_PREFIX="/dev/disk/by-partuuid/"
;;
*)
if [[ "${arg:0:1}" == "-" ]]; then
# first letter of this arg is -
# consider this to be a unknown flag
printf "\033[31mError:\033[37m Unknown command line option '%s'.\n" "$arg"
exit 1
fi
CRR_DEV_NAME="$DEV_PREFIX""$arg" # real device name
# check if device is block
if ! is_block_dev "$CRR_DEV_NAME"; then
printf "\033[31mError:\033[37m '%s' not a valid device.\n" "$arg"
exit 1
fi
DEV_NAMES+=("$CRR_DEV_NAME") # add device to our device list
;;
esac
done
# Do few checks as well
if [ ${#DEV_NAMES[@]} -eq 0 ]; then
# device name not given
printf "\033[31mError:\033[37m Device name not provided.\n"
exit 1
fi
# check if program has root access
check_sudo
# if both EJECTONLY and SHUTDOWNONLY are true, interpret as both eject and shutdown
# so make both the commands off
if [ "$EJECTONLY" = "true" ] && [ "$SHUTDOWNONLY" = "true" ]; then
EJECTONLY="false"
SHUTDOWNONLY="false"
fi
dev_index=0
for dev in "${DEV_NAMES[@]}"; do
((dev_index++))
printf "\033[1m%s. %s\n" "$dev_index" "$dev"
eject_status=0
if [ "$SHUTDOWNONLY" = "false" ]; then
# see parse_cli_flag.sh:71
eject_block_dev "$dev"
eject_status=$?
fi
if [ "$EJECTONLY" = "false" ] && [ $eject_status -eq 0 ]; then
shutdown_block_dev "$dev"
fi
done
if [ "$VERBOSE" = "false" ] && [ "$ERROR_OCCURED" = "true" ]; then
echo
echo "Errors have occurred in some command."
echo "Run $0 with verbose on to see the error message."
fi
if [ "$ERROR_OCCURED" = "true" ]; then
exit 1
fi
Remove current ehdd (if present, check 'whereis ehdd' and remove that file), copy this code into a file named 'ehdd', and place that file in one of the directories listed in $PATH (like /usr/local/bin/).
It is advised that users read 'ehdd --help' for this version as there are some changes.