yast/yast-storage-ng

View on GitHub
src/lib/y2storage/clients/inst_prepdisk.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Copyright (c) [2015-2023] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "y2storage"

Yast.import "SlideShow"
Yast.import "Installation"
Yast.import "FileUtils"
Yast.import "Mode"
Yast.import "Report"

module Y2Storage
  module Clients
    # Installation client to commit the storage changes to disk. That includes
    # partitioning, creating volumes and filesystem, writing /etc/fstab in the
    # target system and any other action handled by libstorage.
    class InstPrepdisk
      include Yast
      include Yast::I18n
      include Yast::Logger

      EFIVARS_PATH = "/sys/firmware/efi/efivars".freeze

      # Constructor
      #
      # @param commit_callbacks [Storage::CommitCallbacks, nil]
      def initialize(commit_callbacks: nil)
        textdomain "storage"
        @commit_callbacks = commit_callbacks
      end

      def run
        return :auto if Mode.update

        log.info("BEGIN of inst_prepdisk")
        Yast::SlideShow.MoveToStage("disk")
        if commit
          log.info("END of inst_prepdisk")
          :next
        else
          log.info("ABORTED inst_prepdisk")
          :abort
        end
      end

      protected

      # Callbacks to use for commit
      #
      # @return [Storage::CommitCallbacks, nil]
      attr_reader :commit_callbacks

      # Commits the actions to disk
      #
      # @return [Boolean] true if everything went fine, false if the user
      #   decided to abort
      def commit
        manager.rootprefix = Yast::Installation.destdir
        return false unless manager.commit(force_rw: true, callbacks: commit_callbacks)

        mount_in_target("/dev", "devtmpfs", "-t devtmpfs")
        mount_in_target("/proc", "proc", "-t proc")
        mount_in_target("/sys", "sysfs", "-t sysfs")
        mount_in_target(EFIVARS_PATH, "efivarfs", "-t efivarfs") if mount_efivars?
        mount_in_target("/run", "/run", "--bind")

        true
      end

      def mount_in_target(path, device, options)
        target_path = manager.prepend_rootprefix(path)

        if !Yast::FileUtils.Exists(target_path) && !SCR.Execute(path(".target.mkdir"), target_path)
          raise ".target.mkdir failed"
        end

        log.info "Cmd: mount #{options} #{device} #{target_path}"

        if !SCR.Execute(path(".target.mount"), [device, target_path], options)
          # TRANSLATORS: %s is the path of a system mount like "/dev", "/proc", "/sys"
          Yast::Report.Warning(_("Could not mount %s") % path)
        end

        nil
      end

      # Check if efivars should be mounted, i.e. if /sys/firmware/efi/efivars
      # exists and the system supports the efivarfs filesystem type.
      #
      # @return [Boolean] true if efivarfs should be mounted
      def mount_efivars?
        File.exist?(EFIVARS_PATH) && efivarfs_support?
      end

      # Check if the efivarfs filesystem type is supported on this system,
      # i.e. if /proc/filesystems contains a line with "efivarfs".
      #
      # Notice that a system might have the /sys/firmware/efi/efivars file,
      # but no support for the efivarfs filesystem to actually mount it.
      # See https://bugzilla.suse.com/show_bug.cgi?id=1174029
      #
      # @return [Boolean] true if efivarfs is supported
      def efivarfs_support?
        File.readlines("/proc/filesystems").any? { |line| line =~ /efivarfs/ }
      rescue Errno::ENOENT => e
        log.error("Can't check efivarfss support: #{e}")
        false
      end

      def manager
        Y2Storage::StorageManager.instance
      end
    end
  end
end