OSDN Git Service

Version 3.1.1+toward_3.2.0_20141228193746
[portsreinstall/current.git] / lib / libpkgsys.sh
index 4ac77be..773c43a 100644 (file)
@@ -2,19 +2,35 @@
 # ==============================================================================
 # portsreinstall library script
 # - Wrappers for hiding version differences in the Ports/Packages system -
-# Copyright (C) 2013 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
+# Copyright (C) 2013-2014 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
 # This software is distributed under the 2-Clause BSD License.
 # ==============================================================================
 
 # ============= Variables =============
-PKGSYS_USE_PKGNG=no    # no: legacy pkg_* tools, yes: the new generation package (pkgng)
-PKGSYS_CMD_PKG_INFO='pkg_info' # Corresponding command for pkg_info
-PKGSYS_CMD_PKG_CREATE='pkg_create'     # Corresponding command for pkg_create
-PKGSYS_CMD_PKG_DELETE='pkg_delete'     # Corresponding command for pkg_delete
-PKGSYS_CMD_PKG_ADD='pkg_add'   # Corresponding command for pkg_add
+PKGSYS_USE_PKGNG=yes   # no: legacy pkg_* tools, yes: the new generation package (pkgng)
+PKGSYS_CMD_PKG_INFO='pkg info' # Corresponding command for pkg_info
+PKGSYS_CMD_PKG_CREATE='pkg create'     # Corresponding command for pkg_create
+PKGSYS_CMD_PKG_DELETE='pkg delete'     # Corresponding command for pkg_delete
+PKGSYS_CMD_PKG_ADD='pkg add'   # Corresponding command for pkg_add
 PKGSYS_AVR_REFETCH_TIMES_PER_SITE=1    # Average number (integer) of retrials for retrieving package or distfiles per mirror site
 PKGSYS_AVR_REFETCH_TIMES_FOR_CHKSUMERR=2       #  Number (integer) of retrials for check sum error in retrieving a package
 
+# ============= Check implementation of the ports tree =============
+pkgsys_chk_ports_tree_implementation ()
+{
+       local var tmp_work
+       if [ ! -d "${PORTSDIR}" ]
+       then
+               message_echo "ERROR: Ports directory ${PORTSDIR} is not found." >&2
+               exit 1
+       fi
+       if [ ! -e "${PORTSDIR}/Makefile" -o ! -e "${PORTSDIR}/Mk/bsd.port.mk" ]
+       then
+               message_echo "ERROR: Ports tree ${PORTSDIR} is missing, broken or incompatible." >&2
+               exit 1
+       fi
+}
+
 # ============= System defined value for the ports/packages =============
 pkgsys_sysvar ()
 {
@@ -23,7 +39,7 @@ pkgsys_sysvar ()
        tmp_work=${TMPDIR}/pkgsys_sysvar:work
        rm -rf "$tmp_work"
        mkdir "$tmp_work"
-       make -C "$tmp_work" -f "${PORTSDIR}/Mk/bsd.port.mk" -V "$var"
+       make -C "$tmp_work" -f "${PORTSDIR}/Mk/bsd.port.mk" -V "$var" 2> /dev/null
 }
 
 # ============= Get the file name of package check sum file =============
@@ -42,6 +58,12 @@ pkgsys_is_pkgtool ()
        esac
 }
 
+# ============= Check whether a port is indispensable for package operations =============
+pkgsys_is_necessary_pkgtool ()
+{
+       [ x"$WITH_PKGNG" = x'yes' -a "x$1" = x'ports-mgmt/pkg' ]
+}
+
 # ============= Check whether the dialog for selecting port options is dialog4ports =============
 pkgsys_is_dialog4ports_used ()
 {
@@ -147,12 +169,22 @@ pkgsys_fetch_legacy_remote ()
        [ -d "${PKGREPOSITORY}" ] || mkdir -p "${PKGREPOSITORY}"
        if [ -e "${PKGREPOSITORY}/$pkg.tbz" ]
        then
-               fetchedMD5=`md5 "${PKGREPOSITORY}/$pkg.tbz" | sed -E "s/^[^=]*=[[:space:]]*(.*)/\1/"`
-               if [ "x$fetchedMD5" = "x$validMD5" ]
+               if [ -e "${PKGREPOSITORY}/$pkg.md5=$validMD5.tbz" ]
+               then
+                       fetchedMD5=`md5 "${PKGREPOSITORY}/$pkg.md5=$validMD5.tbz" | sed -E "s/^[^=]*=[[:space:]]*(.*)/\1/"`
+                       [ "x$fetchedMD5" = "x$validMD5" ] || rm "${PKGREPOSITORY}/$pkg.md5=$fetchedMD5.tbz"
+               fi
+               if [ -e "${PKGREPOSITORY}/$pkg.md5=$validMD5.tbz" ]
                then
-                       needs_fetch=no
+                       ln -f "${PKGREPOSITORY}/$pkg.md5=$fetchedMD5.tbz" "${PKGREPOSITORY}/$pkg.tbz"
                else
-                       mv "${PKGREPOSITORY}/$pkg.tbz" "${PKGREPOSITORY}/$pkg.md5=$fetchedMD5.tbz"
+                       fetchedMD5=`md5 "${PKGREPOSITORY}/$pkg.tbz" | sed -E "s/^[^=]*=[[:space:]]*(.*)/\1/"`
+                       if [ "x$fetchedMD5" = "x$validMD5" ]
+                       then
+                               needs_fetch=no
+                       else
+                               mv "${PKGREPOSITORY}/$pkg.tbz" "${PKGREPOSITORY}/$pkg.md5=$fetchedMD5.tbz"
+                       fi
                fi
        fi
        if [ $needs_fetch = yes ]
@@ -214,15 +246,21 @@ pkg_is_dependency_of_a_legacypkg_latest ()
        :
 }
 
+# ============= Check whether legacy package tools are available =============
+pkgsys_is_legacy_tool_available ()
+{
+       which -s pkg_info
+}
+
 # ============= Define wrapper commands for hiding the differences between pkg_* tools and pkgng =============
 pkgsys_def_pkgtools ()
 {
-       if [ "${DBDIR}/WITH_PKGNG" -nt /etc/make.conf ]
+       if [ "${DBDIR}/WITH_PKGNG" -nt /etc/make.conf -o \( -e "${DBDIR}/WITH_PKGNG" -a ! -e /etc/make.conf \) ]
        then
                PKGSYS_USE_PKGNG=`cat "${DBDIR}/WITH_PKGNG"`
        else
                PKGSYS_USE_PKGNG=`pkgsys_sysvar WITH_PKGNG | tr '[:upper:]' '[:lower:]'`
-               if [ -d "${DBDIR}" ]
+               if [ -d "${DBDIR}" ] && misc_is_superuser_privilege
                then
                        echo "$PKGSYS_USE_PKGNG" > ${DBDIR}/WITH_PKGNG.tmp
                        mv "${DBDIR}/WITH_PKGNG.tmp" "${DBDIR}/WITH_PKGNG"
@@ -237,7 +275,18 @@ pkgsys_def_pkgtools ()
                PKGSYS_CMD_PKG_ADD='pkg add'
                pkg_is_tool_available ()
                {
-                       which -a pkg | grep -v '^/usr/sbin/pkg$' | grep -q '/sbin/pkg$'
+                       if [ -x /usr/sbin/pkg ]
+                       then
+                               pkg -N 2> /dev/null && return
+                               env ASSUME_ALWAYS_YES=yes pkg bootstrap -f
+                               pkg_is_tool_available
+                       else
+                               which -s pkg && return
+                       fi
+               }
+               pkg_info_Ea ()
+               {
+                       pkg info -qa 2> /dev/null
                }
                pkg_info_qoa ()
                {
@@ -249,7 +298,7 @@ pkgsys_def_pkgtools ()
 #              }
                pkg_info_qoX ()
                {
-                       pkg info -qoX "$@" 2> /dev/null
+                       pkg info -qox "$@" 2> /dev/null
                }
                pkg_info_qO ()
                {
@@ -283,6 +332,33 @@ pkgsys_def_pkgtools ()
                {
                        pkg info -Ex "$@" 2> /dev/null
                }
+               pkg_info_qL ()
+               {
+                       pkg info -ql "$@" 2> /dev/null
+               }
+               pkg_check_sanity ()
+               {
+                       local pkg tmp_stdout tmp_stderr
+                       pkg=$1
+                       tmp_stdout=${TMPDIR}/pkgng:pkg_check_sanity:stdout
+                       tmp_stderr=${TMPDIR}/pkgng:pkg_check_sanity:stderr
+                       pkg check -s "$pkg" > $tmp_stdout 2> $tmp_stderr || :
+                       grep '^[^:]*: checksum mismatch for ' "$tmp_stderr" | sed 's/^[^:]*: checksum mismatch for //' || :
+                       if grep -q '^pkg: .*: No such file or directory$' "$tmp_stderr"
+                       then
+                               pkg info -ql "$pkg" | while read filepath
+                               do
+                                       [ -e "$filepath" ] || echo "$filepath"
+                               done
+                       fi
+                       :
+               }
+               pkg_which ()
+               {
+                       local filepath
+                       filepath=$1
+                       pkg which -q "$filepath" 2> /dev/null
+               }
                pkg_info_gen_pkg_origin_table ()
                {
                        pkg query -g '%n-%v\t%o' \* 2> /dev/null > ${DBDIR}/installed_ports:pkg_vs_origin.tbl
@@ -294,6 +370,8 @@ pkgsys_def_pkgtools ()
                pkg_delete_f ()
                {
                        pkg delete -fqy "$@"
+                       pkg info -e "$@" || return 0    # Countermeasure for a bug found for pkg-1.3.4 (at least not until 1.2.7_4)
+                       pkg delete -fy "$@"
                }
                pkg_add_tools ()
                {
@@ -337,13 +415,15 @@ pkgsys_def_pkgtools ()
                {
                        pkg_add_f "$@"
                }
-               pkg_inst_remote ()
+               pkg_inst_remote_fetch ()
                {
-                       local pkg pkgarc
+                       local pkg mode pkgarc
                        pkg=$1
+                       mode=$2
                        tmp_extract=${TMPDIR}/pkgng:pkg_inst_remote:extract
                        pkg fetch -yU "$pkg" || return
                        pkgarc=`pkgsys_pkgname_to_pkgarc "${PKGNG_PKG_CACHEDIR}/All" "$pkg"` || return
+                       [ "x$mode" = xnodepschk ] && return
                        rm -rf "$tmp_extract"
                        mkdir "$tmp_extract"
                        tar xf "$pkgarc" -C "$tmp_extract" +MANIFEST
@@ -357,24 +437,40 @@ pkgsys_def_pkgtools ()
                                        return 1
                                fi
                        done
+                       :
+               }
+               pkg_inst_remote ()
+               {
+                       local pkg mode pkgarc
+                       pkg=$1
+                       mode=$2
+                       pkg_inst_remote_fetch "$pkg" "$mode" || return
+                       pkgarc=`pkgsys_pkgname_to_pkgarc "${PKGNG_PKG_CACHEDIR}/All" "$pkg"` || return
                        env ASSUME_ALWAYS_YES=YES pkg add "$pkgarc"
                }
-               pkg_inst_remote_wild ()
+               pkg_inst_remote_wild_fetch ()
                {
                        local pkg mode pkgarc
                        pkg=$1
                        mode=$2
                        if pkg_is_tool_available
                        then
-                               pkg_inst_remote "$pkg" && return
+                               pkg_inst_remote "$pkg" "$mode" && return
                        fi
+                       pkgsys_is_legacy_tool_available || return
                        message_echo "INFO: Trying to use a legacy package and convert it to pkgng."
                        pkgsys_fetch_legacy_remote "$pkg" || return
                        pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
-                       if [ "x$mode" != xnodepschk ]
-                       then
-                               pkg_is_dependency_of_a_legacypkg_latest "$pkgarc" || return
-                       fi
+                       [ "x$mode" = xnodepschk ] && return
+                       pkg_is_dependency_of_a_legacypkg_latest "$pkgarc"
+               }
+               pkg_inst_remote_wild ()
+               {
+                       local pkg mode pkgarc
+                       pkg=$1
+                       mode=$2
+                       pkg_inst_remote_wild_fetch "$pkg" "$mode" || return
+                       pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
                        pkg_add -ifF "$pkgarc" || return
                        message_echo "INFO: Trying to convert the installed legacy package to pkgng."
                        pkg2ng || :
@@ -399,7 +495,8 @@ pkgsys_def_pkgtools ()
                        PKGNG_AUTODEPS=NO
                        PKGNG_PORTAUDIT_SITE='http=//portaudit.FreeBSD.org/auditfile.tbz'
                        # Load configuration for pkg(1)
-                       pkg_conf=`pkg query %Fp pkg | grep '/etc/pkg\.conf\.sample$' | sed 's/\.sample$//'`
+                       pkg_conf=`pkg query %Fp pkg 2> /dev/null | grep '/etc/pkg\.conf\.sample$' | sed 's/\.sample$//'` || :
+                       [ -n "$pkg_conf" ] || pkg_conf=${MYPREFIX}/etc/pkg.conf
                        grep -v -e '^[[:space:]]*#' -e '^[[:space:]]*$' "$pkg_conf" 2> /dev/null \
                                | grep -e '^[[:space:]]*[A-Z0-9_]*[[:space:]]*:[[:space:]]*.*' \
                                | while read srcline
@@ -413,23 +510,42 @@ pkgsys_def_pkgtools ()
                }
                pkg_rescue_tools ()
                {
-                       local packagepath checksumpath pkgname
+                       local packagepath checksumpath pkgname is_successful
                        packagepath=`pkgsys_get_backup_pkg ports-mgmt/pkg` && \
                                pkg_add_tools "$packagepath" && return
-                       [ -x /usr/local/sbin/pkg ] && return
-                       message_echo "WARNING: WITH_PKGNG is set, but pkgng is missing. It is installed now." >&2
-                       [ -x /usr/sbin/pkg ] && /usr/sbin/pkg && return
+                       pkg_is_tool_available && return
+                       message_echo "WARNING: WITH_PKGNG is set, but pkgng is still missing. It is installed now." >&2
                        pkgsys_ready_checksum_file || return
+                       message_echo "INFO: Installing pkgng by legacy package tool."
                        checksumpath=`pkgsys_ready_checksum_file__fetched_file`
                        pkgname=`sed 's/^MD5[[:space:]]*(//;s/\.tbz)[[:space:]]*=[^=]*$//' "$checksumpath" \
                                | grep -m 1 -E -e "^pkg-[0-9]"` || :
-                       [ -z "$pkgname" ] && pkg_inst_remote_wild "$pkgname" nodepschk && return
-                       make -C "${PORTSDIR}/ports-mgmt/pkg" install clean && return
-                       message_echo "ERROR: WITH_PKGNG is set, but pkgng is missing. It is installed now." >&2
-                       :
+                       [ -n "$pkgname" ] && pkg_inst_remote_wild "$pkgname" nodepschk && return
+                       message_echo "INFO: Failed by package, so installing pkgng by port."
+                       grep -v '^[[:space:]]*WITH_PKGNG=' /etc/make.conf > ${TMPDIR}/make.conf
+                       echo WITHOUT_PKGNG=yes >> ${TMPDIR}/make.conf
+                       ( set -e
+                               unset WITH_PKGNG
+                               unset WITHOUT_PKGNG
+                               
+                               message_echo "INFO: Attempting deinstallation of ports-mgmt/pkg to make sure."
+                               env __MAKE_CONF="${TMPDIR}/make.conf" make -C "${PORTSDIR}/ports-mgmt/pkg" deinstall || :
+                               message_echo "INFO: Attempting (re)installation by ports-mgmt/pkg."
+                               env __MAKE_CONF="${TMPDIR}/make.conf" make -C "${PORTSDIR}/ports-mgmt/pkg" reinstall clean
+                       ) && {
+                               pkg2ng || :
+                               pkg_is_tool_available
+                       }
                }
-               pkg_rescue_tools
+               if ! pkg_rescue_tools
+               then
+                       message_echo "WARNING: Pkgng is still missing, but continuing for the time being." >&2
+               fi
                pkg_loadconf
+       elif ! pkgsys_is_legacy_tool_available
+       then
+               message_echo "ERROR: Pkgng is disabled although the legacy packages tools are unavailable. Resolve the problem manually." >&2
+               exit 1
        else
                unset WITH_PKGNG
                PKGSYS_USE_PKGNG=no
@@ -439,7 +555,11 @@ pkgsys_def_pkgtools ()
                PKGSYS_CMD_PKG_ADD='pkg_add'
                pkg_is_tool_available ()
                {
-                       :
+                       pkgsys_is_legacy_tool_available
+               }
+               pkg_info_Ea ()
+               {
+                       pkg_info -Ea 2> /dev/null
                }
                pkg_info_qoa ()
                {
@@ -485,6 +605,26 @@ pkgsys_def_pkgtools ()
                {
                        pkg_info -Ex "$@" 2> /dev/null
                }
+               pkg_info_qL ()
+               {
+                       pkg_info -qL "$@" 2> /dev/null
+               }
+               pkg_check_sanity ()
+               {
+                       local pkg tmp_stdout tmp_stderr
+                       pkg=$1
+                       tmp_stdout=${TMPDIR}/pkgng:pkg_check_sanity:stdout
+                       tmp_stderr=${TMPDIR}/pkgng:pkg_check_sanity:stderr
+                       pkg_info -qg "$pkg" > $tmp_stdout 2> $tmp_stderr || :
+                       grep ' fails the original MD5 checksum$' "$tmp_stdout" | sed 's/ fails the original MD5 checksum$//' || :
+                       grep "^pkg_info: .* doesn't exist$" "$tmp_stderr" | sed -E "s/^pkg_info: (.*) doesn't exist$/\1/" || :
+               }
+               pkg_which ()
+               {
+                       local filepath
+                       filepath=$1
+                       pkg_info -qW "$filepath" 2> /dev/null
+               }
                pkg_info_gen_pkg_origin_table ()
                {
                        pkg_info -aE 2> /dev/null | while read pkg
@@ -509,18 +649,32 @@ pkgsys_def_pkgtools ()
                {
                        pkg_add -ifF "$@"
                }
-               pkg_inst_remote ()
+               pkg_inst_remote_fetch ()
                {
-                       local pkg pkgarc
+                       local pkg mode pkgarc
                        pkg=$1
+                       mode=$2
                        pkgsys_fetch_legacy_remote "$pkg" || return
                        pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
-                       pkg_is_dependency_of_a_legacypkg_latest "$pkgarc" || return
+                       [ "x$mode" = xnodepschk ] && return
+                       pkg_is_dependency_of_a_legacypkg_latest "$pkgarc"
+               }
+               pkg_inst_remote ()
+               {
+                       local pkg mode pkgarc
+                       pkg=$1
+                       mode=$2
+                       pkg_inst_remote_fetch "$pkg" "$mode" || return
+                       pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
                        pkg_add "$pkgarc" || return
                }
+               pkg_inst_remote_wild_fetch ()
+               {
+                       pkg_inst_remote_fetch "$1" "$2"
+               }
                pkg_inst_remote_wild ()
                {
-                       pkg_inst_remote "$1"
+                       pkg_inst_remote "$1" "$2"
                }
                pkg_loadconf () { :; }
                pkg_rescue_tools () { :; }
@@ -545,8 +699,8 @@ pkgsys_pkg_info_qO_init ()
        origin=$1
        tmppkg=${TMPDIR}/pkgsys_pkg_info_qO_init::pkg
        origin_regexp=`str_escape_regexp "$origin"`
-       { sed -n -E "/[[:space:]]$origin_regexp$/p" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null || :; } \
-               | cut -f 1 > $tmppkg
+       sed -n -E "/[[:space:]]$origin_regexp$/p" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null \
+               | cut -f 1 > $tmppkg || :
        npkgs=`wc -l < $tmppkg`
        if [ $npkgs -gt 0 ]
        then
@@ -579,17 +733,21 @@ pkgsys_init_pkg_orig_by_ambiguous_matching ()
        ambsuffix=
        norigins=0
        len_pkg=`echo -n "$pkg" | wc -c`
-       while [ $len_pkg -gt 0 ]
-       do
-               pkg_regexp=`str_escape_regexp "$pkg"`$ambsuffix
-               grep -E "^${pkg_regexp}[[:space:]]" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null \
-                       | cut -f 2 > $tmporigin
-               norigins=`wc -l < $tmporigin`
-               [ $norigins -gt 0 ] && break
-               len_pkg=$(($len_pkg-1))
-               pkg=`echo -n "$pkg" | head -c $len_pkg`
-               ambsuffix='[a-zA-Z0-9.,_+-]*'
-       done
+       if [ $len_pkg -gt 0 ]
+       then
+               while :
+               do
+                       pkg_regexp=`str_escape_regexp "$pkg"`$ambsuffix
+                       grep -E "^${pkg_regexp}[[:space:]]" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null \
+                               | cut -f 2 > $tmporigin
+                       norigins=`wc -l < $tmporigin`
+                       [ $norigins -gt 0 ] && break
+                       ambsuffix='[a-zA-Z0-9.,_+-]*'
+                       len_pkg=$(($len_pkg-1))
+                       [ $len_pkg -gt 0 ] || break
+                       pkg=`echo -n "$pkg" | head -c $len_pkg`
+               done
+       fi
        [ $norigins -eq 1 ] || return
        cat "$tmporigin"
 }
@@ -646,15 +804,15 @@ pkgsys_eval_ports_glob ()
                shift
                expr "x$glob" : '^x-' > /dev/null 2>&1 && continue
                glob_regexp=`str_convert_portsglob_to_regexp_pattern "$glob"`
-               if expr "$glob" : '[^/][^/]*\/[^/][^/]*$' > /dev/null 2>&1
+               if expr "$glob" : '.*/' > /dev/null 2>&1
                then
                        grep -E "$glob_regexp" "$origlist" 2>&1 || :
                        {
                                pkg_info_qoa
                                cut -f 2 "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null
-                       } | grep -E "$glob" 2>&1 || :
+                       } | grep -E "$glob_regexp" 2>&1 || :
                else
-                       if expr "$glob" : '^[a-z][a-zA-Z0-9+-]*[a-zA-Z0-9+]$' > /dev/null 2>&1 && \
+                       if expr "$glob" : '^[a-z][a-zA-Z0-9_.+-]*[a-zA-Z0-9_.+]$' > /dev/null 2>&1 && \
                                [ `expr "$glob" : '.*-[0-9]' 2>&1` -eq 0 ]
                        then
                                glob_regexp2=`expr "$glob_regexp" : '\(.*\)\$$' 2>&1`'-[0-9]'
@@ -667,8 +825,8 @@ pkgsys_eval_ports_glob ()
                                sed -n ${index}p "$origlist"
                        done || :
                        glob_regexp2=`expr "$glob_regexp" : '\(.*\)\$$' 2>&1`'[[:space:]]'
-                       { sed -n -E "/$glob_regexp2/p" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null || :; } \
-                               | cut -f 2
+                       sed -n -E "/$glob_regexp2/p" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null \
+                               | cut -f 2 || :
                        pkg_info_qoX "$glob_regexp" || :
                fi
        done | sort -u
@@ -677,7 +835,7 @@ pkgsys_eval_ports_glob ()
 # ============= Create a back-up package archive =============
 pkgsys_create_backup_pkg ()
 {
-       local pkgname dstdir origin backup_pkg_old origin_regexp pkgname_ptn backup_pkg pkgpath
+       local pkgname dstdir origin backup_pkg_old pkgname_ptn backup_pkg dbpath pkgpath origin_regexp
        pkgname=$1
        dstdir=$2
        rm -rf "${TMPDIR}"/package.tmp
@@ -700,6 +858,9 @@ pkgsys_create_backup_pkg ()
                message_echo "WARNING: Failed to create backup package for $pkgname." >&2
                return 1
        fi
+       dbpath=${DBDIR}/requires/$origin
+       [ -d "$dbpath" ] || dbpath=${DBDIR}/initial/$origin
+       pkg_info_qL > $dbpath/previously_installed_files
        [ -d "$dstdir" ] || mkdir -p "$dstdir"
        mv "${TMPDIR}/package.tmp/$backup_pkg" "$dstdir"
        pkgpath=$dstdir/$backup_pkg
@@ -739,7 +900,7 @@ pkgsys_delete_backup_pkg ()
 # ============= Get an existing package archive path for a port origin =============
 pkgsys_get_backup_pkg ()
 {
-       local origin origin_regexp
+       local origin tmpnewest origin_regexp
        origin=$1
        tmpnewest=${TMPDIR}/pkgsys_get_backup_pkg::newest
        origin_regexp=`str_escape_regexp "$origin"`
@@ -755,6 +916,16 @@ pkgsys_get_backup_pkg ()
        cat "$tmpnewest" 2> /dev/null
 }
 
+# ============= Get a file list to be restored by the current backup package for a port origin =============
+pkgsys_get_restored_files_by_backup_pkg ()
+{
+       local origin dbpath
+       origin=$1
+       dbpath=${DBDIR}/requires/$origin
+       [ -d "$dbpath" ] || dbpath=${DBDIR}/initial/$origin
+       cat "$dbpath/previously_installed_files" 2> /dev/null || :
+}
+
 # ============= Get a package name from a package archive file name =============
 pkgsys_pkgarc_to_pkgname ()
 {
@@ -790,7 +961,7 @@ pkgsys_eval_ports_glob_even_if_nonexistent ()
        glob_pattern=$1
        {
                pkgsys_eval_ports_glob "$glob_pattern" 2> /dev/null || :
-               echo "$glob_pattern" | grep '^[a-z][a-z]*/[a-zA-Z0-9_+-][a-zA-Z0-9_+-]*$' || :
+               echo "$glob_pattern" | grep '^[a-z][a-z]*/[a-zA-Z0-9_.+-][a-zA-Z0-9_.+-]*$' || :
        } | grep -v -e '^$' | sort -u
 }
 
@@ -837,10 +1008,10 @@ pkgsys_eval_installed_pkgs_globs ()
        done < $tmp_evaluated
 }
 
-# ============= Get conflicting packages of a port =============
-pkgsys_get_conflicting_pkgs ()
+# ============= Get glob patterns of conflicting packages of a port =============
+pkgsys_get_conflicting_pkgs_patterns ()
 {
-       local origin mode conflicts
+       local mode origin conflicts
        mode=$1
        origin=$2
        conflicts=`database_query_get_makevar_val "$origin" CONFLICTS`
@@ -852,7 +1023,85 @@ pkgsys_get_conflicting_pkgs ()
                conflicts=$conflicts' '`database_query_get_makevar_val "$origin" CONFLICTS_INSTALL`
                ;;
        esac
-       pkg_info_Eg $conflicts > ${TMPDIR}/pkgsys_get_conflicting_pkgs::conflicts || :
-       cat "${TMPDIR}/pkgsys_get_conflicting_pkgs::conflicts"
-       [ `wc -l < ${TMPDIR}/pkgsys_get_conflicting_pkgs::conflicts` -gt 0 ]
+       echo "$conflicts" | tr ' ' '\n' | grep -v '^$' || :
+}      
+
+# ============= Get conflicting installed packages of a port =============
+pkgsys_get_conflicting_installed_pkgs ()
+{
+       local mode origin tmp_conflicts
+       mode=$1
+       origin=$2
+       tmp_conflicts=${TMPDIR}/pkgsys_get_conflicting_installed_pkgs::conflicts
+       pkg_info_Eg `pkgsys_get_conflicting_pkgs_patterns "$mode" "$origin"` > $tmp_conflicts || :
+       cat "$tmp_conflicts"
+       [ `wc -l < $tmp_conflicts` -gt 0 ]
 }      
+
+# ============= Check whether a package conflicts with a port =============
+pkgsys_chk_conflict_by_a_pkg ()
+{
+       local mode origin pkg tmp_conflicts_ptn
+       mode=$1
+       origin=$2
+       pkg=$3
+       tmp_conflicts_ptn=${TMPDIR}/pkgsys_chk_conflict_by_a_pkg::conflicts_ptn
+       pkgsys_get_conflicting_pkgs_patterns "$mode" "$origin" \
+               | str_convert_glob_to_regexp_pattern > $tmp_conflicts_ptn
+       echo "$pkg" | grep -q -E -f "$tmp_conflicts_ptn"
+}      
+
+# ============= Check whether installed files are lost or broken for a package =============
+pkgsys_sanitychk_pkgcontents ()
+{
+       local pkg var_is_reinstall_encouraged _is_reinstall_encouraged tmp_sanity nlines iline src filename icol filename_esc pkg_owner origin
+       pkg=$1
+       var_is_reinstall_encouraged=$2
+       tmp_sanity=${TMPDIR}/pkgsys_sanitychk_pkgcontents:sanity
+       pkg_check_sanity "$pkg" > $tmp_sanity || :
+       eval "$var_is_reinstall_encouraged=no"
+       [ `wc -l < $tmp_sanity` -eq 0 ] && return
+       nlines=`wc -l < $tmp_sanity`
+       iline=1
+       _is_reinstall_encouraged=no
+       while [ $iline -le $nlines ]
+       do
+               filename=`sed -n ${iline}p "$tmp_sanity"`
+               iline=$(($iline+1))
+               if [ ! -e "$filename" ]
+               then
+                       _is_reinstall_encouraged=yes
+                       break
+               fi
+               if expr "$filename" : '.*/include/.*' > /dev/null
+               then
+                       _is_reinstall_encouraged=yes
+                       break
+               fi
+               filename_esc=`str_escape_regexp "$filename"`
+               if file "$filename" | sed -E "s/^$filename_esc:[[:space:]]//" | grep -q '^ELF '
+               then
+                       _is_reinstall_encouraged=yes
+                       break
+               fi
+               pkg_owner=`pkg_which "$filename"`
+               if [ "$pkg" != "$pkg_owner" ]
+               then
+                       _is_reinstall_encouraged=yes
+                       break
+               fi
+       done
+       eval "$var_is_reinstall_encouraged=\$_is_reinstall_encouraged"
+       origin=`pkg_info_qo "$pkg"`
+       if [ $opt_batch_mode = no ]
+       then
+               message_echo "[$pkg ($origin)]"
+               sed 's/^/  /' "$tmp_sanity"
+               message_echo
+       else
+               pkg_replace=`str_escape_replaceval "$pkg"`
+               origin_replace=`str_escape_replaceval "$origin"`
+               sed "s/^/$pkg_replace\\\\$origin_replace\\\\$_is_reinstall_encouraged\\\\/" "$tmp_sanity" | tr '\\' '\t'
+       fi
+       return 1
+}