Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- #
- # DESCRIPTION
- #
- # k-smart.app is a simple Application Wrapper around this small bash script, the
- # smartctl binary and a very small binary called keys used to check whether modifier
- # keys are pressed or released.
- #
- # It's main purpose is to display the smartctl output for each disk 'diskutil' lists.
- # When [[shift]] is pressed a short self-test will be executed. When [[option]] is
- # pressed then a long test will be performed.
- #
- # The only purpose of this tool is an easy way to get an actual snapshot of SMART data
- # related to your disks since many GUI tools that focus on SMART on OS X fail in some ways.
- # Also important is the ability to save/copy smartctl's output so you can provide admins
- # or experienced users with the actual SMART data and not that what your SMART GUI thinks.
- # If you want to provide this information to others think about using a platform like
- # http://pastebin.com since it's essential to get the informations smartctl provides in
- # 'raw' format (without lines being wrapped around and the like).
- #
- # MORE INFO
- #
- # Since k-smart is based solely on smartmontools you find all the relevant informations
- # here: http://sourceforge.net/apps/trac/smartmontools/wiki
- #
- # The source of the included 'keys' binary can be found here:
- # http://brettterpstra.com/2012/08/05/quick-tip-checking-for-modifier-keys-in-shell-scripts/
- #
- # The Application Wrapper is made using Platypus 4.8: http://sveinbjorn.org/platypus
- #
- # Have a look at http://sourceforge.net/apps/trac/smartmontools/ticket/25#comment:9 to
- # understand what you might need to do to get your external drives working correctly
- # with smartctl (applies to most other SMART utilities on OS X as well!)
- #
- # CHANGES
- #
- # 1.5: - added "-q noserial" to "smartctl -a" invocation to hide serial numbers from drives
- # in output
- # - get model name from smartctl's 'Device Model' entry when displaying warnings
- #
- # 1.4: - always use a temporary file to store smartctl's output because we use the
- # results multiple times
- # - grep smartctl's output for "WARNING" and display these warnings using 'System
- # Events'. In case the output contains also the string 'http' provide a 'More Info'
- # button which will try to open each URL in Safari if pressed
- # - disable GetSmartCtl function and solely rely on the smartctl binary provided
- # inside the Application Bundle
- #
- # 1.3: - fixed quoting bug which prevented execution of the keys binary if the path to
- # k-smart.app contained whitespace ('keys' is necessary to check whether the user
- # pressed modifier keys)
- #
- # 1.2: - replaced smartctl with an Universal Binary which also runs on 32 bit Macs
- #
- # 1.1: - Added GetListOfVolumes function which skips CoreStorage devices since they
- # appear as normal disks and passthrough SMART which might confuse users
- # - Added CreateShellAlias function to define an alias in the user's .profile
- # which points to the current location of smartctl. From then on a simple
- # invocation of smartctl in Terminal should be possible regardless of k-smart.app's
- # location
- #
- # 1.0: - first version. Simply walks through 'diskutil list' output and calls 'smartctl -a'
- # for every device found
- # - included smartctl 6.1 in the Application Bundle
- # - replaced smartctl 6.1 with a freshly compiled 6.2 (64 bit only)
- # - added 'keys' binary to Application Bundle. When [[shift]]Β is pressed k-smart
- # will execute a short self-test for each and every device. If [[option]] is
- # pressed as well, a long self-test will be executed.
- #
- # TODO
- #
- # - Documentation! Internationalization! Localization!
- # - maybe rely on an older version of Platypus (4.4) to be PPC compatible?
- # - maybe set up an automated build system for smartmontools to always include the most
- # recent smartctl version as Universal Binary?
- # - maybe add some Automator Actions utilizing the GetSmartCtl function to get the path
- # to smartctl to simply automate SMART checks and result verification in a highly
- # flexible fashion?
- # - maybe include smartd correctly (including a routine that installs smartd including
- # a LaunchDaemon using administrator privileges on servers)
- # - maybe include an user agent in ~/Library/LaunchAgents to periodically check drive
- # health via smartctl on 'client' systems?
- # - maybe include the most recent version of the SATSMART kext, check the version on
- # each launch, display an informative message in case a mismatch occured and call
- # installer to let the user install/update the SATSMART driver?
- Main() {
- export PATH=/bin:/usr/bin:/opt/local/bin:/usr/local/bin
- MyTmpFile="$(mktemp /tmp/${0##*/}.XXXXXX || (echo -e "Not able to create temporary file below /tmp/. Exiting." | logger ; exit 1))"
- trap "rm -f \"${MyTmpFile}\"; exit 0" 0 1 2 3 15
- # PathToSmartCtl="$(GetSmartCtl)"
- PathToSmartCtl="${0%/*}"/smartctl
- PathToKeys="${0%/*}"/keys
- CreateShellAlias
- sleep 1
- IsShiftPressed=$("${PathToKeys}" shift)
- IsOptionPressed=$("${PathToKeys}" option)
- case ${IsShiftPressed} in
- 1)
- # shift is pressed, we are in test mode!
- # if option is pressed as well we're
- # performing a long test otherwise short
- if [ "X${IsOptionPressed}" = "X1" ]; then
- TestMode=long
- else
- TestMode=short
- fi
- GetListOfVolumes | while read ; do
- # check whether device is SMART capable
- "${PathToSmartCtl}" -a ${REPLY} >/dev/null 2>&1
- if [ $? -eq 0 ]; then
- echo -e "${AbstandSchraddel}Previous test results for ${REPLY}:\n"
- "${PathToSmartCtl}" -l selftest ${REPLY}
- echo -e "\nNow performing a ${TestMode} test on ${REPLY} in the background. You can close this window and try again in several minutes. Please see below the smartctl output.\n"
- "${PathToSmartCtl}" -t ${TestMode} ${REPLY}
- AbstandSchraddel="\n\n\n"
- fi
- done
- ;;
- *)
- # we simply display SMART status for all devices
- GetListOfVolumes | while read ; do
- echo -e "${AbstandSchraddel}Examining ${REPLY}\n"
- "${PathToSmartCtl}" -q noserial -a ${REPLY} | tee "${MyTmpFile}"
- # check for warning messages in smartctl output
- ButtonPressed=""
- grep -q "WARNING" "${MyTmpFile}" && ButtonPressed="$(DisplayWarning "${REPLY}" "${MyTmpFile}")"
- if [ "X${ButtonPressed}" = "XMore Info" ]; then
- grep "^http" "${MyTmpFile}" | while read ; do
- open -b com.apple.Safari "${REPLY}"
- done
- fi
- AbstandSchraddel="\n\n\n"
- done
- ;;
- esac
- } # Main
- CreateShellAlias() {
- if [ -f "${HOME}/.profile" ]; then
- grep -v "^alias smartctl" <"${HOME}/.profile" >"${MyTmpFile}"
- echo -e "alias smartctl=\"${PathToSmartCtl}\"" >>"${MyTmpFile}"
- cat "${MyTmpFile}" >"${HOME}/.profile"
- else
- echo -e "alias smartctl=\"${PathToSmartCtl}\"" >>"${HOME}/.profile"
- fi
- } # CreateShellAlias
- GetListOfVolumes() {
- /usr/sbin/diskutil list | grep "^/dev/" | while read ; do
- /usr/sbin/diskutil corestorage info ${REPLY} >/dev/null 2>&1 || echo ${REPLY}
- done
- } # GetListOfVolumes
- GetSmartCtl() {
- mdfind "kMDItemCFBundleIdentifier == 'de.kaiser-edv.k-smart'" | grep "\.app$" | while read ; do
- SmartCtlVersion=$("${REPLY}"/Contents/Resources/smartctl | awk -F" " '/^smartctl / {print $2}')
- echo -e "${SmartCtlVersion}\t${REPLY}/Contents/Resources/smartctl"
- done | sort -r | head -n1 | cut -f2
- } # GetSmartCtl
- DisplayWarning() {
- # $1 is the device in question
- # $2 is the path to the redirected "smartctl -a" output
- DeviceShortName="$(echo "$1" | sed 's|^/dev/||')"
- # DeviceName="$(/usr/sbin/diskutil info $1 | awk -F":" '/Media Name:/ {print $2}' | sed -e 's/^ *//g' -e 's/\ Media$//' -e 's/TOSHIBA\ TOSHIBA/TOSHIBA/')"
- DeviceName="$(awk -F":" '/^Device Model/ {print $2}' <"$2" | sed 's/^ *//g')"
- DisplayString=$(grep "WARNING" "$2" | sed -e 's/\"/\\\"/g' -e 's/^==\>\ //')
- grep "^http" "$2" >/dev/null 2>&1
- if [ $? -eq 0 ]; then
- Buttons='{"More Info", "OK"}'
- else
- Buttons='{"OK"}'
- fi
- osascript <<-EOF
- tell application "System Events"
- activate
- set ButtonPressed to (button returned of (display dialog "${DeviceName} (${DeviceShortName})" & return & "${DisplayString}" buttons ${Buttons} default button 1 with icon caution giving up after 30))
- end tell
- EOF
- } # DisplayWarning
- Main "$@"
Advertisement
Add Comment
Please, Sign In to add comment