Search
Write a publication
Pull to refresh

Правильное отключение питания SATA дисков в Ubuntu


По роду деятельности мне часто приходится подключать жёсткие диски к своему компьютеру через SATA разъём. После некоторых манипуляций с ними я обычно просто выдёргиваю питание и шлейф из разъёмов. Но каждый раз при этом диск в моих руках немного витает в воздухе. А шпиндель-то в это время ещё не остановился — что может привести к физическим повреждениям диска и потере данных.
И каждый раз я думал что вот-вот сяду и напишу скрипт для отключения питания, а потом уже буду отключать винт физически.
И вот, наконец, у меня появилось достаточно времени чтобы сесть и спокойно этим заняться.

Google честно признался, что проще всего это сделать отправив единичку в «/sys/block/sdx/device/delete». Когда же подключено несколько дисков, неудобно запоминать букву каждого и менять её в строке. А какой диск мне нужно отключить проще опознать по его названию, размеру и разделам на нём. И вот, после нескольких весёлых часов отладки и разных улучшений, у меня получился маленький скрипт:
sataStop.sh
#!/bin/bash

# - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - 
	Name="SATA Stop"
#	Desc: Turns off SATA drives
#	Usage:	sudo sh ./sataStop.sh
#
#	Author:		Samolysov Maxim
#	E-mail:		zBestR@bk.ru
#	License:	Free for all with NO guarantee. Just think & make sure you know what R`You doing
# - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - 
#	HISTORY
	Version="01.00.01";	Date=[21.04.2013]
#	+ basic functionality
# 	+ colors
#	+ once I`ve stopped ROOT disk... (just for sure it works)... So, now here is a check to not let this happens again )))
#
	Version="01.00.02";	Date=[24.04.2013]
#	! fixed bug with last disk skipped (not turned off)
	Version="01.00.03";	Date=[07.05.2013]
#	+ colorized X-letter in sdX
	Version="01.00.04";	Date=[10.05.2013]
#	+ getSize function
#	+ show disk size in GB & GiB
# in future...	Version="01.00.0";	Date=[..2013]
#	+ try to unmount mounted partitions (use with care)
#	HISTORY END
# - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - 
###	GLOBAL VARIABLES
	disks=$(ls /sys/block/ | grep sd)
	count=0
	ROOT_DISK=""
	HAS_MOUNTS=""
	SIZE=""
	# Regular Colors
	      Black='\e[01;30m' # Black
	        Red='\e[00;31m' # Red
	   LightRed='\e[01;31m' # LightRed
	      Green='\e[00;32m' # Green
	 LightGreen='\e[01;32m' # LightGreen
	     Yellow='\e[00;33m' # Yellow
	LightYellow='\e[01;33m' # LightYellow
	       Blue='\e[00;34m' # Blue
	  LightBlue='\e[01;34m' # LightBlue
	     Purple='\e[00;35m' # Purple
	LightPurple='\e[01;35m' # LightPurple
	       Cyan='\e[00;36m' # Cyan
	      White='\e[01;37m' # White
	Color_Off='\e[0m'        # Reset color
	fullName=" $LightYellow$Name$Yellow v.$LightBlue$Version $Yellow$Green$Date$Yellow"
###	GLOBAL VARIABLES END
### - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
#####	FUNCTIONS

checkMounted () {
mountedTo=$(sudo lsblk -ro name,mountpoint $1 | grep $1 | awk '{print $2}')
} 		# checkMounted END


getModel () {
model=$(sudo hdparm -i /dev/$1 | grep -i model| sed -e 's/Model=/\"/' -e 's/,.*$/\"/')
}		# getModel END


getSize () {
SIZE=""
#	local size=$(sudo lsblk -ro size /dev/$disk | awk 'NR == 2 {print ($1)}' | sed 's/,/./')
local device=$1
local bi=$2
local sp=""
local bsize=$(cat /sys/block/$device/size)
bsize=$( expr $bsize '*'  512)
if [[ $bsize -lt 1000 ]]; then
	bsize="$bsize"
	sp="B"
elif [[ $bsize -lt 1000000 ]]; then
	[[ $bi = 1 ]] && bsize="$bsize/1024" sp="KiB" || bsize="$bsize/1000" sp="KB"
#	sp="KB"
elif [[ $bsize -lt 1000000000 ]]; then
	[[ $bi = 1 ]] && bsize="$bsize/1048576" sp="MiB" || bsize="$bsize/1000000" sp="MB"
#	bsize="$bsize/1048576"
#	sp="MB"
else
	[[ $bi = 1 ]] && bsize="$bsize/1073741824" sp="GiB" || bsize="$bsize/1000000000" sp="GB"
#	bsize="$bsize/1073741824"
#	sp="GB"
fi
bsize=$(echo "scale=0; $bsize" | bc -l)
[[ $bsize -lt 10 ]]   && bsize=" $bsize"
[[ $bsize -lt 100 ]]  && bsize=" $bsize"
[[ $bsize -lt 1000 ]] && bsize=" $bsize"

SIZE="$bsize $sp"
} 		# getSize END


main () {
echo -e "$fullName"
# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
for disk in $disks; do
	let count++
	echo -ne "$Red"
	local model=$(sudo hdparm -i /dev/$disk | grep -i model| sed -e 's/Model=/\"/' -e 's/,.*$/\"/')
	getSize "$disk" 0
	local size="$SIZE"
	getSize "$disk" 1
	local size="$size ($SIZE)"
	disk_1="sd"
	disk_2=$(echo $disk | sed 's/..//')
	echo -e "$LightYellow$count. $LightPurple$disk_1$LightYellow$disk_2\t\e[07;32m$size\e[0m\t$LightGreen$model$ColorOff"
	local parts=$(sudo lsblk -ro name,type | grep $disk | awk '/part/ {print ($1)}' )
	for part in $parts; do
		local mountedTo=$(sudo lsblk -ro name,mountpoint /dev/$part | grep $part | awk '{print $2}')
		local fileSystem=$(sudo lsblk -ro name,fstype /dev/$part | grep $part | awk '{print $2}')
		getSize "$disk/$part" 1
		fileSystem="\t$fileSystem\t $SIZE"
		if [[ $mountedTo == "" ]]; then
			mountedTo="$Green\tnot mounted $ColorOff"
		elif [[ $mountedTo == "/" ]]; then
			# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
			ROOT_DISK=$count
			mountedTo="$Red\t$mountedTo$Yellow\t<--- this is$Red ROOT$ColorOff"
		elif [[ $mountedTo == "[SWAP]" ]]; then
			mountedTo="$Red\t$mountedTo$ColorOff"
		else
			HAS_MOUNTS="$HAS_MOUNTS $disk"
			mountedTo="$LightBlue\t$mountedTo$ColorOff"
		fi
		echo -e "   $Yellow$part$fileSystem$mountedTo$ColorOff"
	done
done # disk in $disks
echo -ne "$LightPurple\rEnter disk number [$LightYellow 1-$count $LightPurple] to turn off ($LightYellow \"Enter\" to exit $LightPurple):$ColorOff $LightYellow"
read answer
# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
if [[ $answer == $ROOT_DISK ]]; then
	echo -e "$Red Do You$LightRed REALLY$Red believe I\`ll stop disk with $LightRed\"ROOT\"$Yellow ??? $LightGreen Sorry, Bro$Yellow...\n $LightBlue I\`m a clever script $Yellow)))$LightPurple But You can still trying$Yellow..."
sleep 15
else
	if [[ $count+1 > $answer &&  $answer > 0 ]]; then
		stop_disk=$(echo ${disks} | awk '{print $'$answer'}')
		local disk_mounted="no"
		d_isk_number=$(echo ${HAS_MOUNTS} | grep -q "${stop_disk}") && disk_mounted="yes"
		if [[ $disk_mounted == "yes" ]]; then
			echo -e "$LightPurple$stop_disk$LightBlue has mounted partitions.$Yellow Unmount them and try again."
sleep 15
		else
			local model=$(sudo hdparm -i /dev/$stop_disk | grep -i model| sed -e 's/Model=/\"/' -e 's/,.*$/\"/')
			echo -ne "Turning off $LightPurple$stop_disk $LightGreen$model...   "
			sudo sh -c "echo 1 > /sys/block/$stop_disk/device/delete"
sleep 2
			# !!! Do NOT even FUCKING try to TURN OFF the ROOT disk !!! COMPUTER WILL FRIZE AND POSSIBLY LOST DATA !!!
			ls /sys/block | grep -q "${stop_disk}" || echo -e "$LightYellow Successfully stopped."
sleep 15
		fi
	fi
fi # $answer == $ROOT_DISK
echo -e "$LightYellow Exit."
sleep 3
} 		# main END

#####	FUNCTIONS END
### - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - - = = = = = = = - - - - - - - - - - - - - -
#####	START SCRIPT

clear
main
echo -ne "$ColorOff"
#####	START SCRIPT END

с удобным выводом:
image

Теперь можно смело выдёргивать шлейф из диска ведь шпинделю хватает времени остановиться (1-3 секунды) пока мои руки дотронутся до самого диска.

P.S. Если мой скрипт спасёт хоть несколько дисков и убережёт чьи-то данные от потери, я считаю задачу выполненной.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.