All these changes make the build one minute faster (on my local workstation) and the resulting ISO is 34MB smaller (on x86_64, might be different elsewhere). ## Improvements - Do not print details about removed kernel drivers and firmware files during build, this speeds up the build significantly (~1 minute faster build) and avoids huge build log. - Uncompress the kernel drivers, no need to compress them twice (they are compressed by the squashfs as well). Compressing all drivers together in the image is more effective than compressing several thousands individual files. This makes the image about 33MB smaller (on x86_64). - Hardlink the duplicate licenses, makes the ISO ~1MB smaller --------- Co-authored-by: Martin Vidner <mvidner@suse.cz>
103 lines
3.2 KiB
Ruby
Executable file
103 lines
3.2 KiB
Ruby
Executable file
#! /usr/bin/env ruby
|
|
|
|
# This script removes unused firmware files (not referenced by any kernel
|
|
# driver) from the system. By default the script runs in safe mode and only
|
|
# lists the unused firmware file, use the "--delete" argument to delete the
|
|
# found files.
|
|
|
|
require "find"
|
|
require "shellwords"
|
|
|
|
# really delete or just do a smoke test?
|
|
do_delete = ARGV[0] == "--delete"
|
|
|
|
# firmware location
|
|
fw_dir = "/lib/firmware/"
|
|
|
|
# in the Live ISO there should be just one kernel installed
|
|
dir = Dir["/lib/modules/*"].first
|
|
puts "Scanning kernel modules in #{dir}..."
|
|
|
|
# find all symlinks until the final file is found, if a file is passed then the
|
|
# file only is returned
|
|
# @return [Array<String>] list of files/symlinks
|
|
def symlinks(path, fw_dir)
|
|
ret = [path]
|
|
|
|
while File.symlink?(path)
|
|
# do not use File.realpath as it skips all intermediate symlinks and returns the final target
|
|
target = File.readlink(path)
|
|
abs_target = File.absolute_path(target, File.dirname(path))
|
|
|
|
# a cycle or a broken link is detected, or the link points outside of the firmware directory
|
|
break if ret.include?(abs_target) || !File.exist?(abs_target) || !abs_target.start_with?(fw_dir)
|
|
|
|
puts "Adding symlink #{path.delete_prefix(fw_dir)} -> #{target} (#{abs_target})"
|
|
ret << abs_target
|
|
|
|
# prepare for the next iteration round
|
|
path = abs_target
|
|
end
|
|
|
|
ret
|
|
end
|
|
|
|
# list of referenced firmware names from the kernel modules, includes symlinks and expanded globs,
|
|
# the paths are relative to the /lib/firmware root
|
|
fw = []
|
|
|
|
# traverse the kernel drivers tree and extract the needed firmware files
|
|
Find.find(dir) do |path|
|
|
if File.file?(path) && path.end_with?(".ko", ".ko.xz", ".ko.zst")
|
|
driver_fw = `/usr/sbin/modinfo -F firmware #{path.shellescape}`.split("\n")
|
|
|
|
driver_fw.each do |fw_name|
|
|
f = fw_name.dup
|
|
# the firmware can be compressed, match also the compressed variants, if
|
|
# a wildcard is at the end then it already matches so it does not need
|
|
# to be added (compressed files would be then included twice)
|
|
f += "{,.xz,.zst}" if !f.end_with?("*")
|
|
|
|
matching = Dir.glob(File.join(fw_dir, f))
|
|
|
|
if fw_name.include?("*")
|
|
puts "Pattern #{fw_name.inspect} expanded to: #{matching.join(", ")}"
|
|
end
|
|
|
|
# find symlink targets if the file is a symlink
|
|
fw_files = matching.inject([]){|acc, file| acc += symlinks(file, fw_dir)}
|
|
|
|
fw += fw_files.map{|m| m.delete_prefix(fw_dir)}
|
|
end
|
|
end
|
|
end
|
|
|
|
puts "Removing unused firmware..."
|
|
# counter for total unused firmware size
|
|
unused_size = 0
|
|
|
|
# traverse the firmware tree and delete the files which are not referenced by any kernel module
|
|
Find.find(fw_dir) do |fw_path|
|
|
next unless File.file?(fw_path)
|
|
|
|
fw_name = fw_path.delete_prefix(fw_dir)
|
|
|
|
if !fw.include?(fw_name)
|
|
unused_size += File.size(fw_path)
|
|
if (do_delete)
|
|
File.delete(fw_path)
|
|
else
|
|
puts "Found unused firmware #{fw_path}"
|
|
end
|
|
end
|
|
end
|
|
|
|
# do some cleanup at the end
|
|
if (do_delete)
|
|
puts "Removing dangling symlinks..."
|
|
system("find #{fw_dir.shellescape} -xtype l -delete")
|
|
puts "Removing empty directories..."
|
|
system("find #{fw_dir.shellescape} -type d -empty -delete")
|
|
end
|
|
|
|
puts "Unused firmware size: #{unused_size} (#{unused_size >> 20} MiB)"
|