Skip to content

Instantly share code, notes, and snippets.

@Zobber
Created April 13, 2020 02:25
Show Gist options
  • Save Zobber/479250e3f14430e96c814dd3e5c4d4e3 to your computer and use it in GitHub Desktop.
Save Zobber/479250e3f14430e96c814dd3e5c4d4e3 to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# showmydisks - report partitions, types, filesystems, and disk space usage
#
PRGVERSION="v0.12 * 2015-09-12 (c) Andreas Schamanek"
# Copyright 2004-2015: Andreas Schamanek <[email protected]>
# Homepage: http://wox.at/as/_/showmydisks
# License + History: see end of file
# Usage : showmydisks [--debug] [-L] [-u] ["dev1 ... devN"]
# Example: showmydisks "hda sda"
# Example: showmydisks -u # show also unallocated sectors
# Note : Use this script carefully. It's been hacked quick and dirty
# by a bad programmer. It's been tested only on a few Debian systems.
# It currently depends on the existence of at least:
# bash, df, sed, awk, file, /etc/fstab, /sys/block, /proc
# ''lsblk'' from the util-linux collection is a great alternative providing
# more details and a beautiful output with several options to configure it.
# lsblk(8) should be available on all major Linux distributions by default.
# me (name of this script without path)
ME=$(basename $0)
PRGVERSION="$ME $PRGVERSION"
# some standard variables
TRUE=0 ; FALSE=1
# debug?
DEBUG=$FALSE
[[ $1 == --debug ]] && DEBUG=$TRUE && shift
# some useful functions
function debugmsg { test $DEBUG = $TRUE && echo -ne "$1" >&2 ; }
function warning { echo -e "\n$ME: warning: $1\n" >&2 ; }
function die { echo -e "\n$ME: error: $2. aborting.\n" >&2 ; exit $1 ; }
# if $1 is --help show usage and example
[[ $1 == --help ]] \
&& echo "Usage: $ME [--debug] [-L] [-u] [\"dev1 ... devN\"]
Example: $ME \"hda sda\"
(Note: Order of command line arguments must not be mixed up.)
" >&2 && exit 0
# if $1 is -L only list devices of hard drives/block devices w/o RAIDs
LISTONLY=$FALSE
[[ $1 == -L ]] && LISTONLY=$TRUE && shift
# if $1 is -u show also unallocated sectors
SHOWUNALLOCATED=$FALSE
[[ $1 == -u ]] && SHOWUNALLOCATED=$TRUE && shift
debugmsg "$PRGVERSION\n"
# warn if script not run as root and expand PATH (mostly for fdisk)
test $UID -ne 0 -a $LISTONLY = $FALSE \
&& { warning "you probably want to be root" ; PATH="/sbin:$PATH" ; }
# list of disks to investigate, provided by $1 or /sys/block/{h,s}d?
DISKS=${1:-`cd /sys/block && "ls" -d hd? sd? 2>/dev/null`}
debugmsg "[disks to consider: $(echo $DISKS)]\n"
# Skip CD-Rom drives and disks with no size, and construct $DISKS
for MYDEV in $DISKS ; do
test -r /sys/block/$MYDEV/device/media \
&& if [ "/$(</sys/block/$MYDEV/device/media)" = "/cdrom" ] ; then
debugmsg "[$MYDEV is type cd-rom]\n"
# remove CD-Rom from $DISKS
DISKS=${DISKS/$MYDEV/}
fi
if [ -s /sys/block/$MYDEV/size ] ; then
MYDEVSIZE=$(</sys/block/$MYDEV/size)
if (( MYDEVSIZE < 99 )) ; then
debugmsg "[$MYDEV's size is reported as $MYDEVSIZE; skipping it]\n"
DISKS=${DISKS/$MYDEV/}
else
debugmsg "[$MYDEV's size = $MYDEVSIZE]\n"
fi
else
debugmsg "[$MYDEV has no valid /sys/block/$MYDEV/size; skipping it]\n"
DISKS=${DISKS/$MYDEV/}
fi
done
DISKS=$(echo $DISKS) # just to remove newlines and extra spaces
# bail out if $DISKS is empty
[[ $DISKS ]] || die 2 "list of disks to investigate is empty"
# add Software RAID to DISKS unless user requested a specific list
if [ "/$1/" = '//' -a -r /proc/mdstat ] ; then
# testing for /proc/mdstat is not sufficient; maybe test -s is?
MDDEVS=$(cd /sys/block && "ls" -d md[0-9] md[0-9][0-9] 2>/dev/null )
MDDEVS=$(echo $MDDEVS) # remove newlines (just for the debugmsg)
debugmsg "[MDDEVS=$MDDEVS]\n"
test "/$MDDEVS/" != '//' && DISKS="$DISKS md"
fi
# Eventually we have compiled $DISKS
debugmsg "[DISKS=$DISKS]\n"
# list of valid disks and partitions (e.g. as detected by kernel)
# VALIDDISKS=$(</proc/partitions) # kernel 2.4.x, has no cdrom, etc.
VALIDDISKS=$(</proc/diskstats) # kernel 2.6.x
# VALIDDISKS=" hda hda1 hda2 hde hde5" # your custom list, mind the 1st space
# symbols for output
SYMDISK="> " # symbol for disks
SYMPART="|-- " # symbol for partitions
# SYMSEP="-----------\n" # separator between disks (include \n, ...)
# make sure we got what we need
[ ! -r /proc/partitions ] && { die 1 "/proc/partitions not readable" ; }
[ ! -r /proc/mounts ] && { die 1 "/proc/mounts not readable" ; }
# collect system data for later use
DF=$(df -klT)
[ -r /proc/mdstat ] && MDSTAT=$(</proc/mdstat) || MDSTAT=
# find rootfs device
ROOTFS=$(awk '$2=="/"&&$1!="rootfs"{print $1}' /proc/mounts)
if [[ $ROOTFS ]] ; then
mapfile -t rootfsarray <<<"$ROOTFS"; rootfscount=${#rootfsarray[@]};
if (( rootfscount > 1 )) ; then
warning "Found $rootfscount rootfs devices mounted on /"
debugmsg "[ROOTFS($rootfscount)=$ROOTFS]\n"
debugmsg "[reducing ROOTFS to last entry]\n"
ROOTFS=${#rootfsarray[-1]}
fi
else
warning "Could not find a device for rootfs (= mount on /)".
fi
debugmsg "[ROOTFS=$ROOTFS]\n"
ROOTFSDEV=$(readlink -e $ROOTFS)
[[ $ROOTFSDEV ]] || die 3 "readlink -e failed for $ROOTFS"
debugmsg "[ROOTFSDEV=$ROOTFSDEV]\n"
ROOTFSTYPE=$(awk "\$1==\"$ROOTFS\"{print \$3}" /proc/mounts)
# some more useful functions
function getparm { MYPOS=$1 ; shift ; echo ${@:$MYPOS:1} ; }
function prettyprintsize {
MYVAL="$1"
for UNIT in KB MB GB TB ; do
MYRES="$MYVAL $UNIT"
NEW=$((MYVAL / 1024))
test $NEW -lt 2 && break
MYVAL=$NEW
done
echo -n $MYRES
}
function getcapacity {
MYCAPAC=$(awk -v partition=$1 '$4 == partition {print $3}' </proc/partitions)
debugmsg "[MYCAPAC=$MYCAPAC] "
[ $MYCAPAC ] && prettyprintsize $MYCAPAC
}
function isrootfs {
# check if $1 is the rootfs
[[ /dev/$1 == $ROOTFSDEV ]] || return $FALSE
MYDF=$(echo "$DF" | awk '/\/$/{df=$5}END{print df}')
CAPFREE=$(prettyprintsize $MYDF)
echo -n "on / as $ROOTFSTYPE ($CAPFREE free)"
}
function mountedas {
# note: mountedas returns $FALSE if $1 _is_ mounted, $TRUE if _not_
awk "/^\/dev\/$1 /"'{ printf "on %s as %s", $2, $3 }' < /proc/mounts
# if mounted get free capacity
MYDF=`echo "$DF" | grep "^/dev/$1 "`
if [ -n "$MYDF" ] ; then
CAPFREE=$(prettyprintsize $(getparm 5 $MYDF))
echo -n " ($CAPFREE free)"
return $FALSE
fi
}
function gettype {
# get type of filesystem if partition $1 is not mounted by use of _file -s_
# idea from _scanpartitions_ of KNOPPIX 3.7 (c) Klaus Knopper Nov 2002
FILE=$(LC_ALL=C file -Ls "/dev/$1")
[ "$?" = "0" ] || return 2
case "$FILE" in
*[Ee][Xx][Tt]2*) echo -n "ext2"; return 0;;
*[Ee][Xx][Tt]3*) echo -n "ext3"; return 0;;
*[Ee][Xx][Tt]4*) echo -n "ext4"; return 0;;
*[Rr][Ee][Ii][Ss][Ee][Rr]*) echo -n "reiserfs"; return 0;;
*[Ff][Aa][Tt]*|*[Xx]86*) echo -n "vfat|msdos"; return 0;;
*[Xx][Ff][Ss]*) echo -n "xfs"; return 0;;
*[Nn][Tt][Ff][Ss]*) echo -n "ntfs"; return 0;;
*[Ss][Ww][Aa][Pp]*) echo -n "swap"; return 0;;
*LUKS\ encrypted*) echo -n "LUKS encrypted"; return 0;;
*\ data*) echo -n "garbage?"; return 0;;
*) echo -n "fs unknown"; return 0;;
esac
}
function isinraid {
# check if $1 is part of a Software RAID set (checking $MDSTAT)
RAID=$(awk -F: "/ $1\[/ { print \$1 }" <<< "$MDSTAT")
[ $RAID ] && echo -n ", used in" $RAID
}
# start of actions ------------------------------------------------------
# print name of system
# echo "# $(uname -n) (kernel $(uname -r), disks as of $(date +%Y-%m-%d))"
for MYDEV in $DISKS ; do
# cleanup + check MYDEV is a block device (unless it is md)
MYDEV=$(basename -- "$MYDEV")
if [ $MYDEV != 'md' -a ! -b /dev/"$MYDEV" ] ; then
warning "$MYDEV is not a block special device"
fi
# start output (unless $LISTONLY)
[ $LISTONLY = $FALSE ] && echo -en "${SYMDISK}$MYDEV:"
# check if it's there
if ! echo "$VALIDDISKS" | grep -sq " $MYDEV" ; then
die 1 "$MYDEV seems to be no valid disk or partition"
fi
# LISTONLY: Only list devices of block devices (quick and dirty)
if [ $LISTONLY = $TRUE ] ; then
[ "/$MYDEV/" != '/md/' ] && echo "$MYDEV"
continue
fi
# we have to distinguish normal block devs and Software RAID
case /$MYDEV/ in
/md/ ) # Software RAID
MYMODEL="Software RAID"
echo -n \ ${MYMODEL}
# total capacity; we sum up all md "partitions"
echo -n " ("
prettyprintsize $(awk '$4 ~ /^md[0-9]/ { sum+=$3 }
END { print sum }' </proc/partitions)
echo ")"
MYFDISK=""
;;
* ) # block devices (no Software RAID)
# print brand/model
MYMODEL="unknown brand"
test -f /sys/block/$MYDEV/device/vendor &&
MYMODEL=$(</sys/block/$MYDEV/device/vendor)
test -f /sys/block/$MYDEV/device/model &&
MYMODEL="$MYMODEL $(</sys/block/$MYDEV/device/model)"
test -f /proc/ide/$MYDEV/model &&
MYMODEL=$(head -1 /proc/ide/$MYDEV/model)
echo -n \ ${MYMODEL}
# print total capacity
echo -n " "; echo "($(getcapacity $MYDEV))"
# save _fdisk -l_ for later use
if [ $UID -ne 0 ] ; then
MYFDISK=`fdisk -l /dev/$MYDEV 2>/dev/null \
| sed -ne "/^\/dev\/$MYDEV/{s/\*/ /;p}"`
else
# if script is run as root do not suppress error messages
MYFDISK=`fdisk -l /dev/$MYDEV \
| sed -ne "/^\/dev\/$MYDEV/{s/\*/ /;p}"`
fi
;;
esac # /$MYDEV/
# get list of partitions
PARTITIONS="$(echo `awk -v pat=$MYDEV[0-9]+ '$4 ~ pat {print $4}' < /proc/partitions`)"
for PARTITION in $PARTITIONS ; do
echo -n "${SYMPART}${PARTITION/$MYDEV}:"
# get type ID of partition
PARTTYPE=`echo "$MYFDISK" \
| awk "/^\/dev\/$PARTITION /"'{ print $5}'`
debugmsg " [PARTTYPE=$PARTTYPE]"
case /$PARTTYPE/ in
// ) if [ $MYDEV = 'md' ] ; then
echo -n " $(</sys/block/$PARTITION/md/level) "
else
echo -n " type unknown `getcapacity $PARTITION` "
fi
isrootfs $PARTITION \
|| { mountedas $PARTITION && gettype $PARTITION ; }
;;
/5/ ) echo -n " extended partition" ;;
/82/ ) echo -n " Linux swap partition"
echo -n ", " ; getcapacity $PARTITION ;;
/83/ ) echo -n " " ; getcapacity $PARTITION ; echo -n " "
isrootfs $PARTITION \
|| { mountedas $PARTITION && gettype $PARTITION ; }
;;
/7/ ) echo -n " type 7 (NTFS?) "
getcapacity $PARTITION ; echo -n " "
mountedas $PARTITION && gettype $PARTITION
;;
/fd/ ) echo -n " " ; getcapacity $PARTITION
echo -n ", partition type fd"
[ "$MDSTAT" ] && isinraid $PARTITION
;;
* ) echo -n " partition type $PARTTYPE" ;;
esac
echo
done # all partitions
# print number of unallocated sectors (if requested)
if [ $SHOWUNALLOCATED = $TRUE -a $MYDEV != 'md' ] ; then
UNALLOCATED=""
UNALLOCATED=$(\
(echo -e "v\nq" | fdisk /dev/$MYDEV) 2>/dev/null \
| sed -ne '/unallocated sectors/s/^.* \([0-9]\+\) unallo.*$/\1/p' )
test "/$UNALLOCATED/" = '//' || echo "($UNALLOCATED unallocated sectors)"
fi
# print separator line/symbol between disk
echo -en "$SYMSEP"
done # all disks
exit 0
# License
#
# This script 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 2 of the License, or
# (at your option) any later version.
#
# This script 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 script; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
# History
#
# 0.02 * 2004-12-23 first buggy "punish me" alpha release
# 0.03 * 2005-01-19 added code to read /sys/block/sd?/device/...
# 0.04 * 2009-09-13 cosmetic changes and testing if it still works
# 0.05 * 2009-09-14 print warning if not /root but go on; added --help;
# 0.05 * 2009-09-14 removed sfdisk requirement; some cosmetics
# 0.06 * 2009-09-15 added -u (unallocated sectors); removed bc requirement
# 0.07 * 2009-09-15 added support for /dev/md (Software RAID)
# 0.08 * 2010-03-07 added support for -L (only list devices)
# 0.09 * 2011-02-20 added ext4 + LUKS, more info about fd partitions (mdstat)
# 0.10 * 2012-08-25 skipping disks with no /sys/block/$MYDEV/size, + cosmetics
# 0.11 * 2015-03-27 added note about lsblk from util-linux
# 0.12 * 2015-09-12 fixed detection of rootfs device
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment