#!/bin/bash ## zramraid-config ## (c) author's idea and realization: Kleemov A. & Koshuba V. ## script author: Koshuba V - stvixfree@gmail.com ## all parameters ##settime=$(date +%s%3N); option=$1; params=$2; export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/etc/zramraid"; version="25.06.18"; ## msg [53] set_msg=( '"0" "0"' '"1" "0"' '"2" "0"' '"3" "0"' '"4" "0"' '"5" "0"' '"6" "1"' '"7" "1"' '"8" "1"' '"9" "1"' '"10" "1"' '"11" "1"' '"12" "1"' '"13" "1"' '"14" "1"' '"15" "1"' '"16" "0"' '"17" "0"' '"18" "0"' '"19" "0"' '"20" "1"' '"21" "1"' '"22" "1"' '"23" "1"' '"24" "1"' '"25" "1"' '"26" "1"' '"27" "1"' '"28" "1"' '"29" "1"' '"30" "1"' '"31" "1"' '"32" "1"' '"33" "1"' '"34" "1"' '"35" "1"' '"36" "1"' '"37" "1"' '"38" "1"' '"39" "1"' '"40" "1"' '"41" "1"' '"42" "1"' '"43" "1"' '"44" "1"' '"45" "1"' '"46" "1"' '"47" "1"' '"48" "1"' '"49" "0"' '"50" "0"' '"51" "0"' '"52" "0"' '"53" "0"' ); msg=(); ### lang=$(locale|grep LANG=|sed 's/\LANG=//g'); rdate=$(date +%c); ## total_mem=$(cat /proc/meminfo |awk '/^MemTotal:/{print $2}'); free_mem=$(cat /proc/meminfo |awk '/^MemAvailable:/{print $2}'); limit_mem=0; info_limit_mem=0; total_size_images=0; zpath="/etc/zramraid"; zconfig="zramraid.conf"; zmsg="/etc/zramraid/messages.dat"; log="/var/log/zramraid.log"; reports=(); id_zmd=(); image_zmd=(); size_zmd=(); json_key=( "id" "info" "image" ); zdm_vars=( "id_zmd" "info_zmd" "image_zmd" ); input_unit=(); math_unit=0; set_params=(); set_id=""; set_image=""; set_opt=( "0" "0" "0" "0" ); set_size_limit=0; set_type_limit=""; ## zr_blkid=$(whereis -b blkid|awk '/^blkid:/{print $2}'); zr_jq=$(whereis -b jq|awk '/^jq:/{print $2}'); ## functions & operations operation_createdef=( "checkDep" "loadMsg" "testId" "confEmpty" ); operation_add=( "checkDep" "loadMsg" "testId" "inPut" "readConf" "testMd" "testImage" "addMd" ); operation_del=( "checkDep" "loadMsg" "testId" "inPut" "readConf" "delMd" ); operation_list=( "clear" "checkDep" "loadMsg" "testId" "readConf" "reportConf" "printInfo" ); operation_help=( "clear" "checkDep" "loadMsg" "printInfo" ); operation_mdinfo=( "clear" "checkDep" "loadMsg" "testId" "inPut" "readConf" "addInfoMd" ); operation_mem=( "checkDep" "loadMsg" "testId" "inPut" "readConf" "setLimitMem" ); execute_func=(); ## logic executor values iFs=(); logic=(); value_in=""; lEnd=1; ##--@F math functions ## Byte <> Kb function Byte(){ if [ ! ${input_unit[2]} ] then eval ${input_unit[1]}=$(echo "scale=0; ${input_unit[0]}/1024"|bc -lq); else eval ${input_unit[1]}=$(echo ${input_unit[0]}*1024|bc -lq); fi } ## Kb <> Byte function Kb() { if [ ! ${input_unit[2]} ] then eval ${input_unit[1]}=$(echo ${input_unit[0]}*1024|bc -lq); else eval ${input_unit[1]}=$(echo "scale=0; ${input_unit[0]}/1024"|bc -lq); fi } ## Mb <> Byte function Mb() { if [ ! ${input_unit[2]} ] then eval ${input_unit[1]}=$(echo ${input_unit[0]}*1024^2|bc -lq); else eval ${input_unit[1]}=$(echo "scale=0; ${input_unit[0]}/1024^2"|bc -lq); fi } ## Gb <> Byte function Gb() { if [ ! ${input_unit[2]} ] then eval ${input_unit[1]}=$(echo ${input_unit[0]}*1024^3|bc -lq); else eval ${input_unit[1]}=$(echo "scale=0; ${input_unit[0]}/1024^3"|bc -lq); fi } ## Tb <> Byte function Tb() { if [ ! ${input_unit[2]} ] then eval ${input_unit[1]}=$(echo ${input_unit[0]}*1024^4|bc -lq); else eval ${input_unit[1]}=$(echo "scale=0; ${input_unit[0]}/1024^4"|bc -lq); fi } ## -@F logic executor function eXlogic() { lEnd=1; if [[ ${#iFs[@]} -eq 0 ]]||[[ ${#iFs[@]} != ${#logic[@]} ]] then echo "exit"; exit 0; fi local exfunc=(); for ((lg_index=0; lg_index != ${#iFs[@]}; lg_index++)) do ## !! debug operation... #echo "eXlogic = execution: function ${iFs[$lg_index]} : index=$lg_index"; local lg=$(echo $((${iFs[$lg_index]})) ); local exfunc=( ${logic[$lg_index]} ); local runfunc=$(echo ${exfunc[$lg]}| sed 's/\"//g'); $runfunc; if [[ $lEnd == 0 ]] then lg_index=$((${#iFs[@]}-1)); fi done iFs=(); logic=(); value_in=""; } ##--@F write log events function writeToLog() { for ((rpt_index=0; rpt_index != ${#reports[@]}; rpt_index++)) do echo "$rdate zramraid message: ${reports[$rpt_index]}">>$log; done } ##--@F make all errors function makeErr() { reports[${#reports[@]}]=${msg[42]}; printInfo; writeToLog; exit 0; } function printInfo() { value_in="$option"; iFs=( "$(echo -n $value_in|wc -m) == 0" "$(echo -n $value_in|sed 's/--help//g'|wc -m) == 0" "$(echo -n $value_in|sed 's/--list//g'|wc -m) == 0" "$(echo -n ${#reports[@]}) == 0" ); logic=( '"" "pInone"' '"" "pIhelp"' '"" "pIlist"' '"pIdf" "pInone"' ); function pInone() { lEnd=0; clear; echo; echo -e ${msg[34]}"\n"${msg[35]}"\n"${msg[36]}"\n"${msg[37]}"\n"${msg[38]}"\n"${msg[39]}; echo -e ${msg[40]}"\n"${msg[41]}"\n"${msg[48]} $version; exit 0; } function pIhelp() { lEnd=0; clear; echo; echo -e ${msg[35]}"\n"${msg[36]}"\n"${msg[37]}"\n"${msg[38]}"\n"${msg[39]}; echo -e ${msg[40]}"\n"${msg[41]}"\n"${msg[48]} $version; exit 0; } function pIlist() { lEnd=0; info_free_mem=0; info_total_mem=0; input_unit=( "$free_mem" "info_free_mem" "1" ); Kb; input_unit=( "$total_mem" "info_total_mem" "1" ); Kb; echo "==============================================================..."; echo "${msg[32]} $info_total_mem""Mb ${msg[33]} $info_free_mem""Mb"; echo "==============================================================..."; for ((rpt_index=0; rpt_index != ${#reports[@]}; rpt_index++)) do echo "${reports[$rpt_index]}"; done echo "--------------------------------------------------------------..."; exit 0; } ## default function last eXlogic.. function pIdf() { for ((rpt_index=0; rpt_index != ${#reports[@]}; rpt_index++)) do echo "${reports[$rpt_index]}"; done exit 0; } eXlogic; } ##--@F Check the program dependency function checkDep() { # This installation check jq if [ $(echo $zr_jq|grep jq|wc -m) = 0 ] then ## lang messages if yes then lang else us... reports=(); reports[${#reports[@]}]=${msg[6]}; makeErr; fi } ##--@F read locale messages function loadMsg() { # test enable file messages if [ ! -f $zmsg ] then reports=(); reports[${#reports[@]}]="$zmsg - file not found!"; makeErr; fi # read msg if [[ ! $(cat $zmsg|grep "$lang"|wc -m) == 0 ]] then index_msg="$(cat $zmsg | jq '."'$lang'".msg[]'|wc -l)"; if [[ ! "$index_msg" == "0" ]]||[[ "$index_msg" == "${#set_msg[@]}" ]] then for (( m_index=0; m_index != $index_msg; m_index++)) do eval st_in_msg="(" ${set_msg[$m_index]} ")"; if [ "${st_in_msg[1]}" != "0" ] then read_msg=$(cat $zmsg | jq '."'$lang'".msg['$m_index']'| sed 's/\"//g'); msg[$m_index]="$read_msg"; else msg[$m_index]=""; fi done else reports=(); reports[${#reports[@]}]="$zmsg - Incorrect file format or empty!"; makeErr; fi fi } ##--@F step operation function readConf() { # test enable file zramraid.conf if [ ! -f $zpath/$zconfig ] then reports=(); reports[${#reports[@]}]=${msg[7]}; makeErr; fi # read config for (( rd_index=0; rd_index !=${#zdm_vars[@]}; rd_index++)) do read_key=$(cat $zpath/$zconfig | jq '.md[].'${json_key[$rd_index]}| sed 's/\"//g'); eval ${zdm_vars[$rd_index]}="(" $read_key ")"; done log=$(cat $zpath/$zconfig | jq '.log'| sed 's/\"//g'); ## test free memory value_mem=$(cat $zpath/$zconfig | jq '.limit_free_mem.value_size'| sed 's/\"//g'); value_in="$value_mem"; iFs=( "$(echo -n $value_in|wc -m) == 0" "$(echo -n $value_in|sed 's/%//g'|wc -m) == 0" "$(echo -n $value_in|sed 's/Kb//g'|wc -m) == 0" ); logic=( '"" "lmem_Err"' '"" "lmem_Per"' '"lmem_Err" "lmem_Kb"' ); lmem_Err() { reports=(); reports[${#reports[@]}]="${msg[29]} $value_mem /or null - ${msg[10]}(${msg[30]}:Kb,%)"; makeErr; } lmem_Per() { lEnd=0; test_read_mem=0; input_unit=( "$free_mem" "test_read_mem" ); Kb; math_unit=$(echo "scale=2; $(echo "scale=2; $test_read_mem/100"|bc -lq)*$(cat $zpath/$zconfig | jq '.limit_free_mem.size'| sed 's/\"//g')"|bc -lq|sed 's/\./ /g'|awk '{print$1}'); ## -" if (( "$math_unit" < 0 ))||[[ "$math_unit" == "" ]]||[[ ! "$math_unit" =~ ^([0-9]+)$ ]] then reports=(); reports[${#reports[@]}]="${msg[29]} $value_mem /or null - ${msg[10]}(${msg[30]}:Kb,%)"; makeErr; else limit_mem=$math_unit; input_unit=( "$math_unit" "info_limit_mem" ); Byte; math_unit=$info_limit_mem; input_unit=( "$math_unit" "info_limit_mem" "1" ); Kb; fi } lmem_Kb() { lEnd=0; input_unit=( "$(cat $zpath/$zconfig | jq '.limit_free_mem.size'| sed 's/\"//g')" "math_unit" ); Kb; limit_mem=$math_unit; input_unit=( "$math_unit" "info_limit_mem"); Mb; } eXlogic; } function testMd() { # test the md number parameters for errors and busy in system for add md if (( "$set_id" < 0 ))||[[ "$set_id" == "" ]]||[[ ! "$set_id" =~ ^([0-9]+)$ ]] then reports=(); reports[${#reports[@]}]="${msg[21]}$set_id - ${msg[10]}"; makeErr; fi if [ "$($zr_blkid /dev/md$set_id|grep $set_id)" ] then reports=(); reports[${#reports[@]}]="${msg[21]}$set_id - ${msg[11]}"; makeErr; fi # test the duble number md from config test_dub=( $(echo -e ${id_zmd[@]}|tr " " "\n"|sort|tr "\n" " ") ); for (( dub_index=0; dub_index != ${#id_zmd[@]}; dub_index++ )) do dubtest_index=$(($dub_index+1)); if [[ ! $dubtest_index > $((${#id_zmd[@]}-1)) ]] then if [[ $((${test_dub[$dubtest_index]}-${test_dub[$dub_index]})) == 0 ]]; then ## duble from config reports=(); reports[${#reports[@]}]="${msg[21]}${id_zmd[$(($dub_index+1))]} - ${msg[12]}"; makeErr; fi fi if [[ $((${test_dub[$dub_index]}-$set_id)) == 0 ]] then ## duble input end from config reports=(); reports[${#reports[@]}]="${msg[21]}$set_id - ${msg[12]}"; makeErr; fi done } function testImage() { total_size_images=0; eval tmp_date="(" $(echo -e $set_image|sed 's,/,\, ,g'|cut -c 2-) ")"; test_path=$(echo $set_image|sed 's,'${tmp_date[$((${#tmp_date[@]}-1))]}',,g'); # test enable file images if [ ! -f $test_path${tmp_date[$((${#tmp_date[@]}-1))]} ] then reports=(); reports[${#reports[@]}]="${msg[22]}$set_image - ${msg[13]}"; makeErr; fi function new_add() { test_size_images=$(stat -c%s $test_path${tmp_date[$((${#tmp_date[@]}-1))]}); } function sum_img() { #echo "summ images..."; ## the sum size images for (( image_index=0; image_index != ${#image_zmd[@]}; image_index++ )) do if [ ! -f ${image_zmd[$image_index]} ] then reports[${#reports[@]}]="${msg[22]}${image_zmd[$image_index]} - ${msg[13]}"; makeErr; fi size_zmd[$image_index]=$(stat -c%s ${image_zmd[$image_index]}); done # test size image end size zram ... for (( im_index=0; im_index != ${#image_zmd[@]}; im_index++ )) do total_size_images=$(($total_size_images+${size_zmd[$im_index]})); done size_new_image=$(stat -c%s $test_path${tmp_date[$((${#tmp_date[@]}-1))]}); test_size_images=$(($total_size_images+$size_new_image)); } function add_false() { input_unit=( "$test_size_images" "math_unit" "1" ); Kb; img_msg=$math_unit; input_unit=( "$limit_mem" "math_unit" "1" ); Kb; mem_msg=$math_unit; reports=(); reports[${#reports[@]}]="${msg[22]}$set_image - ${msg[14]}"; reports[${#reports[@]}]="${msg[23]}$img_msg""Kb > ${msg[20]}$mem_msg""Kb"; makeErr; } iFs=( "$(echo -n ${#image_zmd[@]}) > 0" ); logic=( '"new_add" "sum_img"' ); eXlogic; iFs=( "$(echo -n $test_size_images) <= $limit_mem" ); logic=( '"add_false" ""' ); eXlogic; } ## input parameters function inPut() { function inMd() { lEnd=0; eval set_params="(" $(echo -e $params|sed 's/:/ /') ")"; if [ $(($(echo -n ${set_params[0]}|grep -o md|wc -m)-1)) == 2 ] then set_id=$(echo -e ${set_params[0]}|awk '{print$1}'|sed 's/\md//g'); if [[ "$set_id" == "" ]]||[[ ! "$set_id" =~ ^([0-9]+)$ ]]||(( "$set_id" < 0 )) then reports=(); reports[${#reports[@]}]=${msg[10]}; makeErr; else reports=(); set_image=${set_params[1]}; fi else reports=(); reports[${#reports[@]}]=${msg[10]}; makeErr; fi } function inLimit() { lEnd=0; set_size=$(echo $params|sed 's/%//g'|sed 's/Kb//g'); if [[ "$set_size" == "" ]]||[[ ! "$set_size" =~ ^([0-9]+)$ ]]||(( "$set_size" <= 0 )) then reports=(); reports[${#reports[@]}]=${msg[29]}; reports[${#reports[@]}]=${msg[39]}; makeErr; else set_type=$(echo $params|sed 's/'"$set_size"'//g'); if [[ "$set_type" == "%" ]]||[[ "$set_type" == "Kb" ]] then set_size_limit=$set_size; set_type_limit=$set_type; else reports=(); reports[${#reports[@]}]=${msg[29]}; reports[${#reports[@]}]=${msg[39]}; makeErr; fi fi } function noSwitch() { lEnd=0; reports=(); reports[${#reports[@]}]=${msg[30]}; reports[${#reports[@]}]=${msg[37]}; reports[${#reports[@]}]=${msg[38]}; reports[${#reports[@]}]=${msg[40]}; makeErr; } iFs=( "${set_opt[1]} == 1" "${set_opt[2]} == 1" "${set_opt[3]} == 1" "${set_opt[4]} == 1" ); logic=( '"" "inMd"' '"" "inMd"' '"" "inLimit"' '"noSwitch" "inMd"' ); eXlogic; } ## create empty config function confEmpty() { function confNew(){ echo '{'>$zpath/$zconfig echo -e '"info":"id - md[id], image - is the path to the media to mount",\n'>>$zpath/$zconfig echo -e '"log":"/var/log/syslog",\n'>>$zpath/$zconfig echo '"limit_free_mem":{'>>$zpath/$zconfig echo '"info":"size - the parameter 10-100% or 1024Kb...; Caution - the limit use free memory!",'>>$zpath/$zconfig echo '"size":"90",'>>$zpath/$zconfig echo -e '"value_size":"%"},\n'>>$zpath/$zconfig echo '"md":['>>$zpath/$zconfig echo ' ]'>>$zpath/$zconfig echo -e '}'>>$zpath/$zconfig } if [ ! -f $zpath/$zconfig ] then confNew; else cp $zpath/$zconfig $zpath/$(date +%H_%M)"-zramraid.old">/dev/null; confNew; fi } function addMd() { local tdate=$(date +%j); cat $zpath/$zconfig|jq -c '.md|=.+[{"id":"'$set_id'","info":"","image":"'$set_image'"}]'| jq '.'>$zpath/$tdate$zconfig && cat $zpath/$tdate$zconfig>$zpath/$zconfig && rm -f $zpath/$tdate$zconfig; } ## del md from config function delMd() { local tdate=$(date +%j); local del_value=$(cat $zpath/$zconfig|jq -c '.md[]|select (.id == "'$set_id'")'); #' if [[ ! "$del_value" ]] then reports=(); reports[${#reports[@]}]="${msg[29]}: md$set_id - ${msg[9]}"; makeErr; else cat $zpath/$zconfig|jq -c '.md|=.-['$del_value']'|jq '.'>$zpath/$tdate$zconfig && cat $zpath/$tdate$zconfig>$zpath/$zconfig && rm -f $zpath/$tdate$zconfig; fi } ## report config function reportConf() { reports=(); for (( report_index=0; report_index != ${#id_zmd[@]}; report_index++ )) do reports[${#reports[@]}]="config md: ${id_zmd[$report_index]}"; reports[${#reports[@]}]="info md: ${info_zmd[$report_index]}"; if (( $(stat -c%s ${image_zmd[$report_index]}) > 1024 )) then input_unit=( "$(stat -c%s ${image_zmd[$report_index]})" "math_unit" "1" ); Kb; rep_size="$math_unit""Kb"; else rep_size="$(stat -c%s ${image_zmd[$report_index]})b"; fi reports[${#reports[@]}]="size md: $rep_size"; reports[${#reports[@]}]="image md: ${image_zmd[$report_index]}"; reports[${#reports[@]}]="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; done reports[${#reports[@]}]="${msg[20]} $info_limit_mem Mb"; } ## setting limit memory function setLimitMem() { local tdate=$(date +%j); test_set_mem=0; test_free_mem=0; if [[ "$set_type_limit" == "%" ]] then input_unit=( "$free_mem" "math_unit" ); Kb; test_set_mem=$(echo "scale=2; $(echo "scale=2; $math_unit/100"|bc -lq)*$set_size_limit"|bc -lq|sed 's/\./ /g'|awk '{print$1}'); #-" fi if [[ "$set_type_limit" == "Kb" ]] then math_unit=$set_size_limit; input_unit=( "$math_unit" "test_set_mem" ); Kb; fi if [[ ! "$test_set_mem" == 0 ]] then math_unit=$free_mem; input_unit=( "$math_unit" "test_free_mem" ); Kb; else reports=(); reports[${#reports[@]}]=${msg[29]}; reports[${#reports[@]}]=${msg[39]}; makeErr; fi if (( "$test_free_mem" > "$test_set_mem" )) then ## add date local input_date_limit=$(cat $zpath/$zconfig|jq -c '.limit_free_mem|.size="'"$set_size_limit"'"|.value_size="'"$set_type_limit"'"'); cat $zpath/$zconfig|jq -c ' del (.limit_free_mem)'| jq '.'>$zpath/$tdate$zconfig && cat $zpath/$tdate$zconfig>$zpath/$zconfig && rm -f $zpath/$tdate$zconfig; ## add cat $zpath/$zconfig|jq -c '.limit_free_mem|=.+'"$input_date_limit"''| jq '.'>$zpath/$tdate$zconfig && cat $zpath/$tdate$zconfig>$zpath/$zconfig && rm -f $zpath/$tdate$zconfig; else reports=(); reports[${#reports[@]}]="${msg[20]}$set_size_limit$set_type_limit > ${msg[33]}$free_mem""Kb"; reports[${#reports[@]}]=${msg[29]}; reports[${#reports[@]}]=${msg[39]}; makeErr; fi } ## add info device md function addInfoMd() { if [[ $(cat $zpath/$zconfig|jq -c '.md[]|select(.id == "'$set_id'")') ]] #-' then local Sinput=(); clear echo "--------------------------------------------------"; echo "${msg[45]}"; echo "--------------------------------------------------"; read Sinput; local tdate=$(date +%j); local data_info="$(cat $zpath/$zconfig|jq -c '.md[]|select(.id == "'$set_id'")|.info ="'"'$(echo ${Sinput[@]})'"'"')"; delMd; cat $zpath/$zconfig|jq -c '.md|=.+['"$data_info"']'| jq '.'>$zpath/$tdate$zconfig && cat $zpath/$tdate$zconfig>$zpath/$zconfig && rm -f $zpath/$tdate$zconfig; else reports=(); reports[${#reports[@]}]=${msg[9]}; makeErr; fi } ##--@F step operation function testId() { if (( ! $(id|grep "root"|wc -m) )) then reports=(); reports[${#reports[@]}]="${msg[47]}"; makeErr; fi } ##--@F executor function executor() { if [[ ${#execute_func[@]} -eq 0 ]] then echo "exit"; exit 0; fi for ((ex_index=0; ex_index != ${#execute_func[@]}; ex_index++)) do ## !! debug operation... ##echo "execution: function ${execute_func[ex_index]}" ${execute_func[ex_index]}; done } ##- Begin zramraid case "$option" in ## create default config + "--config-default" | "--config-default" ) execute_func=( ${operation_createdef[@]} ); executor; exit 0 ;; ## add md "--add" | "--add" ) set_opt[1]="1"; execute_func=( ${operation_add[@]} ); executor; exit 0 ;; ## del md "--del" | "--del" ) set_opt[2]="1"; execute_func=( ${operation_del[@]} ); executor; exit 0 ;; ## list md + "--list" | "--list" ) execute_func=( ${operation_list[@]} ); executor; exit 0 ;; ## limit memory "--limit-mem" | "--limit-mem" ) set_opt[3]="1"; execute_func=( ${operation_mem[@]} ); executor; exit 0 ;; ## md info "--info-md" | "--info-md" ) set_opt[4]="1"; execute_func=( ${operation_mdinfo[@]} ); executor; exit 0 ;; ## help + "--help" | "--help" ) execute_func=( ${operation_help[@]} ); executor; exit 0 ;; * ) # selecting defaults. + execute_func=( ${operation_help[@]} ); executor; exit 1 ;; esac