W niektórych Bourne'a jak muszle, read
wbudowane nie może przeczytać cały wiersz z pliku w /proc
(polecenia poniżej powinny być wykonywane w zsh
, wymienić $=shell
z $shell
innymi muszli):
$ for shell in bash dash ksh mksh yash zsh schily-sh heirloom-sh "busybox sh"; do
printf '[%s]\n' "$shell"
$=shell -c 'IFS= read x </proc/sys/fs/file-max; echo "$x"'
done
[bash]
602160
[dash]
6
[ksh]
602160
[mksh]
6
[yash]
6
[zsh]
6
[schily-sh]
602160
[heirloom-sh]
602160
[busybox sh]
6
read
standard wymaga, aby standardem był plik tekstowy , czy to wymaganie powoduje różnorodne zachowania?
Przeczytaj definicję pliku tekstowego POSIX, dokonuję weryfikacji:
$ od -t a </proc/sys/fs/file-max
0000000 6 0 2 1 6 0 nl
0000007
$ find /proc/sys/fs -type f -name 'file-max'
/proc/sys/fs/file-max
Nie ma żadnej NUL
postaci w treści /proc/sys/fs/file-max
, a także find
zgłosił go jako zwykły plik (czy to błąd find
?).
Myślę, że skorupa zrobiła coś pod maską, na przykład file
:
$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty
strace
oparte na wyjaśnieniach jest znacznie łatwiejsze do zrozumienia!cat /proc/sys/fs/file-max | ...
, problem zniknie.procfs
nie można obsłużyć wielu kolejnychread(2)
wywołań tego samego pliku; zachowanie nie zależy od powłoki. Używaniecat
icat
przesyłanie potokowe działa, ponieważ czyta plik w wystarczająco dużych porcjach;read
wbudowana powłoka odczytuje następnie z potoku po jednym znaku na raz.mksh
.read -N 10 a < /proc/sys/fs/file-max
zsh
:read -u0 -k10
(lub użyjsysread
;$mapfile[/proc/sys/fs/file-max]
nie działa, ponieważ tych plików nie można edytowaćmmap
). W każdym razie za pomocą dowolnej powłoki zawsze możnaa=$(cat /proc/sys/fs/file-max)
. Z niektórymi tymmksh
,zsh
iksh93
,a=$(</proc/sys/fs/file-max)
również działa i nie widelec proces wspólnego czytania.Jeśli chcesz wiedzieć, dlaczego? tak jest, możesz zobaczyć odpowiedź w źródłach jądra tutaj :
Zasadniczo wyszukiwanie (
*ppos
nie 0) nie jest realizowane dla odczytów (!write
) wartości sysctl, które są liczbami. Ilekroć wykonywany jest odczyt/proc/sys/fs/file-max
, dana procedura__do_proc_doulongvec_minmax()
jest wywoływana z pozycji dla tabelifile-max
konfiguracji w tym samym pliku.Inne wpisy, takie jak
/proc/sys/kernel/poweroff_cmd
zaimplementowane, za pomocąproc_dostring()
których zezwala na szukanie, dzięki czemu możesz to zrobićdd bs=1
i czytać z powłoki bez żadnych problemów.Zauważ, że ponieważ jądro 2.6 większość
/proc
odczytów zostało zaimplementowanych za pomocą nowego API o nazwie plik_sekw. I obsługuje to wyszukiwanie, więc np. Czytanie/proc/stat
nie powinno powodować problemów./proc/sys/
Wdrożenie, jak widzimy, nie używa tego API.źródło
Przy pierwszej próbie wygląda to jak błąd w pociskach, które zwracają mniej niż rzeczywista Powłoka Bourne'a lub jej pochodne (sh, bosh, ksh, pamiątka).
Oryginalna powłoka Bourne Shell próbuje odczytać blok (64 bajty), nowsze wersje Bourne Shell czytają 128 bajtów, ale zaczynają czytać ponownie, jeśli nie ma nowego znaku linii.
Tło: / procfs i podobne implementacje (np. Zamontowany
/etc/mtab
plik wirtualny) mają zawartość dynamiczną, astat()
wywołanie nie powoduje najpierw odtworzenia treści dynamicznej. Z tego powodu rozmiar takiego pliku (od odczytu do EOF) może różnić się odstat()
zwracanego.Biorąc pod uwagę, że standard POSIX wymaga narzędzi oczekujących krótkich odczytów w dowolnym momencie, oprogramowanie, które uważa, że a,
read()
który zwraca mniej niż zamówiona ilość bajtów, jest uszkodzone. Prawidłowo zaimplementowane narzędzie wywołujeread()
drugi raz w przypadku, gdy zwróci mniej niż oczekiwano - aż do zwrócenia 0. W przypadkuread
wbudowanego polecenia, to oczywiście być wystarczające, aby czytać ażEOF
lub ażNL
widać.Jeśli uruchomisz
truss
lub klon kratownicy, powinieneś być w stanie zweryfikować to nieprawidłowe zachowanie dla powłok, które powracają tylko6
w eksperymencie.W tym szczególnym przypadku wydaje się, że jest to błąd jądra systemu Linux, patrz:
Jądro Linux zwraca 0 z drugim
read
i jest to oczywiście niepoprawne.Wniosek: Powłoki, które najpierw próbują odczytać wystarczająco duży fragment danych, nie wyzwalają tego błędu jądra systemu Linux.
źródło
Pliki w / proc czasami używają znaku NULL do oddzielenia pól w pliku. Wydaje się, że read nie jest w stanie sobie z tym poradzić.
źródło