Update uninstall script.
authorSteve Youngs <steve@steveyoungs.com>
Tue, 21 Apr 2015 12:48:27 +0000 (22:48 +1000)
committerSteve Youngs <steve@steveyoungs.com>
Tue, 21 Apr 2015 12:48:27 +0000 (22:48 +1000)
With this changeset the uninstall script should be a lot more
robust. "sub-packages" are handled, directories are only removed if they
are empty, and something more proactive is done about setuid files.

* usr/lib/pkgusr/uninstall_package (usage): Reword it, taking into
account needing pkgname arg.
(check_suid): New.
(dry_run): Use it.
(run): Ditto.
Handle empty directories more intelligently.
Don't wipe out the .project file if uninstalling a "sub-pkg".

Signed-off-by: Steve Youngs <steve@steveyoungs.com>
usr/lib/pkgusr/uninstall_package

index c674e39..b885fa0 100755 (executable)
@@ -21,69 +21,116 @@ if [ $(id -u) -eq 0 ]; then
        exit 1
 fi
 
        exit 1
 fi
 
+pkg=$1
+
 usage()
 {
        cat<<EOF
 usage()
 {
        cat<<EOF
-USAGE: uninstall_package [now]
+USAGE: uninstall_package pgname [now]
+
+PGNAME is the name of the package.  Normally, this would be the same
+       as the pkgusr name, but can also be a group name.
 
 
-Unless you specify "now" as the 1st arg, nothing will actually
+Unless you specify "now" as the 2nd arg, nothing will actually
 be deleted.
 
 EOF
 }
 
 be deleted.
 
 EOF
 }
 
-pkg=$(whoami)
+
+check_suid()
+{
+       forall_direntries_from ${pkg} -not -user $(whoami) -fprint /tmp/${pkg}.suid
+       if [ -s /tmp/${pkg}.suid ]; then
+               HAVE_SUID=1
+       else
+               HAVE_SUID=0
+       fi
+}
 
 dry_run()
 {
 
 dry_run()
 {
-    forall_direntries_from ${pkg} -not -type d -exec echo rm -vf {} 2>/dev/null \;
-    suid=$(forall_direntries_from ${pkg} -not -user ${pkg})
-    if [ -n "${suid}" ]; then
-       echo '###'
-       echo '# There were setuid binaries found.  You _could_ use root'
-       echo '# to delete this package, but you run a very real risk of'
-       echo '# completely FUCKING UP your system.  Instead, run this:'
-       echo '#'
-       echo '#  forall_direntries_from ${pkg} -not -user ${pkg}'
-       echo '#'
-       echo '# and delete those files manually and individually'
-       echo '###'
-    fi
-    echo
-    echo Use: \"uninstall_package now\" to really remove this package.
-    echo Any errors will be redirected to /tmp/${pkg}.err
+       forall_direntries_from ${pkg} -not -type d -exec echo rm -vf {} 2>/dev/null \;
+       check_suid
+       if [ $HAVE_SUID -eq 1 ]; then
+               echo ******************** S U I D ***********************
+               echo Detected setuid files that must be dealt with before
+               echo this package can be safely removed.
+               echo
+               echo See: /tmp/${pkg}.suid
+               echo ******************** S U I D ***********************
+       fi
+       echo
+       echo Use: \`uninstall_package ${pkg} now\' to really remove this package.
+       echo Any errors will be redirected to /tmp/${pkg}.err
 }
 
 run()
 {
 }
 
 run()
 {
+       # Check for suid
+       check_suid
+       if [ $HAVE_SUID -eq 1 ]; then
+               echo 1>&2 ******************** S U I D ***********************
+               echo 1>&2 Detected setuid files that must be dealt with before
+               echo 1>&2 this package can be safely removed.
+               echo 1>&2
+               echo 1>&2 See: /tmp/${pkg}.suid
+               echo 1>&2 ******************** S U I D ***********************
+               exit 2
+       fi
+
        # Delete anything that isn't a directory
        forall_direntries_from ${pkg} \
        # Delete anything that isn't a directory
        forall_direntries_from ${pkg} \
-               -not -type d -exec rm -vf {} 2>>/tmp/${pkg}.err \;
+           -not -type d -exec rm -vf {} 2>>/tmp/${pkg}.err \;
+
        # Remove any empty directories, but ONLY empty directories
        # Remove any empty directories, but ONLY empty directories
-       forall_direntries_from ${pkg} \
-               -type d -empty -exec rmdir -v {} 2>>/tmp/${pkg}.err \;
+       dirlist=$(mktemp --tmpdir dirs.XXXXXXXX)
+       forall_direntries_from ${pkg} -type d -empty -fprint ${dirlist}
+       while [ -s ${dirlist} ]; do
+               while read dir; do
+                       rmdir -v ${dir} 2>>/tmp/${pkg}.err
+               done<${dirlist}
+               forall_direntries_from ${pkg} -type d -empty -fprint ${dirlist}
+       done
 
 
+       # Make sure there isn't anything left
        leftovers=$(forall_direntries_from ${pkg})
        if [ -s /tmp/${pkg}.err -a -n "${leftovers}" ]; then
                echo Errors were reported.  Please inspect /tmp/${pkg}.err
        leftovers=$(forall_direntries_from ${pkg})
        if [ -s /tmp/${pkg}.err -a -n "${leftovers}" ]; then
                echo Errors were reported.  Please inspect /tmp/${pkg}.err
+               exit 1
        else
        else
+               rm -f /tmp/${pkg}.err ${dirlist} /tmp/${pkg}.suid
+       fi
+
         # Bring ~/.project inline with reality
         # Bring ~/.project inline with reality
-        sed -i -e 's/\(Last_Updated: \).*$/\1Not Installed/' \
-                -e 's/\(Version: \).*$/\1Not Installed/' \
-               -e 's/\(Deps: \).*$/\1Not Installed/' ${HOME}/.project
-        awk '/^CONTENTS:/ { print; exit; } {print}' ${HOME}/.project > ${HOME}/.projtmp
-        echo "--------" >> ${HOME}/.projtmp
-        mv ${HOME}/.projtmp ${HOME}/.project
+       echo -n "Updating .project file... "
+       if [ ${pkg} = $(id -un) ]; then
+               sed -i -e 's/\(Last_Updated: \).*$/\1Not Installed/' \
+                   -e 's/\(Version: \).*$/\1Not Installed/' \
+                       -e 's/\(Deps: \).*$/\1Not Installed/' ${HOME}/.project
+               awk '/^CONTENTS:/ { print; exit; } {print}' ${HOME}/.project > \
+                   ${HOME}/.projtmp
+               echo "--------" >> ${HOME}/.projtmp
+               mv ${HOME}/.projtmp ${HOME}/.project
+       else
+               # doing a sub-pkg, just update-pkg-project
+               update-pkg-project $(whoami)
+       fi
+       echo "Done!"
         # We should be done.
        echo Package: ${pkg} successfully removed
         # We should be done.
        echo Package: ${pkg} successfully removed
-       rm -f /tmp/${pkg}.err
-    fi
 }
 
 }
 
-case $1 in
-        now) IGNORE_READDIR_RACE='-ignore_readdir_race'; run ;;
-       -h|--help|--usage|help|usage) usage ;;
-        *) dry_run|less ;;
-esac
+if [ ${pkg} != $(id -un) -a ${pkg} != $(id -gn) ]; then
+       usage
+       exit 0
+fi
+
+if [ "$2" = "now" ]; then
+       IGNORE_READDIR_RACE='-ignore_readdir_race' \
+       run
+else
+       dry_run|less
+fi
 
 exit 0
 
 exit 0