1#! /bin/sh
2# updatedb -- build a locate pathname database
3# Copyright (C) 1994, 1996, 1997, 2000, 2001, 2003, 2004, 2005, 2006
4# Free Software Foundation, Inc.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10# 
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15# 
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19# csh original by James Woods; sh conversion by David MacKenzie.
20
21usage="\
22Usage: $0 [--findoptions='-option1 -option2...']
23       [--localpaths='dir1 dir2...'] [--netpaths='dir1 dir2...']
24       [--prunepaths='dir1 dir2...'] [--prunefs='fs1 fs2...']
25       [--output=dbfile] [--netuser=user] [--localuser=user] 
26       [--old-format] [--version] [--help]
27
28Report bugs to <bug-findutils@gnu.org>."
29changeto=/
30old=no
31for arg
32do
33  # If we are unable to fork, the back-tick operator will 
34  # fail (and the shell will emit an error message).  When 
35  # this happens, we exit with error value 71 (EX_OSERR).
36  # Alternative candidate - 75, EX_TEMPFAIL.
37  opt=`echo $arg|sed 's/^\([^=]*\).*/\1/'`  || exit 71
38  val=`echo $arg|sed 's/^[^=]*=\(.*\)/\1/'` || exit 71
39  case "$opt" in
40    --findoptions) FINDOPTIONS="$val" ;;
41    --localpaths) SEARCHPATHS="$val" ;;
42    --netpaths) NETPATHS="$val" ;;
43    --prunepaths) PRUNEPATHS="$val" ;;
44    --prunefs) PRUNEFS="$val" ;;
45    --output) LOCATE_DB="$val" ;;
46    --netuser) NETUSER="$val" ;;
47    --localuser) LOCALUSER="$val" ;;
48    --old-format) old=yes ;;
49    --changecwd)  changeto="$val" ;;
50    --version) echo "GNU updatedb version @VERSION@"; exit 0 ;;
51    --help) echo "$usage"; exit 0 ;;
52    *) echo "updatedb: invalid option $opt
53$usage" >&2
54       exit 1 ;;
55  esac
56done
57
58if test "$old" = yes; then
59    echo "Warning: future versions of findutils will shortly discontinue support for the old locate database format." >&2
60
61    sort="@SORT@"
62    print_option="-print"
63    frcode_options=""
64else
65    if @SORT_SUPPORTS_Z@
66    then
67        sort="@SORT@ -z"
68        print_option="-print0"
69        frcode_options="-0"
70    else
71        sort="@SORT@"
72        print_option="-print"
73        frcode_options=""
74    fi
75fi
76
77getuid() {
78    # format of "id" output is ...
79    # uid=1(daemon) gid=1(other)
80    # for `id's that don't understand -u
81    id | cut -d'(' -f 1 | cut -d'=' -f2
82}
83
84# figure out if su supports the -s option
85select_shell() {
86    if su "$1" -s $SHELL -c false < /dev/null  ; then
87	# No.
88	echo ""
89    else
90	if su "$1" -s $SHELL -c true < /dev/null  ; then
91	    # Yes.
92	    echo "-s $SHELL"
93        else
94	    # su is unconditionally failing.  We won't be able to 
95	    # figure out what is wrong, so be conservative.
96	    echo ""
97	fi
98    fi
99}
100
101
102# You can set these in the environment, or use command-line options,
103# to override their defaults:
104
105# Any global options for find?
106: ${FINDOPTIONS=}
107
108# What shell shoud we use?  We should use a POSIX-ish sh.
109: ${SHELL="/bin/sh"}
110
111# Non-network directories to put in the database.
112: ${SEARCHPATHS="/"}
113
114# Network (NFS, AFS, RFS, etc.) directories to put in the database.
115: ${NETPATHS=}
116
117# Directories to not put in the database, which would otherwise be.
118: ${PRUNEPATHS="/tmp /usr/tmp /var/tmp /afs /amd /sfs"}
119
120# Trailing slashes result in regex items that are never matched, which 
121# is not what the user will expect.   Therefore we now reject such 
122# constructs.
123for p in $PRUNEPATHS; do
124    case "$p" in
125	/*/)   echo "$0: $p: pruned paths should not contain trailing slashes" >&2
126	       exit 1
127    esac
128done
129
130# The same, in the form of a regex that find can use.
131test -z "$PRUNEREGEX" &&
132  PRUNEREGEX=`echo $PRUNEPATHS|sed -e 's,^,\\\(^,' -e 's, ,$\\\)\\\|\\\(^,g' -e 's,$,$\\\),'`
133
134# The database file to build.
135: ${LOCATE_DB=@LOCATE_DB@}
136
137# Directory to hold intermediate files.
138if test -d /var/tmp; then
139  : ${TMPDIR=/var/tmp}
140elif test -d /usr/tmp; then
141  : ${TMPDIR=/usr/tmp}
142else
143  : ${TMPDIR=/tmp}
144fi
145export TMPDIR
146
147# The user to search network directories as.
148: ${NETUSER=daemon}
149
150# The directory containing the subprograms.
151if test -n "$LIBEXECDIR" ; then
152    : LIBEXECDIR already set, do nothing
153else
154    : ${LIBEXECDIR=@libexecdir@}
155fi
156
157# The directory containing find.
158if test -n "$BINDIR" ; then
159    : BINDIR already set, do nothing
160else
161    : ${BINDIR=@bindir@}
162fi
163
164# The names of the utilities to run to build the database.
165: ${find:=${BINDIR}/@find@}
166: ${frcode:=${LIBEXECDIR}/@frcode@}
167: ${bigram:=${LIBEXECDIR}/@bigram@}
168: ${code:=${LIBEXECDIR}/@code@}
169
170
171PATH=/bin:/usr/bin:${BINDIR}; export PATH
172
173: ${PRUNEFS="nfs NFS proc afs proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs mfs sysfs shfs"}
174
175if test -n "$PRUNEFS"; then
176prunefs_exp=`echo $PRUNEFS |sed -e 's/\([^ ][^ ]*\)/-o -fstype \1/g' \
177 -e 's/-o //' -e 's/$/ -o/'`
178else
179  prunefs_exp=''
180fi
181
182# Make and code the file list.
183# Sort case insensitively for users' convenience.
184
185rm -f $LOCATE_DB.n
186trap 'rm -f $LOCATE_DB.n; exit' HUP TERM
187
188if test $old = no; then
189
190# FIXME figure out how to sort null-terminated strings, and use -print0.
191if {
192cd "$changeto"
193if test -n "$SEARCHPATHS"; then
194  if [ "$LOCALUSER" != "" ]; then
195    # : A1
196    su $LOCALUSER `select_shell $LOCALUSER` -c \
197    "$find $SEARCHPATHS $FINDOPTIONS \
198     \\( $prunefs_exp \
199     -type d -regex '$PRUNEREGEX' \\) -prune -o $print_option"
200  else
201    # : A2
202    $find $SEARCHPATHS $FINDOPTIONS \
203     \( $prunefs_exp \
204     -type d -regex "$PRUNEREGEX" \) -prune -o $print_option
205  fi
206fi
207
208if test -n "$NETPATHS"; then
209myuid=`getuid` 
210if [ "$myuid" = 0 ]; then
211    # : A3
212    su $NETUSER `select_shell $NETUSER` -c \
213     "$find $NETPATHS $FINDOPTIONS \\( -type d -regex '$PRUNEREGEX' -prune \\) -o $print_option" ||
214    exit $?
215  else
216    # : A4
217    $find $NETPATHS $FINDOPTIONS \( -type d -regex "$PRUNEREGEX" -prune \) -o $print_option ||
218    exit $?
219  fi
220fi
221} | $sort -f | $frcode $frcode_options > $LOCATE_DB.n
222then
223    # OK so far
224    true
225else
226    rv=$?
227    echo "Failed to generate $LOCATE_DB.n" >&2
228    rm -f $LOCATE_DB.n
229    exit $rv
230fi
231
232# To avoid breaking locate while this script is running, put the
233# results in a temp file, then rename it atomically.
234if test -s $LOCATE_DB.n; then
235  rm -f $LOCATE_DB
236  mv $LOCATE_DB.n $LOCATE_DB
237  chmod 644 $LOCATE_DB
238else
239  echo "updatedb: new database would be empty" >&2
240  rm -f $LOCATE_DB.n
241fi
242
243else # old
244
245if ! bigrams=`mktemp -t updatedbXXXXXXXXX`; then
246    echo tempfile failed
247    exit 1
248fi
249
250if ! filelist=`mktemp -t updatedbXXXXXXXXX`; then
251    echo tempfile failed
252    exit 1
253fi
254
255rm -f $LOCATE_DB.n
256trap 'rm -f $bigrams $filelist $LOCATE_DB.n; exit' HUP TERM
257
258# Alphabetize subdirectories before file entries using tr.  James Woods says:
259# "to get everything in monotonic collating sequence, to avoid some
260# breakage i'll have to think about."
261{
262cd "$changeto"
263if test -n "$SEARCHPATHS"; then
264  if [ "$LOCALUSER" != "" ]; then
265    # : A5
266    su $LOCALUSER `select_shell $LOCALUSER` -c \
267    "$find $SEARCHPATHS $FINDOPTIONS \
268     \( $prunefs_exp \
269     -type d -regex '$PRUNEREGEX' \) -prune -o $print_option" || exit $?
270  else
271    # : A6
272    $find $SEARCHPATHS $FINDOPTIONS \
273     \( $prunefs_exp \
274     -type d -regex "$PRUNEREGEX" \) -prune -o $print_option || exit $?
275  fi
276fi
277
278if test -n "$NETPATHS"; then
279  myuid=`getuid`
280  if [ "$myuid" = 0 ]; then
281    # : A7
282    su $NETUSER `select_shell $NETUSER` -c \
283     "$find $NETPATHS $FINDOPTIONS \\( -type d -regex '$PRUNEREGEX' -prune \\) -o $print_option" ||
284    exit $?
285  else
286    # : A8
287    $find $NETPATHS $FINDOPTIONS \( -type d -regex "$PRUNEREGEX" -prune \) -o $print_option ||
288    exit $?
289  fi
290fi
291} | tr / '\001' | $sort -f | tr '\001' / > $filelist
292
293# Compute the (at most 128) most common bigrams in the file list.
294$bigram $bigram_opts < $filelist | sort | uniq -c | sort -nr |
295  awk '{ if (NR <= 128) print $2 }' | tr -d '\012' > $bigrams
296
297# Code the file list.
298$code $bigrams < $filelist > $LOCATE_DB.n
299
300rm -f $bigrams $filelist
301
302# To reduce the chances of breaking locate while this script is running,
303# put the results in a temp file, then rename it atomically.
304if test -s $LOCATE_DB.n; then
305  rm -f $LOCATE_DB
306  mv $LOCATE_DB.n $LOCATE_DB
307  chmod 644 $LOCATE_DB
308else
309  echo "updatedb: new database would be empty" >&2
310  rm -f $LOCATE_DB.n
311fi
312
313fi
314
315exit 0
316