feat: add CONFFILES to record /etc files
This commit is contained in:
@@ -440,9 +440,81 @@ leaf_trace_package() {
|
|||||||
find . -type l | sort > "${_trace_dir}"/LINKS
|
find . -type l | sort > "${_trace_dir}"/LINKS
|
||||||
sed -i "s/.//" "${_trace_dir}"/{DIRS,FILES,LINKS}
|
sed -i "s/.//" "${_trace_dir}"/{DIRS,FILES,LINKS}
|
||||||
install -vm644 "${PKGBUILD_DIR}/${PKG_PREFIX}/${PKG_NAME}.PKGBUILD" "${_trace_dir}/PKGBUILD"
|
install -vm644 "${PKGBUILD_DIR}/${PKG_PREFIX}/${PKG_NAME}.PKGBUILD" "${_trace_dir}/PKGBUILD"
|
||||||
|
leaf_trace_conffiles "${_trace_dir}"
|
||||||
popd > /dev/null 2>&1
|
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() {
|
leaf_update_package_database() {
|
||||||
local _item="$(echo "$2" | awk 'BEGIN{FS="/";OFS="\\/"}{print $1,$2}')"
|
local _item="$(echo "$2" | awk 'BEGIN{FS="/";OFS="\\/"}{print $1,$2}')"
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -645,33 +717,73 @@ leaf_remove_package() {
|
|||||||
[ -n "$(grep "${PKG_PREFIX}/${PKG_NAME}" ${INSTALLED_PACKAGES})" ] || {
|
[ -n "$(grep "${PKG_PREFIX}/${PKG_NAME}" ${INSTALLED_PACKAGES})" ] || {
|
||||||
leaf_error "Package ${PKG_PREFIX}/${PKG_NAME} is NOT installed"
|
leaf_error "Package ${PKG_PREFIX}/${PKG_NAME} is NOT installed"
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf_phase_must "Preremove" src_preremove "Preremove failed."
|
leaf_phase_must "Preremove" src_preremove "Preremove failed."
|
||||||
|
|
||||||
local _file _link _directory _etc_backup_path _relative_path _backup_etc=false
|
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)"
|
local _trace_dir="${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}"
|
||||||
cat "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}/FILES" | while read -r _file; do
|
local _has_conffiles=0
|
||||||
if [[ "${_file}" == /etc/* && -f "${_file}" ]]; then
|
|
||||||
|
[ -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
|
_backup_etc=true
|
||||||
_relative_path="${_file#/etc/}"
|
_relative_path="${_file#/etc/}"
|
||||||
mkdir -pv "${_etc_backup_path}/$(dirname "${_relative_path}")"
|
mkdir -pv "${_etc_backup_path}/$(dirname "${_relative_path}")"
|
||||||
mv -v "${_file}" "${_etc_backup_path}/${_relative_path}"
|
mv -v -- "${_file}" "${_etc_backup_path}/${_relative_path}"
|
||||||
else
|
else
|
||||||
rm -fv "${_file}"
|
rm -fv -- "${_file}"
|
||||||
fi
|
fi
|
||||||
done
|
else
|
||||||
|
rm -fv -- "${_file}"
|
||||||
|
fi
|
||||||
|
done < "${_trace_dir}/FILES"
|
||||||
|
|
||||||
if [[ "${_backup_etc}" == true ]]; then
|
if [[ "${_backup_etc}" == true ]]; then
|
||||||
leaf_record_message "Found files in /etc, backuped to ${_etc_backup_path}."
|
leaf_record_message "Found files in /etc, backuped to ${_etc_backup_path}."
|
||||||
fi
|
fi
|
||||||
cat "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}/LINKS" | while read -r _link; do
|
|
||||||
[ ! -L "${_link}" ] || rm -fv "${_link}"
|
# LINKS
|
||||||
done
|
while read -r _link; do
|
||||||
cat "${TRACE_DIR}/${PKG_PREFIX}/${PKG_NAME}/DIRS" | while read -r _directory; do
|
if [[ "${_link}" == /etc/* && -e "${_link}" ]]; then
|
||||||
if [[ -d ${_directory} ]]; 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}"
|
rmdir --ignore-fail-on-non-empty "${_directory}"
|
||||||
fi
|
fi
|
||||||
done
|
done < "${_trace_dir}/DIRS"
|
||||||
|
|
||||||
leaf_phase_must "Postremove" src_postremove "Postremove failed."
|
leaf_phase_must "Postremove" src_postremove "Postremove failed."
|
||||||
leaf_invoke_hooks remove
|
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_package_database delete "${PKG_PREFIX}/${PKG_NAME}"
|
||||||
leaf_update_environment
|
leaf_update_environment
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user