#!/bin/bash #=============================================================================# # FILE: fvwm-menu-udisks (obdevicemenu ported to FVWM, attempt 2) # # VERSION: 1.4.0 # # # # DESCRIPTION: an Openbox pipe menu for the management of removable media # # with Udisks ported to FVWM # # LICENSE: GPL2 # # AUTHOR: Jamie Nguyen (ported by greatant) # #=============================================================================# # Copyright (C) 2011 Jamie Nguyen # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License v2 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #-------------------------------------# # CONFIGURATION # #-------------------------------------# # {{{ declare udisks="/usr/bin/udisks" declare filemanager="/usr/bin/Thunar" declare notify="/usr/bin/notify-send" declare notify_options="--expire-time=3000" declare optical_devices="-E ^/dev/sr[0-9]+" declare removable_devices="-E ^/dev/sd[b-z][0-9]*|^/dev/mmcblk[0-9]+p*[0-9]*" declare mount_options="--mount-options nosuid,noexec,noatime" declare -i show_internal=0 declare -i show_notifications=1 declare -i show_optical_device_filename=1 declare -i show_removable_device_filename=1 declare -i fancy_sort=0 declare separator_removable_media="Removable media" declare separator_optical_media="Optical media" declare separator_device_info="Device information" declare info_udisks_failed="Udisks failed." declare info_no_devices="None" declare info_mounted="(mounted)" declare info_no_label="No label" declare msg_unmount_all_removable="Unmount all removable devices?" declare msg_unmount_all_optical="Unmount all optical devices?" declare msg_mounting_device="Mounting" declare msg_unmounting_device="Unmounting" declare msg_unmounted="unmounted successfully." declare msg_ejecting_device="Ejecting" declare item_eject="Eject" declare item_info="Info" declare item_mount="Mount" declare item_open="Open" declare item_unmount="Unmount" declare item_unmount_all="Unmount all" declare item_device_filename="device:" declare item_label="label:" declare item_vendor="vendor:" declare item_model="model:" declare item_type="type:" declare item_media="media:" declare item_device_size="size (device):" declare item_partition_size="size (partition):" declare CONFIGFILE if [[ -n "${XDG_CONFIG_HOME}" ]]; then CONFIGFILE="${XDG_CONFIG_HOME}/obdevicemenu/config" else CONFIGFILE="${HOME}/.config/obdevicemenu/config" fi if [[ ! -f "${CONFIGFILE}" ]]; then CONFIGFILE="/etc/obdevicemenu.conf" fi if [[ -f "${CONFIGFILE}" ]]; then . "${CONFIGFILE}" if [[ $? -ne 0 ]]; then printf '%s\n' "DestroyMenu recreate FvwmMenuUdisks" printf '%s\n' "AddToMenu FvwmMenuUdisks fvwm-menu-udisks Title" printf '%s\n' "+ \"Failed to source configuration file\"" exit 1 fi fi if [[ ! -f "${udisks}" ]]; then printf '%s\n' "DestroyMenu recreate FvwmMenuUdisks" printf '%s\n' "AddToMenu FvwmMenuUdisks fvwm-menu-udisks Title" printf '%s\n' "+ \"Udisks not installed\"" exit 1 fi # }}} #-------------------------------------# # INTERNAL API # #-------------------------------------# # {{{ notify() { if [[ "${show_notifications}" = "1" ]] && [[ -f "${notify}" ]]; then if [ -z "${notify_options}" ]; then $notify "$*" else $notify ${notify_options} "$*" fi else $* fi } # functions to retrieve information info_blank() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*blank:" \ | awk '{print $2}' } info_ejectable() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*ejectable:" \ | awk '{print $2}' } info_has_media() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*has media:" \ | awk '{print $3}' } info_internal() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*system internal:" \ | awk '{print $3}' } info_label() { local info_label= info_label="$($udisks --show-info ${1} \ | grep -m 1 -w "^ label:" \ | awk '{$1="";gsub(/_/,"");print substr($0, index($0,$2))}')" if [[ -n "${info_label}" ]]; then printf '%s\n' "${info_label}"; return fi } info_media() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*media:" \ | awk '{gsub(/_/,"");print $2}' } info_model() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*model:" \ | awk '{$1="";gsub(/_/,"");print substr($0, index($0,$2))}' } info_mounted() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*is mounted:" \ | awk '{print $3}' } info_mountpath() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*mount paths:" \ | awk '{$1="";$2="";print substr($0, index($0,$3))}' } info_type() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*type:" \ | awk '{gsub(/_/,"");print $2}' } info_vendor() { $udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*vendor:" \ | awk '{$1="";gsub(/_/,"");print substr($0, index($0,$2))}' } convert_size() { local -i old_size="${1}" local new_size= printf '%s\n' "${old_size}" | grep -ow -E ^[1-9]{1}[0-9]*$ >/dev/null 2>&1 [[ $? -ne 0 ]] && return 1 if [[ "${old_size}" -gt "21474836480" ]]; then new_size="$((${old_size}/1073741824)) GB" elif [[ "${old_size}" -gt "10485760" ]]; then new_size="$((${old_size}/1048576)) MB" elif [[ "${old_size}" -gt "10240" ]]; then new_size="$((${old_size}/1024)) kB" else new_size="${old_size} bytes" fi printf '%s\n' "${new_size}" } info_device_size() { local info_device_size= info_device_size="$($udisks --show-info ${1} \ | grep -m 1 -w "^[[:space:]]*size:" \ | awk '{print $2}')" if [[ -n "${info_device_size}" ]]; then info_device_size="$(convert_size "${info_device_size}")" printf '%s\n' "${info_device_size}" fi } info_partition_size() { local info_partition_size= info_partition_size="$($udisks --show-info ${1} \ | grep -m 1 -w " size:" \ | awk '{print $2}')" if [[ -n "${info_partition_size}" ]]; then info_partition_size="$(convert_size "${info_partition_size}")" printf '%s\n' "${info_partition_size}" fi } # functions to perform udisks commands action_mount() { local devname="${1}" notify "$(printf '%s\n' "${msg_mounting_device} ${devname} ...")" notify "$($udisks --mount ${devname} ${mount_options})" } action_unmount() { local devname="${1}" notify "$(printf '%s\n' "${msg_unmounting_device} ${devname} ...")" notify "$($udisks --unmount ${devname})" # if udisks unmounts successfully, there is no output from udisks # so notify-send fails and will return 1 if [[ $? = '1' ]]; then notify "$(printf '%s\n' "${devname} ${msg_unmounted}")" fi } action_unmount_all() { for devname in $*; do notify "$(printf '%s\n' "${msg_unmounting_device} ${devname} ...")" notify "$($udisks --unmount ${devname})" if [[ $? = '1' ]]; then notify "$(printf '%s\n' "${devname} ${msg_unmounted}")" fi done } action_eject() { local devname="${1}" local -i mounted= mounted="$(info_mounted "${devname}")" if [[ "${mounted}" -eq 1 ]]; then action_unmount "${devname}" fi notify "$(printf '%s\n' "${msg_ejecting_device} ${devname} ...")" notify "$($udisks --eject ${devname})" } action_open() { local devname="${1}" local info_mountpath="$(info_mountpath "${devname}")" if [[ -n "${info_mountpath}" ]]; then $filemanager "${info_mountpath}" else $filemanager fi } action_info() { local devname="${1}" local devmajor="${devname%%[0-9]*}" $udisks --show-info ${devname} >/dev/null 2>&1 if [[ $? -ne 0 ]]; then printf '%s\n' "DestroyMenu FvwmMenuUdisksInfo" printf '%s\n' "AddToMenu FvwmMenuUdisksInfo fvwm-menu-udisks Title" printf '%s\n' "+ \"${info_udisks_failed}\"" exit 0 fi local info_label="$(info_label "${devname}")" local info_vendor="$(info_vendor "${devmajor}")" local info_model="$(info_model "${devmajor}")" local info_device_size="$(info_device_size "${devmajor}")" local info_type="$(info_type "${devname}")" local info_media="$(info_media ${devname})" if [[ "${devname}" != "${devmajor}" ]]; then local info_partition_size="$(info_partition_size "${devname}")" fi printf '%s\n' "DestroyMenu FvwmMenuUdisksInfo" printf '%s\n' "AddToMenu FvwmMenuUdisksInfo \"${separator_device_info}\" Title" [[ -n "${info_device_filename}" ]] && \ printf '%s\n' "+ \"${item_device_filename} ${devname}\"" [[ -n "${info_label}" ]] && \ printf '%s\n' "+ \"${item_label} ${info_label}\"" [[ -n "${info_vendor}" ]] && \ printf '%s\n' "+ \"${item_vendor} ${info_vendor}\"" [[ -n "${info_model}" ]] && \ printf '%s\n' "+ \"${item_model} ${info_model}\"" [[ -n "${info_revision}" ]] && \ printf '%s\n' "+ \"${item_revision} ${info_revision}\"" [[ -n "${info_type}" ]] && \ printf '%s\n' "+ \"${item_type} ${info_type}\"" [[ -n "${info_version}" ]] && \ printf '%s\n' "+ \"${item_version} ${info_version}\"" [[ -n "${info_media}" ]] && \ printf '%s\n' "+ \"${item_media} ${info_media}\"" [[ -n "${info_partition_size}" ]] && \ printf '%s\n' "+ \"${item_partition_size} ${info_partition_size}\"" [[ -n "${info_device_size}" ]] && \ printf '%s\n' "+ \"${item_device_size} ${info_device_size}\"" } fancy_sort() { # this is a very hacky way to sort devices so that /dev/sdc11 wont come # before /dev/sdc2, which happens due to a shortcoming of the sort command # we wont tell bash that partition_number is a number, otherwise it # breaks when leading zeros are added local devname= devmajor= partition_number= local -i j= # first lets put a leading zero in front of single digits (sdc1 -> sdc01). # we are going to ignore /dev/mmcblk* devices... too complicated to sort. j=0 for devname in ${removable[@]}; do if [[ "${devname}" =~ ^/dev/dm-[0-9]+ ]]; then devmajor="${devname%%[0-9]*}" elif [[ "${devname}" =~ ^/dev/fd[0-9]+ ]]; then devmajor="${devname%%[0-9]*}" elif [[ "${devname}" =~ ^/dev/sd[a-z][0-9]+ ]]; then devmajor="${devname%%[0-9]*}" else j=$((++j)); continue fi if [[ "${devname}" = "${devmajor}" ]]; then j=$((++j)); continue fi partition_number="${devname#${devmajor}}" removable[${j}]=${devmajor}$(printf '%02d' "${partition_number}") j=$((++j)) done # now the device array can be sorted properly removable=( $(printf '%s\n' "${removable[@]}" | sort) ) # now lets remove those leading zeros that we added j=0 for devname in ${removable[@]}; do if [[ "${devname}" =~ ^/dev/dm-[0-9]+ ]]; then devmajor="${devname%%[0-9]*}" elif [[ "${devname}" =~ ^/dev/fd[0-9]+ ]]; then devmajor="${devname%%[0-9]*}" elif [[ "${devname}" =~ ^/dev/sd[a-z][0-9]+ ]]; then devmajor="${devname%%[0-9]*}" else j=$((++j)); continue fi if [[ "${devname}" = "${devmajor}" ]]; then j=$((++j)); continue fi partition_number="${devname#${devmajor}}" removable[${j}]=${devmajor}${partition_number#0} j=$((++j)) done } # main functions device_menu() { local -a removable=( ) local -a optical=( ) local -a mounted_removable=( ) local -a mounted_optical=( ) local -i j=0 printf '%s\n' "DestroyMenu recreate FvwmMenuUdisks" printf '%s\n' "AddToMenu FvwmMenuUdisks MissingSubmenuFunction FuncFvwmMenuUdisks" $udisks --enumerate-device-files >/dev/null 2>&1 if [[ $? -ne 0 ]]; then printf '%s\n' "+ fvwm-menu-udisks Title" printf '%s\n' "+ \"${info_udisks_failed}\"" exit 0 fi # removable media printf '%s\n' "+ \"${separator_removable_media}\" Title" removable=( $($udisks --enumerate-device-files \ | grep -ow ${removable_devices} | sort) ) if [[ ${fancy_sort} -eq 1 ]]; then fancy_sort fi for devname in ${removable[@]}; do local devmajor= local info_label= local -i info_internal= local -i mounted= local -i partitions= # check here to see if a device such as /dev/sdb has partitions. if there # are partitions, such as /dev/sdb1, then hide /dev/sdb from being shown. if [[ "${devname}" =~ ^/dev/mmcblk[0-9]+p*[0-9]* ]]; then devmajor="${devname%%p[0-9]*}" if [[ "${devname}" = "${devmajor}" ]]; then partitions="$($udisks --enumerate-device-files \ | grep -ow -E ^${devname}p[0-9]+ -c)" if [[ "${partitions}" -gt 0 ]]; then continue fi fi else devmajor="${devname%%[0-9]*}" if [[ "${devname}" = "${devmajor}" ]]; then partitions="$($udisks --enumerate-device-files \ | grep -ow -E ^${devname}[0-9]+ -c)" if [[ "${partitions}" -gt 0 ]]; then continue fi fi fi info_internal="$(info_internal "${devmajor}")" if [[ "${info_internal}" -eq 1 ]] && [[ "${show_internal}" -eq 0 ]]; then continue fi if [[ "${info_internal}" -eq 0 ]] || [[ "${show_internal}" -eq 1 ]]; then j=$((++j)) info_label="$(info_label "${devname}")" # if no label is present, then use information about the device instead if [[ -z "${info_label}" ]]; then info_label="$(info_label "${devmajor}")" [[ -z "${info_label}" ]] && info_label="$(info_model "${devmajor}")" [[ -z "${info_label}" ]] && info_label="$(info_vendor "${devmajor}")" if [[ -z "${info_label}" ]]; then info_label="No label" else info_label="No label (${info_label})" fi fi mounted="$(info_mounted "${devname}")" if [[ "${mounted}" -eq 0 ]]; then if [[ "${show_removable_device_filename}" -eq 1 ]]; then printf '%s\n' "+ \"${devname#/dev/}: ${info_label}\" Popup ${devname}" # printf '%s' "" # printf '\n' else printf '%s\n' "+ \"${info_label}\" Popup ${devname}" # printf '%s' "" # printf '\n' fi else if [[ "${show_removable_device_filename}" -eq 1 ]]; then printf '%s\n' "+ \"${devname#/dev/}: ${info_label} ${info_mounted}\" Popup ${devname}" # printf '%s' "" # printf '\n' else printf '%s\n' "+ \"${info_label} ${info_mounted}\" Popup ${devname}" # printf '%s' "" # printf '\n' fi mounted_removable[${#mounted_removable[*]}]=${devname} fi fi done if [[ $j -eq 0 ]]; then printf '%s\n' "+ \"${info_no_devices}\"" fi if [[ "${#mounted_removable[*]}" -gt 0 ]]; then printf '%s\n' "+ \"${item_unmount_all}\" Exec $0 --unmount-all-removable ${mounted_removable[*]}" fi # optical media printf '%s\n' "+ \"${separator_optical_media}\" Title" optical=( $($udisks --enumerate-device-files \ | grep -ow ${optical_devices} | sort) ) if [[ "${#optical[*]}" -eq 0 ]]; then printf '%s\n' "+ \"${info_no_devices}\"" return 0 fi for devname in ${optical[@]}; do local info_label= local -i info_blank= local -i info_has_media= local -i mounted= info_has_media="$(info_has_media "${devname}")" if [[ "${info_has_media}" -eq 0 ]]; then printf '%s\n' "+ \"${devname#/dev/}: ${info_no_devices}\"" else info_blank="$(info_blank "${devname}")" if [[ "${info_blank}" -eq 1 ]]; then info_label="Blank media" else info_label="$(info_label ${devname})" [[ -z "${info_label}" ]] && info_label="$(info_model "${devname}")" [[ -z "${info_label}" ]] && info_label="No label" fi mounted="$(info_mounted "${devname}")" if [[ "${mounted}" -eq 0 ]]; then if [ "${show_optical_device_filename}" -eq 1 ]; then printf '%s\n' "+ \"${devname#/dev/}: ${info_label}\" Popup ${devname}" # printf '%s' "" # printf '\n' else printf '%s\n' "+ \"${info_label}\" Popup ${devname}" # printf '%s' "" # printf '\n' fi else if [[ "${show_optical_device_filename}" -eq 1 ]]; then printf '%s\n' "+ \"${devname#/dev/}: ${info_label} ${info_mounted}\" Popup ${devname}" # printf '%s' "" # printf '\n' else printf '%s\n' "+ \"${info_label} ${info_mounted}\" Popup ${devname}" # printf '%s' "" # printf '\n' fi mounted_optical[${#mounted_optical[*]}]=${devname} fi fi done if [[ "${#mounted_optical[*]}" -gt 0 ]]; then printf '%s\n' "+ \"${item_unmount_all}\" Exec $0 --unmount-all-optical ${mounted_optical[*]}" fi } mount_menu() { # local media_type="${1}" local devname="${1}" # local info_label="${3}" local devname_short="${devname##*/}" local -i info_ejectable= local -i mounted= printf '%s\n' "DestroyMenu recreate ${devname}" printf '%s\n' "AddToMenu ${devname} MissingSubmenuFunction FuncFvwmMenuUdisksInfo" printf '%s\n' "+ DynamicPopdownAction DestroyMenu ${devname}" printf '%s\n' "+ \"${devname}\" Title" mounted="$(info_mounted "${devname}")" if [[ "${mounted}" -eq 0 ]]; then printf '%s\n' "+ \"${item_open}\" Exec $0 --mount-and-open ${devname}" # printf '%s\n' "" # printf '%s\n' "" # printf '%s\n' "$0 --mount-and-open ${devname}" # printf '%s\n' "" # printf '%s\n' "" printf '%s\n' "+ \"${item_mount}\" Exec $0 --mount-device ${devname}" # printf '%s\n' "" # printf '%s\n' "" # printf '%s\n' "$0 --mount-device ${devname}" # printf '%s\n' "" # printf '%s\n' "" else printf '%s\n' "+ \"${item_open}\" Exec $0 --open-directory ${devname}" # printf '%s\n' "" # printf '%s\n' "" # printf '%s\n' "$0 --open-directory ${devname}" # printf '%s\n' "" # printf '%s\n' "" printf '%s\n' "+ \"${item_unmount}\" Exec $0 --unmount-device ${devname}" # printf '%s\n' "" # printf '%s\n' "" # printf '%s\n' "$0 --unmount-device ${devname}" # printf '%s\n' "" # printf '%s\n' "" fi info_ejectable="$(info_ejectable "${devname}")" if [[ "${info_ejectable}" -eq 1 ]]; then printf '%s\n' "+ \"${item_eject}\" Exec $0 --eject-device ${devname}" # printf '%s\n' "" # printf '%s\n' "" # printf '%s\n' "$0 --eject-device ${devname}" # printf '%s\n' "" # printf '%s\n' "" fi printf '%s\n' "+ \"${item_info}\" Popup FvwmMenuUdisksInfo" # printf '%s' "" # printf '\n' action_info ${devname} } # }}} if [[ $# == 0 ]]; then device_menu exit 0 fi case "${1}" in "--mount-menu") declare media_type="${2}" declare devname="${3}" shift 3 mount_menu ${media_type} ${devname} "${*}" ;; "--mount-device") action_mount "${2}" ;; "--unmount-device") action_unmount "${2}" ;; "--eject-device") action_eject "${2}" ;; "--open-directory") action_open "${2}" ;; "--mount-and-open") action_mount "${2}" && action_open "${2}" ;; "--show-info") action_info "${2}" ;; "--unmount-all-removable") shift 1 && action_unmount_all $@ ;; "--unmount-all-optical") shift 1 && action_unmount_all $@ ;; esac # vim: set ts=4 sw=4 noet foldmethod=marker :