str_starts, str_replace chr - decimal value to character funiq - print new unique file name mkuniqdir - create and print new unique dir enc_nonprn_white - encode non-printable and white chars to '\xHH' foreach_dev_until - evaluates command for every given device modified: foreach_uuid_until - use $___ as a place holder --- modules.d/99base/dracut-lib.sh | 142 ++++++++++++++++++++++++++++++++++++++-- 1 files changed, 135 insertions(+), 7 deletions(-) diff --git a/modules.d/99base/dracut-lib.sh b/modules.d/99base/dracut-lib.sh index 627d2c5..e8a7850 100755 --- a/modules.d/99base/dracut-lib.sh +++ b/modules.d/99base/dracut-lib.sh @@ -6,6 +6,35 @@ strstr() { [ "${1#*$2*}" != "$1" ] } +# returns OK if $1 contains $2 at the beginning +str_starts() { + [ "${1#$2*}" != "$1" ] +} + +# converts decimal value to its ASCII character representation +# <http://mywiki.wooledge.org/BashFAQ/071> +chr() { + printf \\$(($1/64*100+$1%64/8*10+$1%8)) +} + +# replaces all occurrences of 'search' in 'str' with 'replacement' +# +# str_replace str search replacement +# +# example: +# str_replace ' one two three ' ' ' '_' +str_replace() { + local in="$1"; local s="$2"; local r="$3" + local out='' + + while strstr "${in}" "$s"; do + chop="${in%%$s*}" + out="${out}${chop# }$r" + in="${in#*$s}" + done + echo "${out}${in}" +} + getarg() { set +x local o line val @@ -283,35 +312,134 @@ ip_to_var() { esac } -# Evaluate command for UUIDs either given as arguments for this function or all +# Prints unique path for potential file inside specified directory. It consists +# of specified directory, prefix and number at the end which is incremented +# until non-existing file is found. +# +# funiq dir prefix +# +# example: +# # ls /mnt +# cdrom0 cdrom1 +# +# # funiq /mnt cdrom +# /mnt/cdrom2 +funiq() { + local dir="$1"; local prefix="$2" + local i=0 + + [ -d "${dir}" ] || return 1 + + while [ -e "${dir}/${prefix}$i" ]; do + i=$(($i+1)) || return 1 + done + + echo "${dir}/${prefix}$i" +} + +# Creates unique directory and prints its path. It's using funiq to generate +# path. +# +# mkuniqdir subdir new_dir_name +mkuniqdir() { + local dir="$1"; local prefix="$2" + local retdir + + retdir=$(funiq "${dir}" "${prefix}") || return 1 + until mkdir "${retdir}" 2>/dev/null; do + retdir=$(funiq "${dir}" "${prefix}") || return 1 + done + + echo "${retdir}" +} + +# Encodes non-printable characters and spaces in a string to their hexadecimal +# values prefixed with '\x'. +# +# enc_nonprn_white str +enc_nonprn_white() { + local str="$1"; local i=1 + + while [ $i -le 32 ]; do + str="$(str_replace "${str}" "$(chr $i)" \\x$(printf '%02x' $i))" + i=$(($i+1)) + done + + echo "${str}" +} + +# Evaluates command for UUIDs either given as arguments for this function or all # listed in /dev/disk/by-uuid. UUIDs doesn't have to be fully specified. If -# beginning is given it is expanded to all matching UUIDs. To pass full UUID -# to your command use '${full_uuid}'. Remember to escape '$'! +# beginning is given it is expanded to all matching UUIDs. To pass full UUID to +# your command use '$___' as a place holder. Remember to escape '$'! +# +# foreach_uuid_until [ -p prefix ] command UUIDs # -# $1 = command to be evaluated -# $2 = list of UUIDs separated by space +# prefix - string to put just before $___ +# command - command to be evaluated +# UUIDs - list of UUIDs separated by space # # The function returns after *first successful evaluation* of the given command # with status 0. If evaluation fails for every UUID function returns with # status 1. # # Example: -# foreach_uuid_until "mount -U \${full_uuid} /mnt; echo OK; umount /mnt" \ +# foreach_uuid_until "mount -U \$___ /mnt; echo OK; umount /mnt" \ # "01234 f512 a235567f-12a3-c123-a1b1-01234567abcb" foreach_uuid_until() ( cd /dev/disk/by-uuid + [ "$1" = -p ] && local prefix="$2" && shift 2 local cmd="$1"; shift; local uuids_list="$*" - local uuid; local full_uuid + local uuid; local full_uuid; local ___ [ -n "${cmd}" ] || return 1 for uuid in ${uuids_list:-*}; do for full_uuid in ${uuid}*; do [ -e "${full_uuid}" ] || continue + ___="${prefix}${full_uuid}" eval ${cmd} && return 0 done done return 1 ) + +# Evaluates command for every given device. Every single device must be +# specified either by path, by label prefixed with 'LABEL=' or UUID prefixed +# with 'UUID='. UUIDs are processed by 'foreach_uuid_until'. List elements' +# order is preserved. +# +# foreach_dev_until command device1 device2 ... +# +# The function returns after *first successful evaluation* of the given command +# with status 0. If evaluation fails for every device, function returns with +# status 1. +# +# Example: +# foreach_dev_until "echo \$___; false" /dev/sda1 "LABEL=Linux boot" "UUID=123a" +foreach_dev_until() { + local cmd="$1"; shift + local dev; local ___ + + [ -n "${cmd}" ] || return 1 + + if [ -n "$*" ]; then + for dev; do + if str_starts "${dev}" 'UUID='; then + foreach_uuid_until -p 'UUID=' "${cmd}" "${dev#UUID=*}" && \ + return 0 + else + [ -e "${dev}" ] || [ -e "/dev/disk/by-label/$(enc_nonprn_white\ + "${dev#LABEL=}")" ] || continue + ___="${dev}" + eval ${cmd} && return 0 + fi + done + else + foreach_uuid_until -p 'UUID=' "${cmd}" && return 0 + fi + + return 1 +} -- 1.7.3 -- To unsubscribe from this list: send the line "unsubscribe initramfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html