#!/bin/bash # # rejmerge (pkgutils) # # Copyright (c) 2000-2005 Per Liden # Copyright (c) 2006-2013 by CRUX team (http://crux.nu) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, # USA. # info_n() { echo -n "=======> $1" } info() { info_n "$1" echo } interrupted() { echo "" info "Aborted." exit 1 } atexit() { if [ -e "$TMPFILE" ]; then rm -f "$TMPFILE" fi } rejmerge_diff() { diff -u "$1" "$2" > "$3" } rejmerge_merge() { diff --old-group-format="%<" \ --new-group-format="%>" \ --changed-group-format="<<<<< MERGE CONFLICT $1 >>>>> %<<<<<< MERGE CONFLICT $2 >>>>> %><<<<< END MERGE CONFLICT >>>>> " \ "$1" "$2" > "$3" REJMERGE_MERGE_INFO="$(grep -c '^<<<<< END MERGE CONFLICT >>>>>$' "$3") merge conflict(s)." } permissions_menu() { while true; do info "Access permissions $1" stat -c '%A %U %G %n' "$1" stat -c '%A %U %G %n' "$2" while true; do info_n "[K]eep [U]pgrade [D]iff [S]kip? " read -n1 CMD echo case "$CMD" in k|K) chown --reference="$1" "$2" chmod --reference="$1" "$2" break 2 ;; u|U) chown --reference="$2" "$1" chmod --reference="$2" "$1" break 2 ;; d|D) break 1 ;; s|S) break 2 ;; esac done done } merge_menu() { rejmerge_merge "$1" "$2" "$TMPFILE" while true; do info "Merged $1" cat "$TMPFILE" | more if [ "$REJMERGE_MERGE_INFO" ]; then info "$REJMERGE_MERGE_INFO" unset REJMERGE_MERGE_INFO fi while true; do info_n "[I]nstall [E]dit [V]iew [S]kip? " read -n1 CMD echo case "$CMD" in i|I) chmod --reference="$1" "$TMPFILE" mv -f "$TMPFILE" "$1" rm -f "$2" break 2 ;; e|E) $EDITOR "$TMPFILE" break 1 ;; v|V) break 1 ;; s|S) break 2 ;; esac done done : > "$TMPFILE" } diff_menu() { rejmerge_diff "$1" "$2" "$TMPFILE" while true; do info "$1" cat "$TMPFILE" | more while true; do info_n "[K]eep [U]pgrade [M]erge [D]iff [S]kip? " read -n1 CMD echo case "$CMD" in k|K) rm -f "$2" break 2 ;; u|U) mv -f "$2" "$1" break 2 ;; m|M) merge_menu "$1" "$2" break 2 ;; d|D) break 1 ;; s|S) break 2 ;; esac done done : > "$TMPFILE" } file_menu() { while true; do info "$1" file "$1" "$2" while true; do info_n "[K]eep [U]pgrade [D]iff [S]kip? " read -n1 CMD echo case "$CMD" in k|K) rm -f "$2" break 2 ;; u|U) mv -f "$2" "$1" break 2 ;; d|D) break 1 ;; s|S) break 2 ;; esac done done } print_help() { echo "usage: $REJMERGE_COMMAND [options]" echo "options:" echo " -r, --root specify alternative root" echo " -v, --version print version and exit " echo " -h, --help print help and exit" } parse_options() { while [ "$1" ]; do case $1 in -r|--root) if [ ! "$2" ]; then echo "$REJMERGE_COMMAND: option $1 requires an argument" exit 1 fi REJMERGE_ROOT="$2" REJMERGE_CONF="$2$REJMERGE_CONF" REJECTED_DIR="$2$REJECTED_DIR" shift ;; -v|--version) echo "$REJMERGE_COMMAND (pkgutils) $REJMERGE_VERSION" exit 0 ;; -h|--help) print_help exit 0 ;; *) echo "$REJMERGE_COMMAND: invalid option $1" exit 1 ;; esac shift done if [ ! -d "$REJECTED_DIR" ]; then echo "$REJMERGE_COMMAND: $REJECTED_DIR not found" exit 1 fi } files_regular() { local STAT_FILE1=$(stat -c '%F' "$1") local STAT_FILE2=$(stat -c '%F' "$2") if [ "$STAT_FILE1" != "regular file" ]; then return 1 fi if [ "$STAT_FILE2" != "regular file" ]; then return 1 fi return 0 } main() { parse_options "$@" if [ "$UID" != "0" ]; then echo "$REJMERGE_COMMAND: only root can merge rejected files" exit 1 fi # Read configuration if [ -f "$REJMERGE_CONF" ]; then . "$REJMERGE_CONF" fi REJECTED_FILES_FOUND="no" # Check files for REJECTED_FILE in $(find $REJECTED_DIR ! -type d); do INSTALLED_FILE="$REJMERGE_ROOT${REJECTED_FILE##$REJECTED_DIR}" # Remove rejected file if there is no installed version if [ ! -e "$INSTALLED_FILE" ]; then rm -f "$REJECTED_FILE" continue fi # Check permissions local STAT_FILE1=$(stat -c '%A %U %G' "$INSTALLED_FILE") local STAT_FILE2=$(stat -c '%A %U %G' "$REJECTED_FILE") if [ "$STAT_FILE1" != "$STAT_FILE2" ]; then REJECTED_FILES_FOUND="yes" permissions_menu "$INSTALLED_FILE" "$REJECTED_FILE" fi # Check file types if files_regular "$INSTALLED_FILE" "$REJECTED_FILE"; then # Both files are regular if cmp -s "$INSTALLED_FILE" "$REJECTED_FILE"; then rm -f "$REJECTED_FILE" else REJECTED_FILES_FOUND="yes" diff_menu "$INSTALLED_FILE" "$REJECTED_FILE" fi else # At least one file is non-regular REJECTED_FILES_FOUND="yes" file_menu "$INSTALLED_FILE" "$REJECTED_FILE" fi done # Remove empty directories for DIR in $(find $REJECTED_DIR -depth -type d); do if [ "$DIR" != "$REJECTED_DIR" ]; then rmdir "$DIR" &> /dev/null fi done if [ "$REJECTED_FILES_FOUND" = "no" ]; then echo "Nothing to merge" fi exit 0 } trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM trap "atexit" EXIT export LC_ALL=POSIX readonly REJMERGE_VERSION="#VERSION#" readonly REJMERGE_COMMAND="${0##*/}" REJMERGE_ROOT="" REJMERGE_CONF="/etc/rejmerge.conf" REJECTED_DIR="/var/lib/pkg/rejected" EDITOR=${EDITOR:-vi} TMPFILE=$(mktemp) || exit 1 main "$@" # End of file