Не удается вручную обновить базу данных для поиска?

Я пытался обновить базы данных, используемые locate на моем Macbook (10.6.3 Snow Leopard), но даже выполнение команд, показанных в этой теме, никуда меня не привело. Я просто получаю сообщение об ошибке - если я пытаюсь использовать его с помощью sudo, я получаю некоторую информацию об отказе в разрешении для такого-n-такого каталога. Я попытался запустить его как root (sudo su, затем команда), и это тоже не сработало. Вернитесь к моей обычной терминальной подсказке, и теперь я просто получаю

macbook:~ monte$ sudo /usr/libexec/locate.updatedb
найти: .: В доступе отказано
MacBook: ~ Монте $

Я полностью сбит с толку и наполовину боюсь, что, возможно, что-то спрятал в процессе. Любая помощь или предложения будут с благодарностью!

Monte

4 ответа

Решение вашей проблемы очень простое (и его можно найти в конце этого ответа). Но если вы хотите лучше узнать, почему происходит ошибка и почему работает предложенное решение, вы можете прочитать весь ответ.

Что именно делает locate.updatedb?

Это текущее поведение locate.updatedb:

  • Если вы запускаете скрипт как rootопять звонит сам с пользователем nobody и затем потомки возвращаются, он обновляет окончательную базу данных локали с базой данных, сохраненной процессом потомков (nobody пользователь) во временном местоположении, а затем выходит;

Код (/usr/libexec/locate.updatedb, строка 31, с дополнительными комментариями, добавленными мной):

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
  • При работе с другим пользователем (это пользователь nobody) сценарий индексирует вашу систему (игнорируя пути, на которые у него нет разрешения), а затем сохраняет результат во временный файл (фактически, ранее временный файл, созданный его отцом);
    • Итак, часть логики выполняется как корень, а другая часть как никто;
    • Если скрипт вызывается без sudoне сработает (только root имеет разрешение в /var/db каталог). Вы действительно должны изначально запустить скрипт как root;
    • В следствии, locate.updatedb не может индексировать файлы в вашем доме (nobody у пользователя нет прав доступа к нему);
    • Я думаю locate.updatedb индексирует таким образом, потому что пользователю будет невозможно обнаружить имена файлов, принадлежащих другому пользователю (в другом домашнем каталоге);
    • Если вы хотите найти файлы в вашем доме, вы можете использовать mdfindкак предложено @ted-naleid.

Некоторый код (/usr/libexec/locate.updatedb, строка 93, с дополнительными комментариями):

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
[...]

Почему вы получаете сообщение об ошибке "Отказано в доступе"?

Было сказано, что locale.updatedb запускает новый экземпляр себя как nobody пользователь. Однако вы не можете запустить скрипт внутри рабочего каталога, на который у скрипта нет разрешения.

Возможно, вы получаете ошибки "Отказано в доступе", потому что вы работаете locale.updatedb в вашем доме.

Я создаю простой скрипт, чтобы показать этот факт:

#!/bin/bash

if [ $(id -un) != "nobody" ]; then
    sudo -u nobody "$0"
    exit 0
fi

find / -mindepth 1 -maxdepth 1 | wc -l

Если вы поместите этот скрипт внутри /tmp/test.sh и установить для него разрешение на выполнение (chmod +x /tmp/test.sh), в зависимости от вашего рабочего каталога, может показывать или нет ошибки:

$ 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
       0

Как обновить вашу базу данных locate?

Теперь все просто! Измените только ваш рабочий каталог на место, где nobody имеет разрешение до выполнения locale.updatedb:

cd /
sudo /usr/libexec/locate.updatedb

Возможно, вы захотите попробовать восстановить права доступа к файлам (в приложении Дисковая утилита). Похоже, это может быть проблемой с этим.

Кроме того, не имеет прямого отношения к locate, но я обнаружил, что на mac этот mdfind действительно делает то, что я хочу, немного лучше, чем locate. Это интерфейс командной строки для подсветки, и он позволяет вам найти только по имени файла, если вы хотите имитировать locate:

mdfind -name <filename>

Просто используя "mdfind ", вы найдете имена обоих файлов и загляните внутрь файлов (вроде grep/find вместе взятых).

Нет необходимости обновлять базу данных вручную, так как OSX предоставляет информацию о вас.

launchctl load -wF /System/Library/LaunchDaemons/com.apple.locate.plist

Если это не поможет, попробуйте:

launchctl stop com.apple.locate

launchctl start com.apple.locate

(это немного устарело, но так как я копал аналогичную проблему с 10.6 сегодня...)

macbook:~ monte$ sudo /usr/libexec/locate.updatedb
find: .: Permission denied
macbook:~ monte$

это точно не проблема - это побочный эффект от locate.updatedb, который никому не нужен, но ваш домашний каталог не читается пользователем "nobody".

Вы, вероятно, обнаружите, что системные файлы все еще можно найти с помощью locate, но внутри вашего домашнего каталога ничего нет. Вам нужно сделать свой мир homedir читабельным / исполняемым. Например:

chmod a+rx $HOME

Возможно, вам также потребуется просмотреть содержимое вашего homedir - но, скорее всего, вы не хотите выполнять рекурсивный chmod по всему дереву. (~/.ssh, например, имеет особые требования). Если у вас есть пользовательский набор масок, вы также захотите просмотреть его.

В качестве альтернативы взлома вы можете отредактировать скрипт /usr/libexec/locate.updatedb, чтобы не переключаться на пользователя nobody:

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
fi

Удалить или закомментировать этот блок - или просто настроить тест на что-то другое -

if [ "$(id -u)" = "-99" ]; then

Это должно работать независимо от того, как обновление вызывается - launchd или вручную. Но может вернуться, если вы обновите ОС. (хотя давайте посмотрим правде в глаза, в 2014 году, если вы все еще используете 10.6, вы, вероятно, не собираетесь обновлять сейчас;)

Другие вопросы по тегам