# # Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 LucĂ­a Andrea Illanes Albornoz # set +o errexit -o noglob -o nounset is assumed. # # # rtl_basename() - obtain base name from filename # @_rfname: inout reference to filename # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_basename() { rtl_basename2 "${1}" "${1}"; }; # # rtl_basename2() - obtain base name from filename # @_rfname: in reference to filename # @_rfname_out: out reference to new filename # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_basename2() { local _rb2_rfname="${1#\$}" _rb2_rfname_out="${2#\$}" \ _rb2_fname=""; eval _rb2_fname="\${${_rb2_rfname}}"; eval ${_rb2_rfname_out}='${_rb2_fname##*/}'; return 0; }; # # rtl_check_digest() - check digest of single file # @_rdigest: out reference to digest of file # @_fname: name of file to check # @_digest_check: digest to check against # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_check_digest() { local _rcd_rdigest="${1#\$}" _rcd_fname="${2}" _rcd_digest_check="${3}" \ _rcd_digest=""; if ! [ -e "${_rcd_fname}" ]; then return 1; else set -- $(sha256sum "${_rcd_fname}"); _rcd_digest="${1}"; eval ${_rcd_rdigest}='${_rcd_digest}'; if [ "${_rcd_digest}" = "${_rcd_digest_check}" ]; then return 0; else return 1; fi; fi; }; # # rtl_check_digest_file() - check digest of single file w/ digest file # @_fname: name of file to check # @_digest_check: digest to check against # @_digest_fname: name of file containing digest # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_check_digest_file() { local _rcdf_fname="${1}" _rcdf_digest_check="${2}" _rcdf_digest_fname="${3}" \ _rcdf_digest="" _rcdf_digest_file=""; if ! [ -e "${_rcdf_digest_fname}" ]; then return 1; else _rcdf_digest_file="$(cat "${_rcdf_digest_fname}")"; if [ "${_rcdf_digest_file}" != "${_rcdf_digest_check}" ]\ || ! rtl_check_digest \$_rcdf_digest "${_rcdf_fname}" \ "${_rcdf_digest_check}"; then return 1; else return 0; fi; fi; }; # # rtl_check_path_vars() - check pathname variables for validity # @_rstatus: out reference to status string # @_vnames: list of variable names # # Returns: zero (0) on success, non-zero (>0) on empty or unset pathname variable or pathname variable containing whitespace characters # rtl_check_path_vars() { local _rcpv_rstatus="${1#\$}" _rcpv_vnames="${2}" \ _rcpv_rc=0 _rcpv_vname="" _rcpv_vname_val=""; for _rcpv_vname in ${_rcpv_vnames}; do rtl_get_var_unsafe \$_rcpv_vname_val "${_rcpv_vname}"; if [ "${_rcpv_vname_val:+1}" != 1 ]; then _rcpv_rc=1; rtl_setrstatus "${_rcpv_rstatus}" 'Error: variable \`'"${_rcpv_vname}'"' is empty or unset.'; break; elif [ "${_rcpv_vname_val#* *}" != "${_rcpv_vname_val}" ]; then _rcpv_rc=2; rtl_setrstatus "${_rcpv_rstatus}" 'Error: variable \`'"${_rcpv_vname}'"' contains one or more whitespace characters.'; break; fi; done; return "${_rcpv_rc}"; }; # # rtl_dirname() - obtain directory name from filename # @_rfname: inout reference to {file,directory} name # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_dirname() { rtl_dirname2 "${1}" "${1}"; }; # # rtl_dirname2() - obtain directory name from filename # @_rfname: in reference to filename # @_rfname_out: out reference to directory name # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_dirname2() { local _rfname="${1#\$}" _rdname_out="${2#\$}" \ _rd2_dname=""; eval _rd2_dname="\${${_rfname}}"; _rd2_dname="${_rd2_dname%/*}"; case "${_rd2_dname}" in "") _rd2_dname="."; ;; *) while rtl_matchr "${_rd2_dname}" "*/"; do _rd2_dname="${_rd2_dname%/}"; done; ;; esac; eval ${_rdname_out}='${_rd2_dname}'; return 0; }; # # rtl_exists_any() - check for existence of pathnames beneath directory # @_subdir: single directory name # @...: list of pathnames to check # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_exists_any() { local _rea_subdir="${1}"; shift; while [ "${#}" -gt 0 ]; do if [ -e "${_rea_subdir}/${1}" ]; then return 0; else shift; fi; done; return 1; }; # # rtl_flock_acquire() - acquire file lock # @_fd: single file descriptor # @_conflict_exit_code: exit code on conflict # @_wait: wait period in seconds # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_flock_acquire() { local _rfa_fd="${1}" _rfa_conflict_exit_code="${2:-253}" _rfa_wait="${3:-3600}"; while true; do if flock \ -E "${_rfa_conflict_exit_code}" \ -w "${_rfa_wait}" \ "${_rfa_fd}"; then return 0; elif [ "${?}" -eq "${_rfa_conflict_exit_code}" ]; then continue; else return "${?}"; fi; done; }; # # rtl_is_newer() - check if single file is newer than other single file # @_new_fname: single name of newer file # @_old_fname: single name of older file # # Returns: zero (0) if @_new_fname is newer, non-zero (>0) if @_old_fname is newer # rtl_is_newer() { local _ris_new_fname="${1}" _ris_old_fname="${2}" \ _ris_new_ts="" _ris_old_ts=""; if ! [ -e "${_ris_old_fname}" ]; then return 0; else _ris_new_ts="$(stat -c %Y "${_ris_new_fname}" 2>/dev/null)"; _ris_old_ts="$(stat -c %Y "${_ris_old_fname}" 2>/dev/null)"; if [ "${_ris_new_ts:-0}" -gt "${_ris_old_ts:-0}" ]; then return 0; else return 1; fi; fi; }; # # rtl_patch_files() - patch files # @_patch_cwd: patch(1) -d directory # @_strip_count: patch(1) strip count # @_fn: name of function that produces patch filenames and takes the arguments @_rpatch_fname @_patch_idx @... # @... optional arguments to pass to @_fn # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_patch_files() { local _rpf_patch_cwd="${1}" _rpf_strip_count="${2}" _rpf_fn="${3}" \ _rpf_patch_fname="" _rpf_patch_idx=0; shift $((3 + 2)); _rpf_patch_idx=1; while "${_rpf_fn}" \ \$_rpf_patch_fname "${_rpf_patch_idx}" \ "${@}" \ && [ "${_rpf_patch_fname:+1}" = 1 ]; do : $((_rpf_patch_idx += 1)); if [ -r "${_rpf_patch_fname}" ]\ && ! patch \ -b \ -d "${_rpf_patch_cwd}" \ "-p${_rpf_strip_count}" \ < "${_rpf_patch_fname}"; then return 1; fi; done; return 0; }; # # rtl_set_perms_treeV() - set mode bits of directories and files # @_mode_dir: mode bits for directories # @_mode_file_exec: mode bits for executable files # @_mode_file_nonexec: mode bits for non-executable files # @...: list of base directory pathnames as positional parameters; empty strings are ignored # # Returns: zero (0) on success, non-zero (>0) on failure # rtl_set_perms_treeV() { local _rspt_mode_dir="${1}" _rspt_mode_file_exec="${2}" _rspt_mode_file_nonexec="${3}" \ _rspt_destdir="" _rspt_fname="" \ IFS IFS0="${IFS}"; shift 3; for _rspt_destdir in "${@}"; do if [ -e "${_rspt_destdir}" ]; then rtl_set_IFS_nl; for _rspt_fname in $(find "${_rspt_destdir}" -type d); do if ! rtl_fileop chmod "${_rspt_mode_dir}" \ "${_rspt_fname}"; then return 1; fi; done; for _rspt_fname in $(find \ "${_rspt_destdir}" \ \( -not -perm /0111 \) \ -type f); do if ! rtl_fileop chmod "${_rspt_mode_file_nonexec}" \ "${_rspt_fname}"; then return 1; fi; done; for _rspt_fname in $(find \ "${_rspt_destdir}" \ -perm /0111 \ -type f); do if ! rtl_fileop chmod "${_rspt_mode_file_exec}" \ "${_rspt_fname}"; then return 1; fi; done; IFS="${IFS0}"; fi; done; return 0; }; # vim:filetype=sh textwidth=0