Получить причину отказа в разрешении из-за того, что пройденный каталог не является исполняемым

У меня есть файл /a/b, который может прочитать пользователь A. Но /a не предоставляет права на выполнение A, и поэтому путь /a/b не может пройти через /a. Для произвольно длинного пути, как мне определить причину невозможности доступа к заданному пути из-за того, что промежуточный путь недоступен для пользователя?


person Matt Joiner    schedule 02.04.2016    source источник
comment
вы можете найти мой ответ 29571473#29571473" title="Установщик unix не может найти путь к файлу, хотя я ввожу точный путь"> stackoverflow.com/questions/29570203/ справки (но не прямое решение). Удачи.   -  person shellter    schedule 02.04.2016


Ответы (4)


Альтернативным ответом на анализ дерева вручную и выявление ошибки в одной строке может быть использование инструмента namei.

namei -mo a/b/c/d
f: a/b/c/d
 drwxrw-rw- rasjani rasjani a
 drw-rwxr-x rasjani rasjani b
                        c - No such file or directory

Это показывает всю древовидную структуру и разрешения вплоть до записи, в которой отказано в разрешении.

person rasjani    schedule 19.05.2016
comment
Это было то, о чем я не знал, и это кажется наиболее логичным ранее существовавшим решением. - person Matt Joiner; 25.05.2016

Что-то вроде этого:

#!/bin/bash
PAR=${1}
PAR=${PAR:="."}
if ! [[ "${PAR:0:1}" == / || "${PAR:0:2}" == ~[/a-z] ]]
then
  TMP=`pwd`
  PAR=$(dirname ${TMP}/${PAR})
fi

cd $PAR 2> /dev/null
if [ $? -eq 1 ]; then
  while [ ! -z "$PAR" ]; do
    PREV=$(readlink -f ${PAR})
    TMP=$(echo ${PAR}|awk -F\/ '{$NF=""}'1|tr ' ' \/)
    PAR=${TMP%/}
    cd ${PAR} 2>/dev/null
    if [ $? -eq 0 ]; then
      if [ -e ${PREV} ]; then
        ls -ld ${PREV}
      fi
      exit
    fi
  done
fi

Некрасиво, но с работой справится..

Таким образом, идея в основном состоит в том, чтобы взять параметр $ 1, если это не абсолютный каталог, расширить его до такого, а затем удалить последний элемент пути и попытаться перейти в него, если это не удается, промыть и повторить. Если это работает, PREV будет содержать последний каталог, в который пользователь не может перейти, поэтому распечатайте его.

person rasjani    schedule 18.05.2016
comment
Можете ли вы предоставить ссылку, указывающую, что нет лучшей альтернативы, или это обычный способ сделать это? - person Matt Joiner; 19.05.2016
comment
Понятия не имею о лучшей альтернативе, так как это тоже довольно плохо в том смысле, что у него есть синтаксический анализ строки, который может дать сбой. Другой альтернативой может быть выполнение итерации снизу вверх с помощью find -type -d $PAR, grep stderr для отказа в доступе, grep этой ошибки против PAR, чтобы избежать отображения других подкаталогов. Возможно, было бы красивее. - person rasjani; 19.05.2016
comment
Таким образом, повторение является ключевым здесь, поскольку нет другого способа, AFAIK, который мог бы сообщить, если доступ запрещен на пути, ведущем к фактической конечной точке. Возможно использование проверки test -x||test -r , но также это не удается, потому что он не предоставляет информацию, в какой точке пути был запрещен доступ .. - person rasjani; 19.05.2016
comment
Так что, по сути, такой подход — это просто обычный способ достижения цели =) - person rasjani; 19.05.2016

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

LAST=/a/b
while [ ! -z "$LAST" ] ; do
    NEXT=`echo "$LAST" | sed 's/[^\/]*$//' | sed 's/\/$//'`
    ls "$NEXT" 2> /dev/null > /dev/null
    if [ $? -eq 0 ] ; then 
        echo "Can't access: $LAST"
        break
    fi
    LAST="$NEXT"
done

и мне нравится помещать такие вещи в одну строку просто для удовольствия:

LAST=/a/b; while [ ! -z "$LAST" ] ; do NEXT=`echo "$LAST" | sed 's/[^\/]*$//' | sed 's/\/$//'`; ls "$NEXT" 2> /dev/null > /dev/null; if [ $? -eq 0 ] ; then echo "Can't access: $LAST"; break; fi; LAST="$NEXT"; done
person mrfred    schedule 24.05.2016

У меня есть ниже программа C для вас, которая делает это. Ниже приведены шаги

  1. Скопируйте и сохраните программу как файл .c.
  2. Скомпилируйте программу с помощью файла gcc.c -o
  3. Выполните его как ./file PATH

Предполагая, что у вас есть путь как /a/b/c/d и у вас нет разрешения на «c», тогда вывод будет

  Given Path = /a/b/c/d

  No permission on = /a/b/c

Для разрешения я полагаюсь на ошибку «EACCES». Предполагается, что длина пути равна 1024.

Если у вас есть какие-либо вопросы, пожалуйста, поделитесь.

  #include <stdio.h>
  #include <string.h>
  #include <errno.h>

  #define MAX_LEN 1024

  int main(int argc, char *argv[])
  {
    char path[MAX_LEN] = "/home/sudhansu/Test";
    int i = 0;
    char parse[MAX_LEN] = "";

    if(argc == 2)
    {
      strcpy(path, argv[1]);
      printf("\n\t\t Given Path = %s\n", path);
    }
    else
    {
      printf("\n\t\t Usage : ./file PATH\n\n");
      return 0;
    }

    if(path[strlen(path)-1] != '/')
      strcat(path, "/");

    path[strlen(path)] = '\0';

    while(path[i])
    {
      if(path[i] == '/')
      {
        strncpy(parse, path, i+1);
        if(chdir(parse) < 0)
        {
          if(errno == EACCES)
          {
            printf("\t\t No permission on = [%s]\n", parse);
            break;
          }
        }
      }

      parse[i] = path[i];
      i++;
    }

    printf("\n");
    return 0;
  }

С уважением, Судхансу

person Sudhansu    schedule 24.05.2016