22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/upm/pacman_verifier.rb', line 22
def verify!(*included)
$stderr.puts "Checking integrity of #{included.any? ? included.size : "installed"} packages..."
report = []
Dir.entries(PACKAGE_ROOT).each do |package_dir|
mtree_path = File.join(PACKAGE_ROOT, package_dir, "mtree")
next unless File.exists?(mtree_path)
chunks = package_dir.split("-")
version = chunks[-2..-1].join("-")
package = chunks[0...-2].join("-")
if included.any?
next if not included.include?(package)
end
puts "<8>[<7>+<8>] <10>#{package} <2>#{version}".colorize
result = []
defaults = {}
Zlib::GzipReader.open(mtree_path) do |io|
lines = io.each_line.drop(1)
lines.each do |line|
path, *expected = line.split
expected = expected.map { |opt| opt.split("=") }.to_h
if path == "/set"
defaults = expected
next
end
path = path[1..-1] if path[0] == "."
path = path.gsub(/\\(\d{3})/) { |m| $1.to_i(8).chr }
next if SKIP_FILES.include?(path)
expected = defaults.merge(expected)
lstat = File.lstat(path)
errors = expected.map do |key, val|
case key
when "type"
compare("type", lstat.ftype[0...val.size], val)
when "link"
next if val == "/dev/null"
compare("link", File.readlink(path), val)
when "gid"
compare("gid", lstat.gid, val.to_i)
when "uid"
compare("uid", lstat.uid, val.to_i)
when "mode"
compare("mode", "%o" % (lstat.mode & 0xFFF), val)
when "size"
compare("size", lstat.size, val.to_i)
when "time"
next if expected["type"] == "dir"
next if expected["link"] == "/dev/null"
compare("time", lstat.mtime.to_i, val.to_i)
when "sha256digest"
compare("sha256digest", Digest::SHA256.file(path).hexdigest, val)
when "md5digest"
next if expected["sha256digest"]
compare("md5digest", Digest::MD5.file(path).hexdigest, val)
else
raise "Unknown key: #{key}=#{val}"
end
end.compact
if errors.any?
puts " <4>[<12>*<4>] <11>#{path}".colorize
errors.each do |key, a, e|
puts " <7>expected <14>#{key} <7>to be <2>#{e} <7>but was <4>#{a}".colorize
result << [path, "expected #{key.inspect} to be #{e.inspect} but was #{a.inspect}"]
end
end
rescue Errno::EACCES
puts " <1>[<9>!<1>] <11>Can't read <7>#{path} <8>(<9>permission denied<8>)".colorize
result << [path, "permission denied"]
rescue Errno::ENOENT
puts " <4>[<12>?<4>] <12>Missing file <15>#{path}".colorize
result << [path, "missing"]
end
end
report << [package, result] if result.any?
end
puts
puts "#{report.size} packages with errors (#{report.map { |result| result.size }.sum} errors total)"
puts
if report.any?
puts "Packages with problems:"
report.each do |package, errors|
puts " #{package} (#{errors.size} errors)"
end
end
end
|