ssd_status.sh


SUBMITTED BY: Guest

DATE: Dec. 5, 2013, 7:16 a.m.

FORMAT: Bash

SIZE: 9.3 kB

HITS: 668

  1. #!/bin/bash
  2. ######################################################
  3. ##### #####
  4. ##### Configuration section #####
  5. ##### #####
  6. ######################################################
  7. ## Path to smartctl binary of smartmontools (version has to be >= 5.39)
  8. ## If unset systemwide smartctl is used if found.
  9. SMARTCTL="./smartctl"
  10. ## Path to logfile. Leave empty or comment out to disable logging.
  11. LOGFILE="./ssdlog.csv"
  12. ## Unit used for logging of read/written data.
  13. ## Possible values: B, KB, MB, GB, KiB, MiB, GiB, b, Kb, Mb, Gb, Kib, Mib, Gib
  14. ## Small "b" refers to bit, capital "B" to Byte.
  15. ## Units with an "i" are binary based (1 KiB = 1024 Byte)
  16. ## whereas units without are decimal based (1 KB = 1000 Byte)
  17. LOG_SIZE_UNIT="MiB"
  18. ## Number of decimals used for logging of read/written data.
  19. LOG_SIZE_DEZIMALS=0
  20. ######################################################
  21. ##### #####
  22. ##### END OF #####
  23. ##### Configuration section #####
  24. ##### #####
  25. ######################################################
  26. check_root() {
  27. if [[ $EUID -ne 0 ]]; then
  28. echo "This script must be run as root" 1>&2
  29. exit 1
  30. fi
  31. }
  32. check_device() {
  33. if [[ -z "$1" ]]
  34. then
  35. DEVICE="/dev/sda"
  36. else
  37. DEVICE="$1"
  38. fi
  39. if [ ! -b "${DEVICE}" ]
  40. then
  41. if [ ! -b "/dev/${DEVICE}" ]
  42. then
  43. echo "No device given or given device not a block device."
  44. echo "Call this script with the devicename of the SSD."
  45. echo "E.g.: ./ssd.sh /dev/sda"
  46. exit 1
  47. else
  48. DEVICE="/dev/${DEVICE}"
  49. fi
  50. fi
  51. }
  52. change_path() {
  53. OLDDIR=`pwd`
  54. abspath="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"
  55. path_only=`dirname "$abspath"`
  56. cd ${path_only}
  57. }
  58. check_smartctl() {
  59. if [[ ! -e "${SMARTCTL}" ]]
  60. then
  61. SMARTCTL=`which smartctl`
  62. if [[ "$?" == "1" ]]
  63. then
  64. echo "Path to smartctl not set and smartctl not found in PATH."
  65. echo "ssd_status.sh requires smartctl from smartmontools to run."
  66. exit 1
  67. fi
  68. fi
  69. SMARTCTL_VERSION=`${SMARTCTL} --version | grep "smartctl [0-9]\.[0-9][0-9]" | cut -d\ -f2`
  70. NEWER_539=`echo "${SMARTCTL_VERSION} >= 5.39" | bc -l`
  71. if [[ "${NEWER_539}" == 0 ]]
  72. then
  73. echo "smartctl binary is older than 5.39 (${SMARTCTL} is ${SMARTCTL_VERSION})."
  74. echo "ssd_status.sh requires smartctl to be at least version 5.39 to run."
  75. exit 1
  76. fi
  77. }
  78. get_timedate() {
  79. DATE=`date "+%Y-%m-%d"`
  80. TIME=`date "+%H:%M"`
  81. }
  82. gather_smartinfo() {
  83. SMARTINFO=`${SMARTCTL} ${DEVICE} -i | grep ": " | sed -r 's/ +/*/g'`
  84. for LINE in ${SMARTINFO}
  85. do
  86. if [[ -n `echo ${LINE} | grep -i "device\*model"` ]]
  87. then
  88. MODEL=`echo ${LINE} | cut -d* -f3`
  89. fi
  90. if [[ -n `echo ${LINE} | grep -i "serial\*number"` ]]
  91. then
  92. SERIAL=`echo ${LINE} | cut -d* -f3`
  93. fi
  94. if [[ -n `echo ${LINE} | grep -i "firmware\*version"` ]]
  95. then
  96. FIRMWARE=`echo ${LINE} | cut -d* -f3`
  97. fi
  98. if [[ -n `echo ${LINE} | grep -i "user\*capacity"` ]]
  99. then
  100. SIZE=`echo ${LINE} | cut -d* -f3 | sed 's/\.//g' | sed 's/,//g'`
  101. fi
  102. done
  103. SERIAL_PUBLIC=`echo ${SERIAL} | sed -r "s/.{5}$/*****/"`
  104. }
  105. gather_smartvalues() {
  106. SMARTVALUES=`${SMARTCTL} ${DEVICE} -A -v N,raw64 | grep 0x0000 | sed 's/0x0000.*-//' | sed -r 's/^ +//' | sed -r 's/ +/*/g'`
  107. for LINE in ${SMARTVALUES}
  108. do
  109. ID=`echo ${LINE} | cut -d* -f1`
  110. VALUE=`echo ${LINE} | cut -d* -f3`
  111. if [ "${ID}" = "1" ]; then
  112. RAW_READ_ERROR_RATE=${VALUE}
  113. fi
  114. if [ "${ID}" = "9" ]; then
  115. POWER_ON_HOURS=${VALUE}
  116. fi
  117. if [ "${ID}" = "12" ]; then
  118. POWER_CYCLE_COUNT=${VALUE}
  119. fi
  120. if [ "${ID}" = "184" ]; then
  121. INITIAL_BAD_BLOCK_COUNT=${VALUE}
  122. fi
  123. if [ "${ID}" = "195" ]; then
  124. PROGRAM_FAILURE_BLK_CT=${VALUE}
  125. fi
  126. if [ "${ID}" = "196" ]; then
  127. ERASE_FAILURE_BLK_CT=${VALUE}
  128. fi
  129. if [ "${ID}" = "197" ]; then
  130. READ_FAILURE_BLK_CT=${VALUE}
  131. fi
  132. if [ "${ID}" = "198" ]; then
  133. READ_SECTORS_TOT_CT=${VALUE}
  134. fi
  135. if [ "${ID}" = "199" ]; then
  136. WRITE_SECTORS_TOT_CT=${VALUE}
  137. fi
  138. if [ "${ID}" = "200" ]; then
  139. READ_COMMANDS_TOT_CT=${VALUE}
  140. fi
  141. if [ "${ID}" = "201" ]; then
  142. WRITE_COMMANDS_TOT_CT=${VALUE}
  143. fi
  144. if [ "${ID}" = "202" ]; then
  145. ERROR_BITS_FLASH_TOT_CT=${VALUE}
  146. fi
  147. if [ "${ID}" = "203" ]; then
  148. CORR_READ_ERRORS_TOT_CT=${VALUE}
  149. fi
  150. if [ "${ID}" = "204" ]; then
  151. BAD_BLOCK_FULL_FLAG=${VALUE}
  152. fi
  153. if [ "${ID}" = "205" ]; then
  154. MAX_PE_COUNT_SPEC=${VALUE}
  155. fi
  156. if [ "${ID}" = "206" ]; then
  157. MIN_ERASE_COUNT=${VALUE}
  158. fi
  159. if [ "${ID}" = "207" ]; then
  160. MAX_ERASE_COUNT=${VALUE}
  161. fi
  162. if [ "${ID}" = "208" ]; then
  163. AVERAGE_ERASE_COUNT=${VALUE}
  164. fi
  165. if [ "${ID}" = "209" ]; then
  166. REMAINING_LIFE_TIME=${VALUE}
  167. fi
  168. done
  169. SIZE_B=${SIZE}
  170. SIZE_GiB=`echo "scale=3; ${SIZE_B}/1024/1024/1024" | bc -l`
  171. READ_B=`echo "scale=0; ${READ_SECTORS_TOT_CT}*512" | bc -l`
  172. WRITTEN_B=`echo "scale=0; ${WRITE_SECTORS_TOT_CT}*512" | bc -l`
  173. READ_GiB=`echo "scale=3; ${READ_B}/1024/1024/1024" | bc -l`
  174. WRITTEN_GiB=`echo "scale=3; ${WRITTEN_B}/1024/1024/1024" | bc -l`
  175. }
  176. gather_triminfo() {
  177. TRIMINFO=`hdparm -I ${DEVICE} | grep TRIM`
  178. if [[ -n "${TRIMINFO}" ]]
  179. then
  180. TRIM="Yes"
  181. else
  182. TRIM="No"
  183. fi
  184. }
  185. console_print() {
  186. echo "Model: ${MODEL}"
  187. echo "Serialnumber: ${SERIAL_PUBLIC}"
  188. echo "Firmware / TRIM: ${FIRMWARE} / ${TRIM}"
  189. echo "Size: ${SIZE_GiB} GiB"
  190. echo "Status: ${REMAINING_LIFE_TIME}%"
  191. echo "Power on time: ${POWER_ON_HOURS} hours"
  192. echo "Power cycles: ${POWER_CYCLE_COUNT}"
  193. echo "Cell wear level: ${AVERAGE_ERASE_COUNT} (${MIN_ERASE_COUNT} / ${MAX_ERASE_COUNT}) [avg (min / max)]"
  194. echo "Read: ${READ_GiB} GiB"
  195. echo "Written: ${WRITTEN_GiB} GiB"
  196. }
  197. file_writeheader() {
  198. # echo "SSD status logfile" > ${LOGFILE}
  199. # echo "Generic information:;Model;Serial;Firmware;TRIM;Size" >> ${LOGFILE}
  200. # echo ";${MODEL};${SERIAL_PUBLIC};${FIRMWARE};${TRIM};${SIZE_B}" >> ${LOGFILE}
  201. # echo "" >> ${LOGFILE}
  202. # echo "Log information:" >> ${LOGFILE}
  203. echo "Date;Time;Read;Write;Erase cnt;;;Remaining;Power on;Power;Raw read;Program failure;Erase failure;Read failure;Sectors;;Read;Write;Error bits;Corrected" >> ${LOGFILE}
  204. echo ";;(${LOG_SIZE_UNIT});(${LOG_SIZE_UNIT});Avg;Min;Max;life time;time (hours);cycle cnt;error rate;block count;block count;block count;read;written;commands;commands;flash;read errors" >> ${LOGFILE}
  205. }
  206. file_calculatedatasize() {
  207. case "${LOG_SIZE_UNIT}" in
  208. "B" )
  209. LOG_SIZE_CALC="";;
  210. "KiB" )
  211. LOG_SIZE_CALC="/1024";;
  212. "MiB" )
  213. LOG_SIZE_CALC="/1024/1024";;
  214. "GiB" )
  215. LOG_SIZE_CALC="/1024/1024/1024";;
  216. "KB" )
  217. LOG_SIZE_CALC="/1000";;
  218. "MB" )
  219. LOG_SIZE_CALC="/1000/1000";;
  220. "GB" )
  221. LOG_SIZE_CALC="/1000/1000/1000";;
  222. "b" )
  223. LOG_SIZE_CALC="*8";;
  224. "Kib" )
  225. LOG_SIZE_CALC="*8/1024";;
  226. "Mib" )
  227. LOG_SIZE_CALC="*8/1024/1024";;
  228. "Gib" )
  229. LOG_SIZE_CALC="*8/1024/1024/1024";;
  230. "Kb" )
  231. LOG_SIZE_CALC="*8/1000";;
  232. "Mb" )
  233. LOG_SIZE_CALC="*8/1000/1000";;
  234. "Gb" )
  235. LOG_SIZE_CALC="*8/1000/1000/1000";;
  236. esac
  237. READ=`echo "scale=${LOG_SIZE_DEZIMALS}; ${READ_B}${LOG_SIZE_CALC}" | bc -l`
  238. WRITTEN=`echo "scale=${LOG_SIZE_DEZIMALS}; ${WRITTEN_B}${LOG_SIZE_CALC}" | bc -l`
  239. }
  240. file_writelogentry() {
  241. echo "${DATE};${TIME};${READ};${WRITTEN};${AVERAGE_ERASE_COUNT};${MIN_ERASE_COUNT};${MAX_ERASE_COUNT};${REMAINING_LIFE_TIME};${POWER_ON_HOURS};${POWER_CYCLE_COUNT};${RAW_READ_ERROR_RATE};${PROGRAM_FAILURE_BLK_CT};${ERASE_FAILURE_BLK_CT};${READ_FAILURE_BLK_CT};${READ_SECTORS_TOT_CT};${WRITE_SECTORS_TOT_CT};${READ_COMMANDS_TOT_CT};${WRITE_COMMANDS_TOT_CT};${ERROR_BITS_FLASH_TOT_CT};${CORR_READ_ERRORS_TOT_CT}" >> ${LOGFILE}
  242. }
  243. file_log() {
  244. if [[ ! -e "${LOGFILE}" ]]
  245. then
  246. file_writeheader
  247. fi
  248. file_writelogentry
  249. }
  250. check_root
  251. check_device
  252. change_path
  253. check_smartctl
  254. get_timedate
  255. gather_smartinfo
  256. gather_smartvalues
  257. gather_triminfo
  258. file_calculatedatasize
  259. console_print
  260. if [[ -n "${LOGFILE}" ]]
  261. then
  262. file_log
  263. fi
  264. cd ${OLDDIR}

comments powered by Disqus