Skip to content

Instantly share code, notes, and snippets.

@ruario
Last active January 29, 2019 15:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ruario/11246041 to your computer and use it in GitHub Desktop.
Save ruario/11246041 to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# Version: 1.2
#
# This script provides a method for tracking software installed from
# source. Run it as follows for more information:
#
# pkgtrack -h
#
# Copyright 2018 Ruari Odegaard, Oslo, Norway
# All rights reserved.
#
# Redistribution and use of this script, with or without modification,
# is permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
helptext () {
cat << EOH
Script usage:
$OWNNAME [options] [installation command]
Script options:
-h, --help Print this help text.
-n, --name [package name] Specify the name of the package,
otherwise the parent directory
name will be used.
-l, --list List installed packages
-s, --show-contents Show a list of files contained
within the package.
-ip, --install-package Install a previously backed up
package.
-id, --install-directory Install the contents of the current
directory to root (/) and log it.
-u, --uninstall Remove a package you installed
previously.
-b, --backup Create a backup archive of a
previously installed package.
Examples:
\$ $OWNNAME make install
\$ $OWNNAME --name foo ./install-foo.sh
\$ $OWNNAME --list
\$ $OWNNAME -n foo -s
\$ $OWNNAME --uninstall -n foo
\$ $OWNNAME -b -n foo
\$ $OWNNAME --install-package -n foo.pkg.tar.gz
\$ $OWNNAME --install-directory --name foo
EOH
}
noname () {
printf "\n\"$PKGNAME\" is not installed, specify a valid name with the \"--name\" option.\n\n" >&2
}
extract_dirs () {
sed 's,\(.*\)/.*,\1,' "$1" | sort -u | \
while read d; do
while echo "$d" | grep -vx .; do
d=$(dirname "$d")
done
done | sort -ur | grep -vxE \
-e '(/s?bin|/etc|/lib(32|64)?|/opt|/var)' \
-e '/usr((/local)?(/s?bin|/doc|/include|/info|/lib(32|64)?|/man(/man[1-9n])?|/share(/doc|/info|/man(/man[1-9n])?)?|/src)?)?' \
-e '/usr/local/etc'
}
removefiles () {
while read f; do
# '-e' alone would not find broken symlinks
if [ -e "$f" -o -h "$f" ]; then
if [ -d "$f" ]; then
if ! ls -A "$f" | grep -q ^; then
# Don't remove a symlink pointing to a directory, as it could have
# been created by the user or the distribution
if [ ! -h "$f" ]; then
rmdir -v "$f"
fi
fi
else
rm -v "$f"
fi
fi
done
}
listfiles () {
ROOTDIRS=$(find / -maxdepth 1 -type d -regextype posix-egrep -regex '/(etc|s?bin|lib.*|opt|usr)')
find $ROOTDIRS ! -type d -print > $1
}
# Handle options
SHOWHELP=n
PKGUNINSTALL=n
PKGLIST=n
PKGSHOW=n
PKGINSTALL=n
PKGBACKUP=n
PKGINSTDIR=n
while [ 0 ]; do
if [ "$1" = "-h" -o "$1" = "--help" ]; then
SHOWHELP=y
shift 1
elif [ "$1" = "-n" -o "$1" = "--name" ]; then
PKGNAME="$2"
shift 2
elif [ "$1" = "-u" -o "$1" = "--uninstall" ]; then
shift 1
PKGUNINSTALL=y
elif [ "$1" = "-l" -o "$1" = "--list" ]; then
shift 1
PKGLIST=y
elif [ "$1" = "-s" -o "$1" = "--show-contents" ]; then
shift 1
PKGSHOW=y
elif [ "$1" = "-ip" -o "$1" = "--install-package" ]; then
shift 1
PKGINSTALL=y
elif [ "$1" = "-id" -o "$1" = "--install-directory" ]; then
shift 1
PKGINSTDIR=y
elif [ "$1" = "-b" -o "$1" = "--backup" ]; then
shift 1
PKGBACKUP=y
else
break
fi
done
OWNNAME=$(basename "$0")
if [ "$SHOWHELP" = "y" ]; then
helptext
exit 0
fi
if [ "$PKGLIST" = "y" ]; then
ls /var/lib/footprints | grep "$1"
exit 0
fi
if [ -z "$PKGNAME" ]; then
PKGNAME=$(basename "$(pwd)")
echo "The \"--name\" option was not used so the package name has been set to the name of the directory: $PKGNAME" >&2
fi
if echo "$PKGNAME" | grep -Fq '/'; then
echo 'The package name must not contain "/". Use "--name" to specify another name.' >&2
exit 1
fi
if [ "$PKGSHOW" = "y" ]; then
if [ -r "/var/lib/footprints/$PKGNAME" ]; then
echo "@${PKGNAME}:"
cat "/var/lib/footprints/$PKGNAME"
exit 0
else
noname
helptext
exit 1
fi
fi
if [ "$PKGINSTALL" = "y" ]; then
if [ -r "$PKGNAME" ]; then
tar -C / -xvf "$PKGNAME"
exit 0
else
noname
helptext
exit 1
fi
fi
if [ "$PKGINSTDIR" = "y" ]; then
if [ -r "/var/lib/footprints/$PKGNAME" ]; then
echo "$PKGNAME is already installed" >&2
helptext
exit 1
else
echo "Installing ${PKGNAME}:"
mkdir -p /var/lib/footprints
find . ! -type d | grep -vF "./var/lib/footprints/$PKGNAME" | \
cpio --quiet -pmdv / 2>&1 | sed 's,^//\.,,' | tee "/var/lib/footprints/$PKGNAME"
echo "/var/lib/footprints/$PKGNAME" | tee -a "/var/lib/footprints/$PKGNAME"
exit 0
fi
fi
if [ "$PKGBACKUP" = "y" ]; then
if [ -r "/var/lib/footprints/$PKGNAME" ]; then
if command -v xz >/dev/null 2>&1; then
EXT=xz
elif command -v bzip2 >/dev/null 2>&1; then
EXT=bz2
else
EXT=gz
fi
sed 's,^/,,' "/var/lib/footprints/$PKGNAME" | tar -C / --format=pax -cvvaf "${PKGNAME}.pkg.tar.$EXT" -T-
echo "Created: ${PKGNAME}.pkg.tar.$EXT"
exit 0
else
noname
helptext
exit 1
fi
fi
if [ "$PKGUNINSTALL" = "y" ]; then
if [ -r "/var/lib/footprints/$PKGNAME" ]; then
PKGUNINSTALL_LIST=$(mktemp -t remove.XXXXXX)
cat "/var/lib/footprints/$PKGNAME" > "$PKGUNINSTALL_LIST"
extract_dirs "/var/lib/footprints/$PKGNAME" >> "$PKGUNINSTALL_LIST"
removefiles < "$PKGUNINSTALL_LIST"
rm -f "$PKGUNINSTALL_LIST"
exit 0
else
noname
helptext
exit 1
fi
fi
if [ -z "$1" ]; then
echo "You must specify an installation command (e.g. \"$OWNNAME make install\")" >&2
helptext
exit 1
fi
# The original tracking script, before I added all the fancy stuff above! ;)
BEFORE=$(mktemp -t before.XXXXXX)
AFTER=$(mktemp -t after.XXXXXX)
listfiles $BEFORE
$@
listfiles $AFTER
mkdir -p /var/lib/footprints
diff --normal $BEFORE $AFTER | sed -n 's/^> //p' > "/var/lib/footprints/$PKGNAME"
echo "/var/lib/footprints/$PKGNAME" >> "/var/lib/footprints/$PKGNAME"
rm -f $BEFORE $AFTER
echo "Created log: /var/lib/footprints/$PKGNAME"
@ruario
Copy link
Author

ruario commented Apr 24, 2014

Save the above somewhere in your path. Then just preface it to any install command you wish to track, e.g.:

pkgtrack make install

or perhaps:

pkgtrack --name virtualbox-4.3.10_93012 ./VirtualBox-4.3.10-93012-Linux_amd64.run

A suitably name log file will be created in /var/lib/footprints/, listing all the files that where installed. This log can be used to remove those files or create a backup of the installation using and archiver like tar, cpio or zip.

@ruario
Copy link
Author

ruario commented Apr 24, 2014

You may notice that the script only logs files that are created by the install process, not directories. This is done intentionally as it keeps the logs from being overly bloated and makes them easier to read.

Directories are far more likely to be shared between many applications, rather than being tied to the specific package you installed. Thus it is also a more accurate representation of the package contents.

@ruario
Copy link
Author

ruario commented Nov 14, 2018

See also createpkg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment