Cannot manually update database for locate?
I've been trying to update the databases used by locate on my Macbook (10.6.3 Snow Leopard) but even following the commands shown in this thread hasn't gotten me anywhere. I just get an error from it - if I try to use it via sudo, I get some racket about permission denied for such-n-such directory. I tried running it as root (sudo su, then the command) and that didn't work either. Quit back to my regular terminal prompt, and now I just get
macbook:~ monte$ sudo /usr/libexec/locate.updatedb
find: .: Permission denied
macbook:~ monte$
I'm thoroughly confused, and half afraid that I may have hosed something in the process. Any help or suggestions would be greatly appreciated!
Monte
4 Answers
The solution for your problem is very simple. But if you want to know better why the error is occurring and why the proposed solution works, you can read the entire answer.
Otherwise, if you only want to get the answer, go straight to the "How to update your locate db?" session.
What exactly locate.updatedb does?
This is the current behavior of locate.updatedb:
- If you are running the script as
root, the script calls itself with the usernobody. Then, when the children returns, it updates the final locale database with the database saved by the children process (nobodyuser) in a temporary location, and then exits;
Code (/usr/libexec/locate.updatedb, line 31, with additional comments added by me):
if [ "$(id -u)" = "0" ]; then ## IF ROOT USER rc=0 export FCODES=`mktemp -t updatedb` ## CREATE A TEMP FILE chown nobody $FCODES # TEMP FILE OWNED BY THE NOBODY USER tmpdb=`su -fm nobody -c "$0"` || rc=1 ## CALL ITSELF AS USER NOBODY if [ $rc = 0 ]; then install -m 0444 -o nobody -g wheel $FCODES \ /var/db/locate.database ## INSTALL THE LOCATE DATABASE SAVED \ ## BY THE CHILDREN IN THE TEMP FILE fi rm $FCODES exit $rc ## EXIT
fi- When running with another user (it is, the user
nobody), the script indexes your system (ignoring the paths which it doesn't have permission) and then saves the result in a temporary file (actually, the previously temp file created by its father).
Some considerations:
- Part of the logic is executed as root, and other part as nobody;
- If the script is called without
sudo, it won't work (onlyroothas permission in the/var/dbdirectory). It is, you must really run the script asroot; - As a result,
locate.updatedbcan't index files inside your home directory (thenobodyuser doesn't have permission to access it);- I think
locate.updatedbindexes this way because it will be impossible to an user to discover name of files that belongs to another user (in another home directory); - If you want to locate files inside your home, you can use
mdfind, as proposed by @ted-naleid.
- I think
Some code (/usr/libexec/locate.updatedb, line 93, with additional comments):
if $find -s $SEARCHPATHS $excludes -or -print 2>/dev/null | ## SEARCH $mklocatedb -presort > $tmp ## CREATE LOCALEDB
then case X"`$find $tmp -size -257c -print`" in X) cat $tmp > $FCODES;; ## SAVE LOCALEDB IN THE TEMP FILE
[...]Why are you getting "Permission Denied" errors?
As I said, locale.updatedb launchs a new instance of itself as the nobody user. However, you cannot start a script inside a workdir in which the script has no permissions.
Probably, you are getting "Permission denied" errors because you're running locale.updatedb inside your home.
I'm creating a simple script to show this fact:
#!/bin/bash
if [ $(id -un) != "nobody" ]; then sudo -u nobody "$0" exit 0
fi
find / -mindepth 1 -maxdepth 1 | wc -lIf you put this script inside /tmp/test.sh and set execution permission to it (chmod +x /tmp/test.sh), depending of your workdir, it can show or not errors:
$ cd /tmp
$ ./test.sh 29
$ cd ~
$ /tmp/test.sh
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
find: .: Permission denied 0How to update your locate db?
Now, it's simple! Only change your workdir to a place where nobody has permission before executing locale.updatedb:
cd /
sudo /usr/libexec/locate.updatedb You might want to try to repair file permissions (in the Disk Utility application). Sounds like it might be an issue with that.
Also, not directly related to locate, but I've found that on the mac that mdfind actually does what I want quite a bit better than locate does. It's the command line interface to spotlight, and it lets you find just by file name if you want to mimic locate:
mdfind -name <filename>Just using "mdfind " will find both file names and look inside files (sort of grep/find put together).
No need to manually update the database for it as OSX maintains the spotlight information for you.
1launchctl load -wF /System/Library/LaunchDaemons/com.apple.locate.plistIf it doesn't help, try:
launchctl stop com.apple.locate
launchctl start com.apple.locate 1 (this is a bit old, but since I was digging on a similar problem with 10.6 today...)
macbook:~ monte$ sudo /usr/libexec/locate.updatedb
find: .: Permission denied
macbook:~ monte$this isn't a problem, exactly - it's a side effect of locate.updatedb su'ing to nobody, but your home directory isn't readable by the "nobody" user.
You'll probably find that system files are still findable with locate, but nothing inside your home directory is. You'll need to make your homedir world readable/executable. For example:
chmod a+rx $HOMEYou may need to review the contents of your homedir, too - but it's likely you dont want to do a recursive chmod across the entire tree. (~/.ssh, for example, has specific requirements). If you have a custom umask set, you'll want to review that as well.
As a hackaround alternative you could edit the /usr/libexec/locate.updatedb script to not switch to the nobody user:
if [ "$(id -u)" = "0" ]; then rc=0 export FCODES=`mktemp -t updatedb` chown nobody $FCODES tmpdb=`su -fm nobody -c "$0"` || rc=1 if [ $rc = 0 ]; then install -m 0444 -o nobody -g wheel $FCODES /var/db/locate.database fi rm $FCODES exit $rc
fiRemove or comment out that block - or just tweak the test to something else -
if [ "$(id -u)" = "-99" ]; thenThis should work regardless of how the update is called - by launchd, or manually. But could revert if you update the OS. (though lets face it, in 2014 if you're still running 10.6, you're probably not going to update now ;)