Intereting Posts
Unix ищет и удаляет переменную (содержит косую черту) из файла Поддерживает ли режим Realtek RTL8192SU режим точки доступа Измерьте время, чтобы получить адрес DHCP? После каждой перезагрузки громкоговорители имеют громкость 0 СООТВЕТСТВУЮЩЕЕ, УСТАНОВЛЕННОЕ состояние в iptables Синтаксическая ошибка Bash, когда «else» следует за пустой категорией «then» Эквивалент POSIX для тайм-аута GNU? Найдите процесс, который потребляет память Выгода от модуля ядра, скомпилированного внутри ядра? Задайте размер хранилища при создании виртуальной виртуальной машины VM Эффективный механизм для определения того, был ли открытый файл изменен извне? Сценарий Bash, который может протестировать конкретную библиотеку lib CSV – преобразование НЕКОТОРЫХ столбцов в строки с дублированными данными Загрузить ВСЕ rpms для продукта Почему сценарий в /etc/rc6.d не запускается при перезагрузке?

Почему некоторые оболочки `read` builtin не могут прочитать всю строку из файла в` / proc`?

В некоторых оболочках, подобных Bourne, встроенное read не может прочитать всю строку из файла в /proc (команда, приведенная ниже, должна быть запущена в zsh , заменить $=shell на $shell другими оболочками):

 $ 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 требует, чтобы стандартный ввод был текстовым файлом , вызывает ли это требование разнообразное поведение?


Прочитайте определение текстового файла POSIX, я делаю некоторую проверку:

 $ od -ta </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 

В содержании /proc/sys/fs/file-max нет символа NUL , а также find его как обычный файл (это ошибка в find ?).

Я предполагаю, что оболочка сделала что-то под капотом, например file :

 $ file /proc/sys/fs/file-max /proc/sys/fs/file-max: empty 

Проблема в том, что эти файлы /proc в Linux отображаются как текстовые файлы в отношении stat()/fstat() , но не ведут себя как таковые.

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

Утилита read должна читать содержимое файлов по одному байту за раз, чтобы не прочесть символ новой строки. Вот что делает dash :

  $ strace -fe read dash -c 'read a < /proc/sys/fs/file-max' read(0, "1", 1) = 1 read(0, "", 1) = 0 

Некоторые оболочки, такие как bash имеют оптимизацию, чтобы избежать необходимости делать так много системных вызовов read() . Сначала они проверяют, доступен ли файл, и если да, читайте в кусках, как они знают, что они могут поместить курсор назад после строки новой строки, если они прочитали это:

 $ strace -e lseek,read bash -c 'read a' < /proc/sys/fs/file-max lseek(0, 0, SEEK_CUR) = 0 read(0, "1628689\n", 128) = 8 

При использовании bash вас все еще будут проблемы с файлами proc размером более 128 байтов и могут быть прочитаны только в одном системном вызове.

Кажется, что bash отключает эту оптимизацию, когда используется опция -d .

ksh93 делает оптимизацию еще больше, чтобы стать фиктивным. Чтение ksh93 выполняет поиск назад, но запоминает дополнительные данные, которые он прочитал для следующего read , поэтому следующее read (или любые другие его встроенные функции, которые читают данные, такие как cat или head ) даже не пытается read данные (даже если что данные были изменены другими командами между ними):

 $ seq 10 > a; ksh -c 'read a; echo test > a; read b; echo "$a $b"' < a 1 2 $ seq 10 > a; sh -c 'read a; echo test > a; read b; echo "$a $b"' < a 1 st 

Если вам интересно узнать почему? это так, вы можете увидеть ответ в источниках ядра здесь :

  if (!data || !table->maxlen || !*lenp || (*ppos && !write)) { *lenp = 0; return 0; } 

В принципе, поиск ( *ppos не 0) не реализован для чтения ( !write ) значений sysctl, которые являются числами. Всякий раз, когда чтение выполняется из /proc/sys/fs/file-max , подпрограмма __do_proc_doulongvec_minmax() вызывается из записи для file-max в таблице конфигурации в том же файле.

Другие записи, такие как /proc/sys/kernel/poweroff_cmd , реализуются через proc_dostring() что позволяет proc_dostring() , поэтому вы можете сделать dd bs=1 на нем и без проблем прочитать из своей оболочки.

Обратите внимание, что поскольку ядро ​​2.6 чтение большинства /proc было реализовано через новый API, называемый seq_file, и это поддерживает запросы, поэтому, например, чтение /proc/stat не должно вызывать проблем. В /proc/sys/ реализация, как мы видим, не использует этот api.

С первой попытки это выглядит как ошибка в оболочках, которые возвращают меньше реальной оболочки Bourne или ее производных (sh, bosh, ksh, реликвия).

Оригинальная Bourne Shell пытается прочитать блок (64 байта), новее вариантов Bourne Shell читает 128 байтов, но они начинают читать снова, если нет нового символа линии.

Предыстория: / procfs и аналогичные реализации (например, установленный виртуальный файл /etc/mtab ) имеют динамический контент, а вызов stat() не вызывает повторного создания динамического содержимого. По этой причине размер такого файла (от чтения до EOF) может отличаться от того, что возвращает stat() .

Учитывая, что стандарт POSIX требует, чтобы утилиты ожидали коротких чтений в любое время, программное обеспечение, которое считает, что read() который возвращает меньше, чем упорядоченное количество байтов, является индикацией EOF. Правильно реализованная утилита вызывает read() второй раз в случае, если она возвращает меньше ожидаемого – до тех пор, пока не будет возвращено значение 0. В случае read встроенного, конечно, было бы достаточно читать до EOF или до тех пор, пока не увидит NL .

Если вы запустили truss или клон фермы, вы должны иметь возможность проверить это неправильное поведение для оболочек, которые возвращают только 6 в вашем эксперименте.

В этом особом случае, похоже, это ошибка ядра Linux, см.

 $ sdd -debug bs=1 if= /proc/sys/fs/file-max Simple copy ... readbuf (3, 12AC000, 1) = 1 writebuf (1, 12AC000, 1) 8readbuf (3, 12AC000, 1) = 0 sdd: Read 1 records + 0 bytes (total of 1 bytes = 0.00k). sdd: Wrote 1 records + 0 bytes (total of 1 bytes = 0.00k). 

Ядро Linux возвращает 0 со вторым, и это, конечно, неверно.

Вывод: оболочки, которые сначала пытаются прочитать достаточно большой фрагмент данных, не вызывают ошибку ядра Linux.

Файлы под / proc иногда используют символ NULL для разделения полей внутри файла. Кажется, что чтение не в состоянии справиться с этим.