Znajdź pliki, które użytkownik może pisać, wydajnie i przy minimalnym procesie tworzenia

20

Jestem rootem. Chciałbym wiedzieć, czy użytkownik inny niż root ma dostęp do zapisu do niektórych plików - tysięcy z nich. Jak to zrobić skutecznie, unikając tworzenia procesów?

Howard
źródło
Pokaż nam, co faktycznie robisz!
F. Hauri
Ten sam rodzaj pytania, co unix.stackexchange.com/a/88591
Stéphane Chazelas
Zakładając, że nie obchodzą Cię warunki wyścigu, dlaczego nie po prostu zadzwonić access(2)z odpowiednio ustawionym rzeczywistym UID (np. Przez setresuid(2)lub przenośny odpowiednik)? Mam na myśli, że trudno byłoby mi to zrobić po bashu, ale jestem pewien, że Perl / Python sobie z tym poradzą.
Kevin
1
@ Kevin, powłoki [ -wzwykle używają dostępu (2) lub równoważnego. Musisz także ustawić GID oprócz UID (tak jak robią Su lub Sudo). bash nie ma wbudowanej obsługi tego, ale zsh ma.
Stéphane Chazelas
@ StéphaneChazelas - możesz używać chgrpw dowolnej powłoce.
mikeserv

Odpowiedzi:

2

Być może tak:

#! /bin/bash

writable()
{
    local uid="$1"
    local gids="$2"
    local ids
    local perms

    ids=($( stat -L -c '%u %g %a' -- "$3" ))
    perms="0${ids[2]}"

    if [[ ${ids[0]} -eq $uid ]]; then
        return $(( ( perms & 0200 ) == 0 ))
    elif [[ $gids =~ (^|[[:space:]])"${ids[1]}"($|[[:space:]]) ]]; then
        return $(( ( perms & 020 ) == 0 ))
    else
        return $(( ( perms & 2 ) == 0 ))
    fi
}

user=foo
uid="$( id -u "$user" )"
gids="$( id -G "$user" )"

while IFS= read -r f; do
    writable "$uid" "$gids" "$f" && printf '%s writable\n' "$f"
done

Powyżej uruchamia pojedynczy program zewnętrzny dla każdego pliku, a mianowicie stat(1) .

Uwaga: To zakłada bash(1)i wcielenie Linuxa stat(1).

Uwaga 2: Proszę przeczytać komentarze Stéphane Chazelas poniżej dotyczące przeszłości, teraźniejszości, przyszłości oraz potencjalnych zagrożeń i ograniczeń tego podejścia.

lcd047
źródło
To znaczy, że plik można zapisać, nawet jeśli użytkownik nie ma dostępu do katalogu, w którym się znajduje.
Stéphane Chazelas
Zakłada się, że nazwy plików nie zawierają znaku nowej linii, a ścieżki plików przekazywane na standardowe wejście nie zaczynają się -. Zamiast tego możesz zmodyfikować go, aby akceptował listę rozdzielaną wartościami NULread -d ''
Stéphane Chazelas
Zauważ, że nie ma czegoś takiego jak statystyka Linuksa . Linux to jądro występujące w niektórych systemach GNU i innych niż GNU. Chociaż istnieją polecenia (jak z util-linux), które są napisane specjalnie dla Linuksa, statto nie jest to polecenie, o którym mowa, to polecenie GNU, które zostało przeniesione na większość systemów, nie tylko na Linuksa. Zauważ też, że masz statkomendę w Linuksie na długo przed napisaniem GNU stat( statwbudowane zsh).
Stéphane Chazelas
2
@ Stéphane Chazelas: Zauważ, że nie ma czegoś takiego jak statystyka Linuksa. - Wydaje mi się, że napisałem „wcielenie Linuxa stat(1)”. Mam na myśli a, stat(1)który akceptuje -c <format>składnię, w przeciwieństwie do, powiedzmy, składni BSD -f <format>. Uważam również, że było całkiem jasne, że nie miałem na myśli stat(2). Jestem jednak pewien, że strona wiki o historii popularnych poleceń byłaby całkiem interesująca.
lcd047
1
@ Stéphane Chazelas: To znaczy, że plik można zapisać, nawet jeśli użytkownik nie ma dostępu do katalogu, w którym się znajduje. - Prawda i prawdopodobnie rozsądne ograniczenie. Zakłada się, że nazwy plików nie zawierają znaku nowej linii - Prawda i prawdopodobnie rozsądne ograniczenie. a ścieżki plików przekazywane na standardowe wejście nie zaczynają się od - - Edytowane, dziękuję.
lcd047
17

TL; DR

find / ! -type l -print0 |
  sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'

Musisz zapytać system, czy użytkownik ma uprawnienia do zapisu. Jedynym niezawodnym sposobem jest przełączenie efektywnego identyfikatora UID, efektywnego identyfikatora GID i suplementów na identyfikator użytkownika i użycieaccess(W_OK) wywołania systemowego (nawet jeśli ma to pewne ograniczenia w niektórych systemach / konfiguracjach).

I pamiętaj, że brak uprawnień do zapisu do pliku niekoniecznie gwarantuje, że nie możesz modyfikować zawartości pliku w tej ścieżce.

Dłuższa historia

Zastanówmy się, czego potrzeba na przykład, aby użytkownik $ miał dostęp do zapisu /foo/file.txt(zakładając, że żaden z /fooi/foo/file.txt ma dowiązań symbolicznych)?

On potrzebuje:

  1. dostęp do wyszukiwania do /(nie ma potrzebyread )
  2. dostęp do wyszukiwania do /foo(nie ma potrzebyread )
  3. dostęp do zapisu do/foo/file.txt

Widać już, że podejścia (takie jak @ lcd047 lub @ apaul ), które sprawdzają, że tylko pozwolenie file.txtnie działa, ponieważ mogliby powiedzieć, że file.txtjest zapisywalne, nawet jeśli użytkownik nie ma uprawnień do wyszukiwania /lub/foo .

I takie podejście jak:

sudo -u "$user" find / -writeble

Nie zadziała również, ponieważ nie zgłosi plików w katalogach, użytkownik nie ma dostępu do odczytu (tak finddziałający, jak $usernie może wyświetlić ich zawartości), nawet jeśli może do nich pisać.

Jeśli zapomnimy o listach ACL, systemach plików tylko do odczytu, flagach FS (takich jak niezmienne), innych środkach bezpieczeństwa (apparmor, SELinux, które potrafią nawet rozróżnić różne typy zapisu) i skupimy się tylko na tradycyjnych atrybutach uprawnień i własności, aby uzyskać z uprawnieniami (wyszukiwanie lub zapis), jest to już dość skomplikowane i trudne do wyrażenia find .

Potrzebujesz:

  • jeśli plik należy do Ciebie, potrzebujesz tego uprawnienia dla właściciela (lub masz identyfikator użytkownika 0)
  • jeśli plik nie jest twoją własnością, ale grupa należy do ciebie, musisz mieć to uprawnienie dla grupy (lub mieć identyfikator użytkownika 0).
  • jeśli nie jest twoją własnością i nie należy do żadnej z twoich grup, obowiązują inne uprawnienia (chyba że twój identyfikator użytkownika wynosi 0).

W findskładni, tutaj jako przykład z użytkownikiem UID 1 oraz GID 1 i 2, byłoby to:

find / -type d \
  \( \
    -user 1 \( -perm -u=x -o -prune \) -o \
    \( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
    -perm -o=x -o -prune \
  \) -o -type l -o \
    -user 1 \( ! -perm -u=w -o -print \) -o \
    \( -group 1 -o -group 2 \) \( ! -perm -g=w -o -print \) -o \
    ! -perm -o=w -o -print

Ten ściąga katalogi, których użytkownik nie ma prawa do wyszukiwania i do innych typów plików (wykluczone dowiązania symboliczne, ponieważ nie są istotne), sprawdza dostęp do zapisu.

Jeśli chcesz również rozważyć dostęp do zapisu do katalogów:

find / -type d \
  \( \
    -user 1 \( -perm -u=x -o -prune \) -o \
    \( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
    -perm -o=x -o -prune \
  \) ! -type d -o -type l -o \
    -user 1 \( ! -perm -u=w -o -print \) -o \
    \( -group 1 -o -group 2 \) \( ! -perm -g=w -o -print \) -o \
    ! -perm -o=w -o -print

Lub dla arbitralnego $useri jego członkostwa w grupie pobranych z bazy danych użytkowników:

groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
  \( \
    -user "$user" \( -perm -u=x -o -prune \) -o \
    \( -group $groups \) \( -perm -g=x -o -prune \) -o \
    -perm -o=x -o -prune \
  \) ! -type d -o -type l -o \
    -user "$user" \( ! -perm -u=w -o -print \) -o \
    \( -group $groups \) \( ! -perm -g=w -o -print \) -o \
    ! -perm -o=w -o -print

(to jest 3 procesy w sumie: id, seda find)

Najlepiej byłoby zejść z drzewa jako root i sprawdzić uprawnienia jako użytkownik dla każdego pliku.

 find / ! -type l -exec sudo -u "$user" sh -c '
   for file do
     [ -w "$file" ] && printf "%s\n" "$file"
   done' sh {} +

(to jeden findproces plus jeden sudoi shprzetwarzaj co kilka tysięcy plików [i printfzwykle są one wbudowane w powłokę).

Lub z perl:

find / ! -type l -print0 |
  sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'

(3 procesy łącznie: find, sudoa perl).

Lub z zsh:

files=(/**/*(D^@))
USERNAME=$user
for f ($files) {
  [ -w $f ] && print -r -- $f
}

(W sumie 0 proces, ale przechowuje całą listę plików w pamięci)

Te rozwiązania opierają się na access(2)wywołaniu systemowym. Oznacza to, że zamiast odtwarzać algorytm używany przez system do sprawdzania uprawnień dostępu, prosimy system o sprawdzenie tego samego algorytmu (który uwzględnia uprawnienia, listy ACL, niezmienne flagi, systemy plików tylko do odczytu ... ) przydałby się, gdybyś spróbował otworzyć plik do zapisu, więc jest to najbliższe niezawodne rozwiązanie.

Aby przetestować podane tutaj rozwiązania z różnymi kombinacjami użytkownika, grupy i uprawnień, możesz:

perl -e '
  for $u (1,2) {
    for $g (1,2,3) {
      $d1="u${u}g$g"; mkdir$d1;
      for $m (0..511) {
        $d2=$d1.sprintf"/%03o",$m; mkdir $d2; chown $u, $g, $d2; chmod $m,$d2;
        for $uu (1,2) {
          for $gg (1,2,3) {
            $d3="$d2/u${uu}g$gg"; mkdir $d3;
            for $mm (0..511) {
              $f=$d3.sprintf"/%03o",$mm;
              open F, ">","$f"; close F;
              chown $uu, $gg, $f; chmod $mm, $f
            }
          }
        }
      }
    }
  }'

Zmieniający się użytkownik między 1 a 2 i grupa między 1, 2 i 3 i ograniczający się do niższych 9 bitów uprawnień, ponieważ są to już utworzone pliki 9458694. Dotyczy to katalogów, a następnie plików.

To tworzy wszystkie możliwe kombinacje u<x>g<y>/<mode1>/u<z>g<w>/<mode2>. Użytkownik z identyfikatorami UID 1 i GID 1 i 2 miałby dostęp do zapisu, u2g1/010/u2g3/777ale nieu1g2/677/u1g1/777 na przykład nie.

Teraz wszystkie te rozwiązania próbują zidentyfikować ścieżki plików, które użytkownik może otworzyć do zapisu, co różni się od ścieżek, w których użytkownik może modyfikować zawartość. Aby odpowiedzieć na to bardziej ogólne pytanie, należy wziąć pod uwagę kilka rzeczy:

  1. $ użytkownik może nie mieć dostępu do zapisu, /a/b/fileale jeśli jest właścicielem file(i ma dostęp do wyszukiwania /a/b, a system plików nie jest tylko do odczytu, a plik nie ma niezmiennej flagi, a on ma dostęp do powłoki z systemu), wtedy będzie mógł zmienić uprawnienia filei udzielić sobie dostępu.
  2. To samo, jeśli jest właścicielem, /a/bale nie ma dostępu do wyszukiwania.
  3. $ użytkownik może nie mieć dostępu, /a/b/fileponieważ nie ma dostępu do wyszukiwania /alub /a/b, ale plik ten może mieć na /b/c/fileprzykład twardy link , w którym to przypadku może być w stanie zmodyfikować zawartość /a/b/file, otwierając go poprzez /b/c/fileścieżkę.
  4. To samo dotyczy mocowań opraw . On nie może mieć dostęp do wyszukiwarki /a, ale /a/bmoże wiązać montowane w /c, więc on może otworzyć filena piśmie za pośrednictwem swojej /c/filedrugiej ścieżce.
  5. Może nie mieć uprawnień do zapisu /a/b/file, ale jeśli ma dostęp do zapisu /a/b, może tam usunąć lub zmienić nazwę filei zastąpić go własną wersją. Zmieniłby zawartość pliku, /a/b/filenawet jeśli byłby to inny plik.
  6. To samo, jeśli on ma dostęp do zapisu /a(mógł zmienić nazwę /a/b, aby /a/cutworzyć nowy /a/bkatalog, a nowy filew nim.

Aby znaleźć ścieżki, $userktóre można modyfikować. W przypadku adresu 1 lub 2 nie możemy już polegać na access(2)wywołaniu systemowym. Możemy dostosować nasze find -permpodejście, aby zakładać dostęp do wyszukiwania do katalogów lub zapisywać dostęp do plików, gdy tylko będziesz właścicielem:

groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
  \( \
    -user "$user" -o \
    \( -group $groups \) \( -perm -g=x -o -prune \) -o \
    -perm -o=x -o -prune \
  \) ! -type d -o -type l -o \
    -user "$user" -print -o \
    \( -group $groups \) \( ! -perm -g=w -o -print \) -o \
    ! -perm -o=w -o -print

Możemy adresować 3 i 4, rejestrując numery urządzeń i i-węzłów lub wszystkie pliki $ użytkownik ma uprawnienia do zapisu i zgłasza wszystkie ścieżki plików, które mają te numery dev i i-węzłów. Tym razem możemy skorzystać z bardziej niezawodnych access(2) podejścia:

Coś jak:

find / ! -type l -print0 |
  sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-w,$_' |
  perl -l -0ne '
    ($w,$p) = /(.)(.*)/;
    ($dev,$ino) = stat$p or next;
    $writable{"$dev,$ino"} = 1 if $w;
    push @{$p{"$dev,$ino"}}, $p;
    END {
      for $i (keys %writable) {
        for $p (@{$p{$i}}) {
          print $p;
        }
      }
    }'

5 i 6 są na pierwszy rzut oka skomplikowane przez todrobinę uprawnień. W przypadku katalogów jest to bit z ograniczonym usuwaniem, który uniemożliwia użytkownikom (innym niż właściciel katalogu) usuwanie lub zmianę nazw plików, których nie są właścicielami (nawet jeśli mają dostęp do zapisu w katalogu).

Na przykład, jeśli wrócimy do naszego wcześniejszego przykładu, jeśli masz dostęp do zapisu /a, powinieneś być w stanie zmienić nazwę /a/bna /a/c, a następnie ponownie utworzyć /a/bkatalog i nowy filew nim. Ale jeśli tbit jest włączony, /aa ty nie jesteś właścicielem /a, możesz to zrobić tylko wtedy, gdy jesteś właścicielem /a/b. To daje:

  • Jeśli posiadasz katalog, zgodnie z 1, możesz przyznać sobie prawo do zapisu, a bit t nie ma zastosowania (i możesz go i tak usunąć), więc możesz usunąć / zmienić nazwę / odtworzyć dowolny plik lub katalog, więc wszystkie znajdujące się tam ścieżki plików można przepisać dowolną zawartością.
  • Jeśli nie jesteś właścicielem, ale masz dostęp do zapisu, to:
    • Albo tbit nie jest ustawiony, a ty jesteś w takim samym przypadku jak powyżej (wszystkie ścieżki do plików są twoje).
    • lub jest ustawiony, a następnie nie możesz modyfikować plików, których nie jesteś właścicielem lub nie masz dostępu do zapisu, więc dla naszego celu znalezienia ścieżek plików, które możesz zmodyfikować, to tak samo, jak w ogóle nie mieć uprawnień do zapisu.

Możemy więc rozwiązać wszystkie 1, 2, 5 i 6 za pomocą:

find / -type d \
  \( \
    -user "$user" -prune -exec find {} + -o \
    \( -group $groups \) \( -perm -g=x -o -prune \) -o \
    -perm -o=x -o -prune \
  \) ! -type d -o -type l -o \
    -user "$user" \( -type d -o -print \) -o \
    \( -group $groups \) \( ! -perm -g=w -o \
       -type d ! -perm -1000 -exec find {} + -o -print \) -o \
    ! -perm -o=w -o \
    -type d ! -perm -1000 -exec find {} + -o \
    -print

To i rozwiązanie dla 3 i 4 są niezależne, możesz scalić ich wyniki, aby uzyskać pełną listę:

{
  find / ! -type l -print0 |
    sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-w,$_' |
    perl -0lne '
      ($w,$p) = /(.)(.*)/;
      ($dev,$ino) = stat$p or next;
      $writable{"$dev,$ino"} = 1 if $w;
      push @{$p{"$dev,$ino"}}, $p;
      END {
        for $i (keys %writable) {
          for $p (@{$p{$i}}) {
            print $p;
          }
        }
      }'
  find / -type d \
    \( \
      -user "$user" -prune -exec sh -c 'exec find "$@" -print0' sh {} + -o \
      \( -group $groups \) \( -perm -g=x -o -prune \) -o \
      -perm -o=x -o -prune \
    \) ! -type d -o -type l -o \
      -user "$user" \( -type d -o -print0 \) -o \
      \( -group $groups \) \( ! -perm -g=w -o \
         -type d ! -perm -1000 -exec sh -c 'exec find "$@" -print0' sh {} + -o -print0 \) -o \
      ! -perm -o=w -o \
      -type d ! -perm -1000 -exec sh -c 'exec find "$@" -print0' sh {} + -o \
      -print0
} | perl -l -0ne 'print unless $seen{$_}++'

Jak powinno być jasne, jeśli przeczytałeś wszystko do tej pory, jego część przynajmniej dotyczy uprawnień i własności, a nie innych funkcji, które mogą przyznawać lub ograniczać dostęp do zapisu (FS tylko do odczytu, listy ACL, niezmienna flaga, inne funkcje bezpieczeństwa ...) A ponieważ przetwarzamy je na kilku etapach, niektóre z tych informacji mogą być niepoprawne, jeśli pliki / katalogi są tworzone / usuwane / zmieniane nazwy lub ich uprawnienia / własność modyfikowane podczas działania tego skryptu, na przykład na zajętym serwerze plików z milionami plików .

Uwagi na temat przenośności

Cały ten kod jest standardowy (POSIX, Unix dla tbitów), z wyjątkiem:

  • -print0jest rozszerzeniem GNU obsługiwanym teraz także przez kilka innych implementacji. Z findwdrożeń, które nie mają poparcia dla niego, można użyć -exec printf '%s\0' {} +zamiast tego, i wymienić -exec sh -c 'exec find "$@" -print0' sh {} +z -exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +.
  • perlnie jest poleceniem określonym w POSIX, ale jest powszechnie dostępne. Potrzebujesz perl-5.6.0lub więcej -Mfiletest=access.
  • zshnie jest poleceniem określonym przez POSIX. Powyższy zshkod powinien działać z zsh-3 (1995) i nowszymi.
  • sudonie jest poleceniem określonym przez POSIX. Kod powinien działać z dowolną wersją, o ile konfiguracja systemu pozwala na działanie perljako dany użytkownik.
Stéphane Chazelas
źródło
Co to jest dostęp do wyszukiwania ? Nigdy nie słyszałem o tym w tradycyjnych uprawnieniach: czytanie, pisanie, wykonywanie.
bela83
2
@ bela83, wykonaj uprawnienie do katalogu (nie wykonujesz katalogów) przekłada się na wyszukiwanie . To jest możliwość dostępu do plików w nim zawartych. Możesz wyświetlić zawartość katalogu, jeśli masz uprawnienia do odczytu, ale nie możesz nic zrobić z plikami w nim zawartymi, chyba że masz również xuprawnienia do wyszukiwania ( bitowe) w katalogu. Możesz także mieć uprawnienia do wyszukiwania, ale nie możesz czytać , co oznacza, że ​​pliki w nim są ukryte, ale jeśli znasz ich nazwę, możesz uzyskać do nich dostęp. Typowym przykładem jest katalog plików sesji php (coś w rodzaju / var / lib / php).
Stéphane Chazelas
2

Możesz łączyć opcje z findpoleceniem, aby znaleźć pliki o określonym trybie i właścicielu. Na przykład:

$ find / \( -group staff -o -group users \) -and -perm -g+w

Powyższe polecenie wyświetli listę wszystkich wpisów należących do grupy „personel” lub „użytkownicy” i mających uprawnienia do zapisu dla tej grupy.

Powinieneś także sprawdzić wpisy, które są własnością użytkownika, a także pliki, które można zapisywać na całym świecie, więc:

$ find / \( -user yourusername -or \
             \(  \( -group staff -o -group users \) -and -perm -g+w \
             \) -or \
            -perm -o+w \
         \)

Jednak to polecenie nie pasuje do pozycji z rozszerzoną listą ACL. Możesz suwięc znaleźć wszystkie zapisywalne wpisy:

# su - yourusername
$ find / -writable
apaul
źródło
To by powiedziało, że plik z r-xrwxrwx yourusername:anygrouplub r-xr-xrwx anyone:staffjest do zapisu.
Stéphane Chazelas
Raportowałby również, że pliki do zapisu, które znajdują się w katalogach yourusername, nie mają dostępu.
Stéphane Chazelas
1

Podejście zależy od tego, co naprawdę testujesz.

  1. Czy chcesz zapewnić dostęp do zapisu?
  2. Czy chcesz zapewnić brak dostępu do zapisu?

Jest tak, ponieważ istnieje tak wiele sposobów, aby dojść do 2), a odpowiedź Stéphane obejmuje je dobrze (niezmienny należy pamiętać) i przypomnieć, że istnieją również środki fizyczne, takie jak odmontowanie dysku lub uczynienie go tylko do odczytu na poziom sprzętowy (zakładki dyskietek). Zgaduję, że twoje tysiące plików znajdują się w różnych katalogach i chcesz raport lub porównujesz z listą główną. (Kolejne znęcanie się nad kukiełką tylko czeka, aby się wydarzyło).

Prawdopodobnie chcesz przechodzić drzewo Perla przez Stéphane'a i w razie potrzeby łączyć dane wyjściowe z listą (su przechwyci również brakujące wykonanie w katalogach nadrzędnych?). Jeśli macierzyństwo zastępcze stanowi problem z wydajnością, czy robisz to dla „dużej liczby” użytkowników? Czy jest to zapytanie online? Jeśli jest to stały stały wymóg, może być czas na rozważenie produktu innej firmy.

mckenzm
źródło
0

Możesz to zrobić...

find / ! -type d -exec tee -a {} + </dev/null

... dla listy wszystkich plików, do których użytkownik nie może zapisać w formie zapisanej na stderr w formie ...

"tee: cannot access %s\n", <pathname>" 

...lub podobne.

Poniższe komentarze zawierają uwagi na temat problemów, jakie może mieć to podejście, oraz wyjaśnienie poniżej, dlaczego może ono działać. Bardziej rozsądnie jednak powinieneś prawdopodobnie tylko find zwykłe pliki, takie jak:

find / -type f -exec tee -a {} + </dev/null

W skrócie, teewypisze błędy podczas próby open()utworzenia pliku z jedną z dwóch flag ...

O_WRONLY

Otwarty tylko do pisania.

O_RDWR

Otwarty do czytania i pisania. Wynik jest niezdefiniowany, jeśli ta flaga zostanie zastosowana do FIFO.

... i spotyka ...

[EACCES]

Odmowa dostępu do wyszukiwania dla komponentu prefiksu ścieżki lub plik istnieje, a uprawnienia określone przez oflag są odrzucane, lub plik nie istnieje i odmowa zapisu dla katalogu nadrzędnego pliku, który ma zostać utworzony, lub O_TRUNC jest określono i odmówiono uprawnienia do zapisu.

... jak określono tutaj :

teeNarzędzie może kopiować standardowe wejście na standardowe wyjście, tworząc kopię na zero lub więcej plików. Narzędzie tee nie buforuje wyjścia.

Jeśli -aopcja nie zostanie określona, ​​pliki wyjściowe zostaną zapisane (patrz Odczyt pliku, zapis i tworzenie ) ...

... POSIX.1-2008 wymaga funkcjonalności równoważnej z użyciem O_APPEND ...

Ponieważ musi to sprawdzić w ten sam sposób test -w...

-w nazwa ścieżki

Prawda, jeśli nazwa ścieżki rozwiązuje istniejącą pozycję katalogu dla pliku, dla którego udzielone zostanie zezwolenie na zapis do pliku, jak zdefiniowano w Odczyt pliku, Zapis i Tworzenie . False, jeśli ścieżka nie może zostać rozwiązany lub jeśli pathname postanawia istniejącego wpisu katalogu dla pliku, dla których uprawnienie do zapisu pliku nie zostanie przyznana.

Oboje sprawdzają EACCESS .

mikeserv
źródło
Przy takim podejściu najprawdopodobniej napotkasz limit liczby jednocześnie otwartych plików (chyba że liczba plików jest niska). Uważaj na skutki uboczne związane z urządzeniami i nazwanymi potokami. Otrzymasz inny komunikat o błędzie dla gniazd.
Stéphane Chazelas
@ StéphaneChazelas - Wszystko wt. - Myślę, że prawdą może być również to, że teezawiesi się, chyba że zostanie wyraźnie przerwane raz na cykl. To była najbliższa rzecz, o której mogłem pomyśleć [ -w... chociaż - jej efekty powinny być bliskie, ponieważ gwarantuje, że użytkownik może OAPPENDOWAĆ plik. Znacznie łatwiejsze niż którakolwiek z opcji byłoby paxz -oopcjami formatowania i / lub -tporównywaniem EACCESS- ale za każdym razem, gdy sugeruję, paxludzie wydają się go wzruszać. Zresztą jedyne pax, jakie znalazłem, które spełnia standard, to AST - w takim przypadku równie dobrze możesz ich użyć ls.
mikeserv