Интересно, как приложения-убийцы, такие как Thunderbird или Firefox, могут обновляться через системный менеджер пакетов, пока они еще работают? Что происходит со старым кодом во время их обновления? Что мне делать, если я хочу написать программу a.out, которая обновляется во время работы?
files
upgrade
executable
ubuplex
источник
источник
Ответы:
Замена файлов в целом
Во-первых, существует несколько стратегий для замены файла:
Откройте существующий файл для записи, обрежьте его до 0 длины и запишите новый контент. (Менее распространенный вариант - открыть существующий файл, перезаписать старый контент новым, урезать файл до новой длины, если он короче.) В терминах оболочки:
Удалите старый файл и создайте новый файл с тем же именем. В терминах оболочки:
Запишите новый файл с временным именем, затем переместите новый файл к существующему имени. Этот шаг удаляет старый файл. В терминах оболочки:
Я не буду перечислять все различия между стратегиями, я просто упомяну некоторые важные здесь. С помощью Stategy 1, если какой-либо процесс в настоящее время использует файл, процесс видит новое содержимое по мере его обновления. Это может вызвать некоторую путаницу, если процесс ожидает, что содержимое файла останется прежним. Обратите внимание, что речь идет только о процессах, которые открывают файл (как видно в
lsof
или в ; интерактивные приложения, у которых открыт документ (например, открытие файла в редакторе), обычно не оставляют файл открытым, они загружают содержимое файла во время Операция «открыть документ» и они заменяют файл (используя одну из стратегий выше) во время операции «сохранить документ»./proc/PID/fd/
При стратегиях 2 и 3, если файл
somefile
открыт в каком-либо процессе , старый файл остается открытым во время обновления содержимого. В стратегии 2 этап удаления файла фактически удаляет только запись файла в каталоге. Сам файл удаляется только в том случае, если у него нет ведущей к нему записи каталога (в типичных файловых системах Unix может быть несколько записей каталога для одного и того же файла ), и ни у одного процесса его нет. Вот способ убедиться в этом - файл удаляется только после завершенияsleep
процесса (rm
удаляется только его запись в каталоге).В стратегии 3 шаг перемещения нового файла к существующему имени удаляет запись каталога, ведущую к старому контенту, и создает запись каталога, ведущую к новому контенту. Это делается за одну атомарную операцию, поэтому у этой стратегии есть главное преимущество: если процесс в любой момент открывает файл, он увидит либо старый, либо новый контент - нет риска получить смешанный контент или файл не будет существующий.
Замена исполняемых файлов
Если вы попробуете стратегию 1 с запущенным исполняемым файлом в Linux, вы получите ошибку.
«Текстовый файл» означает файл, содержащий исполняемый код по неясным историческим причинам . Linux, как и многие другие варианты Unix, отказывается перезаписывать код работающей программы; несколько вариантов Unix позволяют это, приводя к сбоям, если новый код не был очень хорошо продуманной модификацией старого кода.
В Linux вы можете перезаписать код динамически загружаемой библиотеки. Это может привести к сбою программы, которая его использует. (Возможно, вы не сможете наблюдать это,
sleep
поскольку он загружает весь библиотечный код, который ему нужен при запуске. Попробуйте более сложную программу, которая делает что-то полезное после сна, напримерperl -e 'sleep 9; print lc $ARGV[0]'
.)Если интерпретатор выполняет сценарий, файл сценария открывается интерпретатором обычным способом, поэтому защита от перезаписи сценария отсутствует. Некоторые интерпретаторы читают и анализируют весь сценарий перед началом выполнения первой строки, другие читают сценарий по мере необходимости. См. Что произойдет, если вы редактируете скрипт во время выполнения? и как Linux работает со скриптами оболочки? Больше подробностей.
Стратегии 2 и 3 также безопасны для исполняемых файлов: хотя выполняемые исполняемые файлы (и динамически загружаемые библиотеки) не являются открытыми файлами в смысле наличия файлового дескриптора, они ведут себя очень похожим образом. Пока какая-то программа выполняет код, файл остается на диске даже без записи в каталоге.
Обновление приложения
Большинство менеджеров пакетов используют стратегию 3 для замены файлов из-за основного преимущества, упомянутого выше - в любой момент времени открытие файла приводит к его действительной версии.
Обновление приложения может прерваться, если обновление одного файла является атомарным, обновление приложения в целом не происходит, если приложение состоит из нескольких файлов (программы, библиотеки, данные и т. Д.). Рассмотрим следующую последовательность событий:
На шаге 3 запущенный экземпляр старой версии приложения открывает файл данных из новой версии. Работает ли это или нет, зависит от приложения, из какого он файла и насколько файл был изменен.
После обновления вы заметите, что старая программа все еще работает. Если вы хотите запустить новую версию, вам придется выйти из старой программы и запустить новую версию. Менеджеры пакетов обычно убивают и перезапускают демонов при обновлении, но оставляют приложения конечного пользователя в покое.
У некоторых демонов есть специальные процедуры для обработки обновлений без необходимости убивать демона и ждать перезапуска нового экземпляра (что приводит к прерыванию работы службы). Это необходимо в случае init , который нельзя убить; Системы init предоставляют способ, чтобы запрос запущенного экземпляра
execve
заменил себя новой версией.источник
unlink
, как вы расскажете позже. Может быть, «заменяет существующее имя», но это все еще несколько сбивает с толку.Обновление можно запустить во время работы программы, но запущенная программа, которую вы видите, на самом деле является ее старой версией. Старый двоичный файл остается на диске, пока вы не закроете программу.
Объяснение: в системах Linux файл является просто индексом, который может иметь несколько ссылок на него. Например.
/bin/bash
То, что вы видите, это просто ссылкаinode 3932163
на мою систему. Вы можете найти, на какой инод что-то ссылается, выполнивls --inode /path
ссылку. Файл (inode) удаляется только в том случае, если на него указывают нулевые ссылки, и он не используется какой-либо программой. Когда менеджер пакетов обновляется, например./usr/bin/firefox
, он сначала отменяет связь (удаляет жесткую ссылку/usr/bin/firefox
), затем создает новый файл с именем,/usr/bin/firefox
который является жесткой ссылкой на другой индекс (тот, который содержит новуюfirefox
версию). Старый inode теперь помечен как свободный и может использоваться повторно для хранения новых данных, но остается на диске (inode создается только при сборке файловой системы и никогда не удаляется). На следующем стартеfirefox
будет использован новый.Если вы хотите написать программу, которая «обновляет» себя во время работы, единственное возможное решение, о котором я могу подумать, - это периодически проверять временную метку своего двоичного файла, и, если она новее, чем время запуска программы, то перезагрузить себя.
источник
apt
Работа по обновлению Debian ? Я могу обновить любую работающую программу без проблем, включаяIceweasel
(Firefox
).dpkg
) не перезаписывает файлы. Вместо этого он отменяет связь и помещает новый под тем же именем. Смотрите вопрос и ответ, на который я ссылаюсь, для объяснения.ln
(жесткие ссылки). Вы можете удалить имена сrm
(unlink). Вы не можете удалить файл напрямую, только удалить его имена. Если файл не имеет имен и, кроме того, не открыт, ядро удалит его. У запущенной программы есть файл, из которого она запускается, так что даже после удаления всех имен файл все еще присутствует.Интересно, как приложения-убийцы, такие как Thunderbird или Firefox, могут обновляться через системный менеджер пакетов, пока они еще работают? Что ж, я могу сказать вам, что это не очень хорошо работает ... У меня был ужасный перерыв в работе Firefox, если я оставил его открытым, пока выполнялось обновление пакета. Мне иногда приходилось насильно его убивать и перезапускать, потому что он был настолько сломан, что даже не смог его правильно закрыть.
Что происходит со старым кодом во время их обновления? Обычно в Linux программа загружается в память, поэтому исполняемый файл на диске не нужен и не используется во время работы программы. На самом деле вы можете даже удалить исполняемый файл, и программе должно быть все равно ... Однако некоторым программам может понадобиться исполняемый файл, и некоторые ОС (например, Windows) блокируют исполняемый файл, предотвращая удаление или даже переименовывание / перемещение, в то время как Программа запущена. Firefox ломается, потому что он на самом деле довольно сложный и использует кучу файлов данных, которые говорят ему, как создать свой GUI (пользовательский интерфейс). Во время обновления пакета эти файлы перезаписываются (обновляются), поэтому, когда старый исполняемый файл Firefox (в памяти) пытается использовать новые файлы GUI, могут происходить странные вещи ...
Что мне делать, если я хочу написать программу a.out, которая обновляется во время работы? На ваш вопрос уже есть много ответов. Проверьте это: /programming/232347/how-should-i-implement-an-auto-updater Кстати, вопросы о программировании лучше решать в StackOverflow.
источник