feat: add CONFFILES to record /etc files
This commit is contained in:
144
leaf
144
leaf
@@ -440,9 +440,81 @@ leaf_trace_package() {
|
||||
find . -type l | sort > "${_trace_dir}"/LINKS
|
||||
sed -i "s/.//" "${_trace_dir}"/{DIRS,FILES,LINKS}
|
||||
install -vm644 "${PKGBUILD_DIR}/${PKG_PREFIX}/${PKG_NAME}.PKGBUILD" "${_trace_dir}/PKGBUILD"
|
||||
leaf_trace_conffiles "${_trace_dir}"
|
||||
popd > /dev/null 2>&1
|
||||
}
|
||||
|
||||
leaf_trace_conffiles() {
|
||||
# usage: leaf_trace_conffiles <trace_dir>
|
||||
# called with CWD = pkgdir (same as leaf_trace_package)
|
||||
local _trace_dir="$1"
|
||||
local _out="${_trace_dir}/CONFFILES"
|
||||
local _p _type _val _mode _uid _gid
|
||||
|
||||
[ -d ./etc ] || return 0
|
||||
|
||||
: > "${_out}"
|
||||
|
||||
# regular files
|
||||
while IFS= read -r -d '' _p; do
|
||||
_mode=$(stat -c %a -- "$_p")
|
||||
_uid=$(stat -c %u -- "$_p")
|
||||
_gid=$(stat -c %g -- "$_p")
|
||||
_val=$(sha256sum -- "$_p" | awk '{print $1}')
|
||||
printf '%s\tf\t%s\t%s\t%s\t%s\n' "/${_p#./}" "${_val}" "${_mode}" "${_uid}" "${_gid}" >> "${_out}"
|
||||
done < <(find ./etc -type f -print0)
|
||||
|
||||
# symlinks
|
||||
while IFS= read -r -d '' _p; do
|
||||
_mode=$(stat -c %a -- "$_p")
|
||||
_uid=$(stat -c %u -- "$_p")
|
||||
_gid=$(stat -c %g -- "$_p")
|
||||
_val=$(readlink -- "$_p")
|
||||
printf '%s\tl\t%s\t%s\t%s\t%s\n' "/${_p#./}" "${_val}" "${_mode}" "${_uid}" "${_gid}" >> "${_out}"
|
||||
done < <(find ./etc -type l -print0)
|
||||
|
||||
sort -o "${_out}" "${_out}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
leaf_conffile_is_unmodified() {
|
||||
# usage: leaf_conffile_is_unmodified <abs_path> <trace_dir>
|
||||
# return 0 if unmodified (safe to remove), 1 otherwise
|
||||
local path="$1" tdir="$2"
|
||||
local cf="${tdir}/CONFFILES"
|
||||
local line type val mode uid gid
|
||||
local cur_val cur_mode cur_uid cur_gid
|
||||
|
||||
[ -r "${cf}" ] || return 1
|
||||
[ -e "${path}" ] || return 1
|
||||
|
||||
line="$(grep -F -m1 -- "${path}"$'\t' "${cf}" 2>/dev/null)" || return 1
|
||||
|
||||
IFS=$'\t' read -r _p type val mode uid gid <<< "${line}"
|
||||
|
||||
cur_mode="$(stat -c %a -- "${path}" 2>/dev/null)" || return 1
|
||||
cur_uid="$(stat -c %u -- "${path}" 2>/dev/null)" || return 1
|
||||
cur_gid="$(stat -c %g -- "${path}" 2>/dev/null)" || return 1
|
||||
|
||||
# metadata changed -> treat as modified
|
||||
if [ "${cur_mode}" != "${mode}" ] || [ "${cur_uid}" != "${uid}" ] || [ "${cur_gid}" != "${gid}" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "${type}" in
|
||||
f)
|
||||
cur_val="$(sha256sum -- "${path}" 2>/dev/null | awk '{print $1}')" || return 1
|
||||
[ "${cur_val}" = "${val}" ] && return 0 || return 1
|
||||
;;
|
||||
l)
|
||||
cur_val="$(readlink -- "${path}" 2>/dev/null)" || return 1
|
||||
[ "${cur_val}" = "${val}" ] && return 0 || return 1
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
leaf_update_package_database() {
|
||||
local _item="$(echo "$2" | awk 'BEGIN{FS="/";OFS="\\/"}{print $1,$2}')"
|
||||
case $1 in
|
||||
@@ -645,33 +717,73 @@ leaf_remove_package() {
|
||||
[ -n "$(grep "${PKG_PREFIX}/${PKG_NAME}" ${INSTALLED_PACKAGES})" ] || {
|
||||
leaf_error "Package ${PKG_PREFIX}/${PKG_NAME} is NOT installed"
|
||||
}
|
||||
|
||||
leaf_phase_must "Preremove" src_preremove "Preremove failed."
|
||||
|
||||
local _file _link _directory _etc_backup_path _relative_path _backup_etc=false
|
||||
_etc_backup_path="/etc/.leaf_backup/${PKGNAME}_$(date +%Y%m%d%H%M%S)"
|
||||
cat "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}/FILES" | while read -r _file; do
|
||||
if [[ "${_file}" == /etc/* && -f "${_file}" ]]; then
|
||||
_backup_etc=true
|
||||
_relative_path="${_file#/etc/}"
|
||||
mkdir -pv "${_etc_backup_path}/$(dirname "${_relative_path}")"
|
||||
mv -v "${_file}" "${_etc_backup_path}/${_relative_path}"
|
||||
local _trace_dir="${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}"
|
||||
local _has_conffiles=0
|
||||
|
||||
[ -r "${_trace_dir}/CONFFILES" ] && _has_conffiles=1
|
||||
|
||||
_etc_backup_path="/etc/.leaf_backup/${PKG_NAME}_$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
# FILES
|
||||
while read -r _file; do
|
||||
if [[ "${_file}" == /etc/* && -e "${_file}" ]]; then
|
||||
if [ "${_has_conffiles}" -eq 1 ]; then
|
||||
if leaf_conffile_is_unmodified "${_file}" "${_trace_dir}"; then
|
||||
rm -fv -- "${_file}"
|
||||
else
|
||||
leaf_record_message "Preserved modified config file: ${_file}"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
# fallback for old packages without CONFFILES (keep old behavior)
|
||||
if [[ -f "${_file}" ]]; then
|
||||
_backup_etc=true
|
||||
_relative_path="${_file#/etc/}"
|
||||
mkdir -pv "${_etc_backup_path}/$(dirname "${_relative_path}")"
|
||||
mv -v -- "${_file}" "${_etc_backup_path}/${_relative_path}"
|
||||
else
|
||||
rm -fv -- "${_file}"
|
||||
fi
|
||||
else
|
||||
rm -fv "${_file}"
|
||||
rm -fv -- "${_file}"
|
||||
fi
|
||||
done
|
||||
done < "${_trace_dir}/FILES"
|
||||
|
||||
if [[ "${_backup_etc}" == true ]]; then
|
||||
leaf_record_message "Found files in /etc, backuped to ${_etc_backup_path}."
|
||||
fi
|
||||
cat "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}/LINKS" | while read -r _link; do
|
||||
[ ! -L "${_link}" ] || rm -fv "${_link}"
|
||||
done
|
||||
cat "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}/DIRS" | while read -r _directory; do
|
||||
if [[ -d ${_directory} ]]; then
|
||||
|
||||
# LINKS
|
||||
while read -r _link; do
|
||||
if [[ "${_link}" == /etc/* && -e "${_link}" ]]; then
|
||||
if [ "${_has_conffiles}" -eq 1 ]; then
|
||||
if leaf_conffile_is_unmodified "${_link}" "${_trace_dir}"; then
|
||||
rm -fv -- "${_link}"
|
||||
else
|
||||
leaf_record_message "Preserved modified config link: ${_link}"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
else
|
||||
[ ! -L "${_link}" ] || rm -fv -- "${_link}"
|
||||
fi
|
||||
done < "${_trace_dir}/LINKS"
|
||||
|
||||
# DIRS
|
||||
while read -r _directory; do
|
||||
if [[ -d "${_directory}" ]]; then
|
||||
rmdir --ignore-fail-on-non-empty "${_directory}"
|
||||
fi
|
||||
done
|
||||
done < "${_trace_dir}/DIRS"
|
||||
|
||||
leaf_phase_must "Postremove" src_postremove "Postremove failed."
|
||||
leaf_invoke_hooks remove
|
||||
rm -rf "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}"
|
||||
rm -rf "${_trace_dir}"
|
||||
leaf_update_package_database delete "${PKG_PREFIX}/${PKG_NAME}"
|
||||
leaf_update_environment
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user