Відповіді:
Як згадував @Kusalananda, зазвичай оновлення виконується шляхом видалення старого файлу та створення нового з тим самим іменем. Це фактично створить новий файл з новим inode, залишивши систему вільною для використання старого, поки він відкритий.
Як спрощений приклад, такі речі, як
rm /bin/cat
cp /new/version/of/cat /bin/cat
створить логічно новий файл і працює, хоча він cat
може працювати. Те саме стосується бібліотек. (Наведене вище - приклад, а не надійний спосіб оновлення файлу в реальному світі.)
Хтось міг спробувати змінити бінарне місце замість того, щоб створити нове з тим же ім’ям. У цьому випадку принаймні Linux фактично перешкоджає внесенню змін у виконуваний файл:
window 1 # ./cat
window 2 # echo foobar > cat
-bash: cat: Text file busy
Однак, схоже, це не працює з динамічно завантаженими бібліотеками ...
Я зробив копію libc.so.6
для тестування і заповнив її нулями, поки він використовувався:
window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ldd ./cat
linux-vdso.so.1 (0x00007ffcfaf30000)
libc.so.6 => /tmp/lib/libc.so.6 (0x00007f1145e67000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1146212000)
window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ./cat
foo
foo
Segmentation fault
(Тим часом в іншому вікні, після foo
, перед сегментом за замовчуванням)
window 2 /tmp/lib# dd if=/dev/zero of=libc.so.6 bs=1024 count=2000
Насправді сама програма не може проти цього, оскільки я фактично редагував її код в Інтернеті.
(Можливо, це залежатиме від системи. Я протестував на Debian Jessie 8.5, Linux 3.16.7-ckt25-2 + deb8u3. Зокрема, системи IIRC Windows ще більш агресивно ставляться до запобігання модифікації файлів під час використання.)
Тому я думаю, що відповідь полягає в тому, що оновлення, як правило, робиться таким чином, щоб уникнути будь-яких проблем, і в цьому допомагають внутрішні файлові системи. Але (в Linux), схоже, немає жодних гарантій проти фактично пошкодження динамічних бібліотек.
install
Утиліта зазвичай використовується для речей , як це. Не потрібно явно отримувати rm
цільовий файл. Крім того, він зберігає дозволи на існуючий файл, може створити резервну копію, встановити новий режим тощо. Приклад використання:install /new/version/of/cat /bin/cat
rm
+ cp
. Можливо, також було б розумно розмістити новий файл на місці атомістично з перейменуванням, уникаючи короткого вікна, в якому немає жодної версії. (Хоча GNU install
навіть не здається цього робити, hmpf.)
rm
), він ще не видалений. Він буде існувати на диску і все ще може бути прочитаний усіма процесами, у яких він відкритий. Він буде видалений лише тоді, коли його кількість жорстких посилань досягне нуля І кількість прецесій з відкритим файлом досягне нуля.
install
Утиліта спеціально небезпечна! Він замінює цільовий файл на місці, а не замінює його атомно. mv
(з джерелом і dest в одному каталозі, джерело, як правило, тимчасовий файл) - єдиний безпечний спосіб встановлення файлів.
strace
розповідаю, install
в GNU coreutils від’єднує цільовий файл і потім копіює новий на своє місце. Що означає, що є коротке вікно, під час якого файл є частковим. Він не встановлює файл атомно на перейменування.
Файли не будуть "належним чином видалені", якщо вони від’єднані, поки вони все ще відкриваються. Коли вони закриті, дисковий простір, який вони використовували, знову буде вважатися "вільним". Це стосується також запущених додатків та їх спільних бібліотек.
Єдине, що я можу побачити, як не вдалося, було б, якщо програма, що використовується dlopen()
для завантаження спільної бібліотеки на вимогу, або якщо програма мала отримати доступ до інших файлів на вимогу, таких як словники, теми тем чи інші файли, які раптово зникли.
Для ілюстрації: Запуск vim
в одному сеансі оболонки під час видалення інсталяції vim
в іншому сеансі оболонки не «пошкоджується» або припиняється поточно запущений vim
сеанс. Але деякі речі почнуть виходити з ладу, як, наприклад, перевірка орфографії, яка вимагає vim
відкриття файлів при її встановленні.
ln -sf
при заміні через бібліотеку, тому що-f
дозволив вам «перезапису» існуючому призначення символічної посилання з новим, без нього коли - або «зламаний» ( в відміну , якщо ти зrm
подальшим аln -s
). Тому перед командою library.so вказував на стару версію, наприклад. library.so.4 ... після команди, він просто вказав на library.so.5 (або що завгодно), - ніколи не вказуючи на дійсну бібліотеку.