File: //usr/bin/dlocate
#!/bin/bash
# Original script by Jim Pick <jim@jimpick.com>, GPL'd of course
#
# Completely rewritten several times with many new features and
# enhancements (plus numerous patches and by others, see the changelog)
# by Craig Sanders <cas@taz.net.au>
DLOCATE="$0"
DLOCATEDB=/var/lib/dlocate/dlocatedb
DPKGLIST=/var/lib/dlocate/dpkg-list
DPKG_INFO=/var/lib/dpkg/info
COMPRESS_DLOCATEDB=0
GREP='grep'
[ -e /etc/default/dlocate ] && . /etc/default/dlocate
[ "$COMPRESS_DLOCATE" = "1" ] && GREP='zgrep'
function usage {
[ -n "$*" ] && printf "%s\n" "$*" > /dev/stderr && exit 1
cat <<__EOF__
Usage: dlocate [option...] [command] [PATTERN...]
Commands:
none PATTERN List records that match either package or files names
-S PATTERN List records that match filenames
-L package List all files in package
-l package Regexp-enhanced emulation of 'dpkg -l'
-s package Print package's status
--ls package 'ls -ldF' of all files in package
--du package 'du -sck' of all files in package
--conf package List conffiles in package
--lsconf package 'ls -ldF' of conffiles in package
--md5sum package List package's md5sums (if any)
--md5check package Check package's md5sums (if any)
--man package List package's man pages (if any)
--lsman package List full path/filenames of man pages
--lsbin package List full path/filenames of executable files
--lsdir package List only the directories in package
Output directory names only when searching for files
-K List installed kernel & related packages
-k detailed list of installed kernel & related packages
-- Stop processing commands and options. Remainder of
command-line is filename(s)/package-name(s)
The -l, and -S commands are approximately the same as the equivalent dpkg
options except that the search is performed using regular expressions
rather than fixed strings.
Options
-f, --filename-only Output file names only when searching for files
-p, --package-only Output package names only when searching for files
Regular Expression Options (see grep(1) for details):
-E, --extended-regexp
-F, --fixed-strings
-G, --basic-regexp
-P, --perl-regexp
-w, --word-regexp Restrict matches to whole words
-i, --ignore-case Case-insensitive match
Miscellaneous Options:
-h, -H, --help Display this help message and exit.
-V, --version Display dlocate's version number and exit.
-v, --verbose, --debug Verbose/debug output
-c, --columns [cols] Set COLUMN width. Without -c, dlocate defaults to
using the entire terminal line width.
__EOF__
exit 1
}
function warn() {
printf "%s\n\n" "$*" >&2
}
function dlocate_version {
VERSION_BANNER="1.07"
echo "dlocate version $VERSION_BANNER"
exit 0
}
function dlocate_option_error () {
echo "dlocate: unknown option '$1'"
echo
echo "Use: 'dlocate -- $1' if you want to search for '$1'"
exit 1
}
# Thanks to "A. Costa" <agcosta@gis.net> in https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=407412
# What provided an installed virtual package?
# What programs provide a given virtual package?
deb_provided_by() { grep-status -F Provides "$1" -a -F Status installed -ns Package: ; }
list_deb_providers() { grep-available -F Provides "$1" -ns Package: ; }
OPTION='DEFAULT'
# default to extended regexp
RE_TYPE="-E"
RE_SEPARATOR="|"
# default to case-sensitive
IGNORE_CASE=''
# default to non- word-based searches
WORD_RE=''
WSEP1='\<'
WSEP2='\>'
# output filters for -S and DEFAULT option
OUTPUT_FILTER="none"
function output_filter() {
[ -n "$VERBOSE" ] && warn "OUTPUT FILTER: $OUTPUT_FILTER"
case "$OUTPUT_FILTER" in
filenames) awk -F': ' '{ print $NF }' ;;
packages) awk -F': ' '{ print $1 }' | sort -u ;;
*) cat ;;
esac
}
VERBOSE=''
KERNEL=''
# getopt is only safe if GETOPT_COMPATIBLE is not set.
unset GETOPT_COMPATIBLE
# POSIXLY_CORRECT disables getopt parameter shuffling, so nuke it.
# parameter shuffling moves all non-option args to the end, after
# all the option args. e.g. args like "-x -y file1 file2 file3 -o optval"
# become "-x -y -o optval -- file1 file2 file3"
unset POSIXLY_CORRECT
OPTS_SHORT='hHVvdc:KkSLlsiEFGPwfp'
OPTS_LONG='help,version,verbose,debug,columns:,ls,du,conf,lsconf,md5sum,md5check,man,lsman,lsbin,ignore-case,extended-regexp,fixed-strings,basic-regexp,perl-regexp,filename-only,package-only,lsdir'
# check options and shuffle them
# use getopt's `-a` option to provide backwards-compatibility
# with the old, broken option handling.
TEMP=$(getopt -a -o "$OPTS_SHORT" --long "$OPTS_LONG" -n "$0" -- "$@")
if [ $? != 0 ] ; then usage "Terminating..." ; fi
# assign the re-ordered options & args to this shell instance
eval set -- "$TEMP"
while true ; do
case "$1" in
-h|-H|--help) usage ; shift ;;
-V|--vers*) dlocate_version ; shift ;;
-v|--verb*|--deb*) VERBOSE=1 ; shift ;;
-c|--col*) COLUMNS="${2:-80}" ; shift 2 ;;
-E|--ext*) RE_TYPE='-E' ; shift ;;
-F|--fix*) RE_TYPE='-F' ; RE_SEPARATOR=$'\n' ; shift ;;
-G|--bas*) RE_TYPE='-G' ; shift ;;
-P|--per*) RE_TYPE='-P' ; WSEP1='\b' ; WSEP2='\b' ; shift ;;
-w|--wor*) WORD_RE="-w" ; shift ;;
-i|--ign*) IGNORE_CASE='-i' ; shift ;;
-f|--fil*) OUTPUT_FILTER='filenames' ; shift ;;
-p|--pac*) OUTPUT_FILTER='packages' ; shift ;;
# only one of the following options can be used at a time.
# last one seen on the command-line wins.
-K|-k) OPTION="$1" ; KERNEL=1 ; shift ;;
-S) OPTION="$1" ; shift ;;
-L) OPTION="$1" ; shift ;;
-l) OPTION="$1" ; shift ;;
-s) OPTION="$1" ; shift ;;
--ls) OPTION="$1" ; shift ;;
--du) OPTION="$1" ; shift ;;
--conf) OPTION="$1" ; shift ;;
--lsconf) OPTION="$1" ; shift ;;
--md5sum) OPTION="$1" ; shift ;;
--md5check) OPTION="$1" ; shift ;;
--man) OPTION="$1" ; shift ;;
--lsman) OPTION="$1" ; shift ;;
--lsbin) OPTION="$1" ; shift ;;
--lsdir) OPTION="$1" ; shift ;;
--) shift ; break ;;
*) usage ;;
esac
done
[ -z "$*${KERNEL}" ] && usage
PKGS=("$@")
joinargs() { local IFS="$1"; shift; echo "$*"; }
PKGS_REGEXP=$(joinargs "$RE_SEPARATOR" "$@")
[ "$RE_TYPE" = "-G" ] && PKGS_REGEXP=$(printf "%s" "$PKGS_REGEXP" | sed -E -e 's/\|/\\|/g')
FILES_REGEXP="($PKGS_REGEXP)"
[ "$WORD_RE" = "-w" ] && FILES_REGEXP="${WSEP1}$FILES_REGEXP${WSEP2}"
[ -z "$COLUMNS" ] &&
COLUMNS=$(stty -a 2>&- | sed -ne '/columns/s/.*columns \([0-9]*\)[^0-9].*/\1/p');
[ 0"$COLUMNS" -lt 80 ] && COLUMNS=80;
if [ -n "$VERBOSE" ] ; then
declare -p COLUMNS TEMP PKGS OPTION RE_SEPARATOR PKGS_REGEXP FILES_REGEXP |
sed -e 's/^declare [^ ]\+ //' >&2
echo >&2
fi
[ -z "$PKGS_REGEXP" ] && PKGS_REGEXP='^$'
if [ "$OPTION" = '-l' ] ; then
((fieldw=(COLUMNS-24)/4));
# dpkg uses ((fieldd=fieldw*2+16));
#
# limiting the output to COLUMNS-2 characters and losing up to
# additional 3 characters due to the rounding error.
((fieldd=COLUMNS-fieldw*2-6));
fmt_eq=$(echo ==================================================== |
cut -c-$fieldw)
HEADER=$( printf \
"Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ %-${fieldw}s %-${fieldw}s %s
+++-${fmt_eq}-${fmt_eq}-${fmt_eq}${fmt_eq}==================\\n" \
Name Version Description)
BODY_FMT_STRING="%-2s %-${fieldw}.${fieldw}s %-${fieldw}.${fieldw}s %-${fieldd}.${fieldd}s\\n"
[ -n "$VERBOSE" ] && warn RUNNING: $GREP $RE_TYPE $WORD_RE $IGNORE_CASE -- "'$PKGS_REGEXP'" "$DPKGLIST"
BODY=$($GREP $RE_TYPE $WORD_RE $IGNORE_CASE -- "$PKGS_REGEXP" "$DPKGLIST" | \
awk -F'\t' "{ printf \"$BODY_FMT_STRING\", \$1, \$2, \$3, \$4 }" |
sed -e 's/ *$//g'
)
[ -n "$BODY" ] && printf "%s\n" "$HEADER" "$BODY"
elif [ "$OPTION" = '-S' ] ; then
if [ "$RE_TYPE" = '-F' ] ; then
warn "Error: -F Fixed String searches are incompatible with -S"
exit 1
fi
PREFIX="^([-a-zA-Z0-9_.+]+:|diversion by )"
[ "$RE_TYPE" = "-G" ] && PREFIX="^\([-a-zA-Z0-9_.+]+:\|diversion by \)"
[ -n "$VERBOSE" ] && warn RUNNING: $GREP $RE_TYPE $IGNORE_CASE -- "'$PREFIX.*$FILES_REGEXP'" "$DLOCATEDB"
$GREP $RE_TYPE $IGNORE_CASE -- "$PREFIX.*$FILES_REGEXP" "$DLOCATEDB" | output_filter
result=${PIPESTATUS[0]}
elif [ "$OPTION" = 'DEFAULT' ] ; then
[ -n "$VERBOSE" ] && warn RUNNING: $GREP $RE_TYPE $IGNORE_CASE -- $WORD_RE "'$PKGS_REGEXP'" "$DLOCATEDB"
$GREP $RE_TYPE $IGNORE_CASE $WORD_RE -- "$PKGS_REGEXP" "$DLOCATEDB" | output_filter
result=${PIPESTATUS[0]}
#[ "$result" -eq 1 ] && echo "not in package: $PKGS_REGEXP" >&2
elif [ "$OPTION" = '-s' ] ; then
for p in "${PKGS[@]}" ; do
grep-status -P -X "$p"
result=$?
if [ "$result"0 -ne 0 ] ; then
printf "%s\n" "Package: $p (virtual package, currently provided by '$(deb_provided_by "$p")')"
printf "%s\n\n" "X-Available-Providers: $(list_deb_providers "$p" | sort -u | xargs | sed -e 's/ / | /g')"
# use X-Available-Provides: to provide a hint that it's a synthetic status field.
fi
done
elif [ "$OPTION" = '-k' ] ; then
kmodules=( $(grep-status -s Package -n -e ' (module-assistant|dkms)([, ]|$)' | grep -v 'module-assistant') )
kmods_re=$(joinargs '|' "${kmodules[@]}")
linux_pkgs='^(linux-(image|source|headers|doc|debug|kbuild|perf|support|tools|manual))'
[ -n "$kmods_re" ] && linux_pkgs="$linux_pkgs|^($kmods_re)$"
[ -n "$VERBOSE" ] && warn RUNNING: grep-status -P -e "'$linux_pkgs'"
grep-status -P -e "$linux_pkgs" | \
grep-dctrl -n -s Package -F status " installed" - | sort -V
result=$?
elif [ "$OPTION" = '-K' ] ; then
KERN_RE=$(joinargs '|' $("$DLOCATE" -k))
[ -n "$VERBOSE" ] && warn RUNNING: dlocate -E -w -l "'($KERN_RE)'"
"$DLOCATE" -c "$COLUMNS" -E -w -l "($KERN_RE)" | grep -v '^.n'
result=$?
else
for PKG in "${PKGS[@]}" ; do
case "$OPTION" in
-L)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
cat "$DPKG_INFO/$PKG.list"
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
--ls)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
xargs -d '\n' -r ls -ldF < "$DPKG_INFO/$PKG.list"
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
--du)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
sed '1d' "$DPKG_INFO/$PKG.list" |
xargs -d '\n' -r ls -1dF |
sed -e '/@$\|\/$/d; s/\*$//;' |
xargs du -sck
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
--conf)
if [ -s "$DPKG_INFO/$PKG.conffiles" ] ; then
cat "$DPKG_INFO/$PKG.conffiles"
result=$?
else
warn "Package $PKG is not installed or has no conffiles."
result=1
fi
;;
--lsconf)
if [ -s "$DPKG_INFO/$PKG.conffiles" ] ; then
xargs -a "$DPKG_INFO/$PKG.conffiles" -d '\n' -r ls -ldF
result=$?
else
warn "Package $PKG is not installed or has no conffiles."
result=1
fi
;;
--md5sum)
if [ -s "$DPKG_INFO/$PKG.md5sums" ] ; then
cat "$DPKG_INFO/$PKG.md5sums"
result=$?
else
warn "Package $PKG is not installed or has no md5sums."
result=1
fi
;;
--md5check)
if [ -s "$DPKG_INFO/$PKG.md5sums" ] ; then
pushd / >/dev/null 2>&1
cat "$DPKG_INFO/$PKG.md5sums" | \
md5sum -c -
popd >/dev/null 2>&1
result=$?
else
warn "Package $PKG is not installed or has no md5sums."
result=1
fi
;;
--lsman)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
"$DLOCATE" -L "$PKG" | \
grep -E '/man[0-9]+/'
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
--man)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
"$DLOCATE" -L "$PKG" | \
grep -E '/man[0-9]+/' | \
sed -e 's/\.gz$//' \
-e 's:.*/::' \
-e 's/\(^.*\)\.\(.*\)/\2 \1/' | \
sort -u
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
--lsbin)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
"$DLOCATE" -L $PKG | \
xargs -d '\n' -r stat -c '%A %n' | \
awk '!/^[^-]/ && /^-.{2,8}[xs]/ {print $2}'
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
--lsdir)
if [ -s "$DPKG_INFO/$PKG.list" ] ; then
"$DLOCATE" -L $PKG | \
xargs -d '\n' -r stat -c '%A %n' | \
awk '/^d/ {print $2}'
result=$?
else
warn "Package $PKG is not installed or $DPKG_INFO/$PKG.list is empty."
result=1
fi
;;
esac
done
fi
test -n "$result" && exit $result