Как в bash можно записать файл, перенаправленный для ввода, и можно ли это предотвратить?

Это ожидаемое поведение.

Любой из них предотвратит обновление atime, но они независимы.

В ядре нет системного вызова для запроса общего состояния. Вы должны проверить оба из них самостоятельно.

23
06.10.2020, 11:36
1 ответ

Это связано с тем, как/dev/stdin(на самом деле/proc/self/fd/0)реализовано в Linux (и Cygwin, но не в других системах ).

В Linux открытие /dev/stdinне похоже на выполнение dup(0), он просто заново открывает тот же файл, что и при открытии на fd 0. Он не использует описание открытого файла , на которое ссылается fd 0 (с режимом только для чтения ), но получает совершенно не связанное новое описание открытого файла с режимом как указано в open().

Таким образом, если sops -d /dev/stdinоткрывается /dev/stdinв режиме чтения+записи, а fd 0 был открыт в режиме чтения -только в /some/file, /some/fileбудет открыт в режиме чтения+записи.

По сути, cmd /dev/stdin < fileесть то же самое, что и cmd file < file. Вы обнаружите, что /dev/stdin— это просто символическая ссылка¹ наfile:

/tmp$ namei -l /dev/stdin < file
f: /dev/stdin
drwxr-xr-x root     root     /
drwxr-xr-x root     root     dev
lrwxrwxrwx root     root     stdin -> /proc/self/fd/0
drwxr-xr-x root     root       /
dr-xr-xr-x root     root       proc
lrwxrwxrwx root     root       self -> 73569
dr-xr-xr-x stephane stephane     73569
dr-x------ stephane stephane   fd
lr-x------ stephane stephane   0 -> /tmp/file
drwxr-xr-x root     root         /
drwxrwxrwt root     root         tmp
-rw-r--r-- stephane stephane     file

Может стать хуже. Если бы он открывался с O _TRUNCATE, файл был бы усечен. Если бы fd 0 указывал на конец канала для чтения, а /dev/stdinбыл открыт в режиме только для записи -, вы бы получили другой конец канала.

Но используя:

cat file | cmd /dev/stdin

Защитит от cmdперезаписи file, так как все cmdувидит канал.И даже если бы он открылся только в режиме записи -, он не смог бы вернуться к file, он просто добрался бы до конца записи канала, а единственным файловым дескриптором на конце чтения был бы cmd. ] стандартный ввод.

Другие операционные системы не имеют проблемы, так как открытие /dev/stdinпохоже на выполнение dup(0), поэтому вы получаете то же описание открытого файла , и если вы открываете в несовместимом режиме, open()системный вызов просто терпит неудачу.


¹ технически, как отметил @user414777 в комментариях, /proc/<pid>/fd/<fd>являются волшебными символическими ссылками в том смысле, что они, например, могут достигать мест, недоступных обычным символическим ссылкам, но когда дело доходит до их открытия, прошлое на этапе разрешения пути они действуют как обычные символические ссылки в том смысле, что вы просто открываете целевой файл

31
18.03.2021, 23:00

Теги

Похожие вопросы