diff --git a/src/downloader/constants.py b/src/downloader/constants.py index 9672889..8207c71 100644 --- a/src/downloader/constants.py +++ b/src/downloader/constants.py @@ -64,6 +64,15 @@ # Linux Update files FILE_MiSTer_version = '/MiSTer.version' FILE_Linux_7z = '/media/fat/linux/7za' +FILE_Linux_user_files = [ + # source -> destination + ('/media/fat/linux/hostname', '/etc/hostname'), + ('/media/fat/linux/hosts', '/etc/hosts'), + ('/media/fat/linux/interfaces', '/etc/network/interfaces'), + ('/media/fat/linux/resolv.conf', '/etc/resolv.conf'), + ('/media/fat/linux/dhcpd.conf', '/etc/dhcpd.conf'), + ('/media/fat/linux/fstab', '/etc/fstab'), +] # Reboot files FILE_downloader_needs_reboot_after_linux_update = '/tmp/downloader_needs_reboot_after_linux_update' diff --git a/src/downloader/linux_updater.py b/src/downloader/linux_updater.py index 9be9fc0..e35e348 100644 --- a/src/downloader/linux_updater.py +++ b/src/downloader/linux_updater.py @@ -19,7 +19,9 @@ import subprocess import json import sys -from downloader.constants import FILE_downloader_needs_reboot_after_linux_update, FILE_MiSTer_version, FILE_Linux_7z +import tempfile +import os.path +from downloader.constants import FILE_downloader_needs_reboot_after_linux_update, FILE_MiSTer_version, FILE_Linux_7z, FILE_Linux_user_files class LinuxUpdater: @@ -29,6 +31,7 @@ def __init__(self, config, file_system, file_downloader_factory, logger): self._logger = logger self._file_system = file_system self._linux_descriptions = [] + self._user_files = [] def update_linux(self, importer_command): self._logger.bench('Update Linux start.') @@ -68,6 +71,11 @@ def _update_linux_impl(self, importer_command): self._logger.debug('current_linux_version "%s" matches db linux: %s' % (current_linux_version, linux['version'])) return + for source, destination in FILE_Linux_user_files: + if self._file_system.is_file(source): + self._logger.print('Custom "%s" file will be installed to the updated Linux system from the "linux" folder.' % (os.path.basename(source))) + self._user_files.append((source, destination)) + self._logger.print('Linux will be updated from %s:' % description['id']) self._logger.print('Current linux version -> %s' % current_linux_version) self._logger.print('Latest linux version -> %s' % linux['version'][-6:]) @@ -148,6 +156,11 @@ def _run_subprocesses(self, linux, linux_path): self._logger.print() return + if len(self._user_files) > 0: + restore_error = self._restore_user_files() + if restore_error: + return + self._logger.print() self._logger.print("======================================================================================") self._logger.print("Hold your breath: updating the Kernel, the Linux filesystem, the bootloader and stuff.") @@ -179,5 +192,53 @@ def _run_subprocesses(self, linux, linux_path): self._logger.print('Error code: %d' % result.returncode) self._logger.print() + def _restore_user_files(self) -> bool: + temp_dir = tempfile.mkdtemp() + self._logger.debug('Created temporary directory for image: %s' % temp_dir) + + mount_cmd = 'mount -t ext4 /media/fat/linux.update/files/linux/linux.img {0}'.format(temp_dir) + self._logger.debug('Mounting temporary Linux image with command: %s' % mount_cmd) + result = subprocess.run(mount_cmd, shell=True, stderr=subprocess.STDOUT) + + if result.returncode != 0: + self._logger.print('ERROR! Could not mount updated Linux image, try again later.') + self._logger.print('Error code: %d' % result.returncode) + self._logger.print() + return False + + copy_error = False + self._logger.print('Restoring user Linux configuration files:') + for source, destination in self._user_files: + image_destination = temp_dir + destination + self._logger.debug('Copying "%s" to "%s"' % (source, image_destination)) + self._logger.print(' - Installing "%s" to "%s"...' % (source, destination), end='') + try: + self._file_system.copy(source, image_destination) + except Exception as e: + self._logger.print('ERROR! Could not be installed.') + self._logger.debug('Could not copy "%s" to "%s": %s' % (source, destination, str(e))) + copy_error = True + break + else: + self._logger.print('OK!') + self._logger.print() + + unmount_cmd = 'umount {0}'.format(temp_dir) + self._logger.debug('Unmounting Linux image with command: %s' % unmount_cmd) + result = subprocess.run(unmount_cmd, shell=True, stderr=subprocess.STDOUT) + + if result.returncode != 0: + self._logger.print('ERROR! Could not unmount updated temporary Linux image.') + self._logger.print('Error code: %d' % result.returncode) + self._logger.print() + return False + + if copy_error: + self._logger.print('ERROR! Could not restore user Linux configuration files.') + self._logger.print() + return False + + return True + def needs_reboot(self): return self._file_system.is_file(FILE_downloader_needs_reboot_after_linux_update)