Skip to content

Commit b04c4d1

Browse files
authored
Merge pull request #74 from rancher-sandbox/lima-and-qemu
Extract minimal set of lima and qemu files to install on a clean machine
2 parents bd037c4 + 40ce17b commit b04c4d1

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

hack/lima-and-qemu.pl

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env perl
2+
use strict;
3+
use warnings;
4+
5+
use FindBin qw();
6+
7+
# By default capture both legacy firmware (alpine) and UFI (default) usage
8+
@ARGV = qw(alpine default) unless @ARGV;
9+
10+
# This script creates a tarball containing lima and qemu, plus all their
11+
# dependencies from /usr/local/**.
12+
#
13+
# New processes (with their command line arguments) have been captured by
14+
# `sudo dtrace -s /usr/bin/newproc.d` (on a system with SIP disabled, using lima 0.3.0):
15+
# `limactl start examples/alpine.yaml; limactl stop alpine; limactrl delete alpine`.
16+
#
17+
# 5680 <777> limactl start --tty=false examples/alpine.yaml
18+
# 5681 <5680> curl -fSL -o /Users/jan/Library/Caches/lima/download/by-url-sha256/21753<...>
19+
# 5683 <5680> qemu-img create -f qcow2 /Users/jan/.lima/alpine/diffdisk 107374182400
20+
# 5684 <5680> /usr/local/bin/limactl hostagent --pidfile /Users/jan/.lima/alpine/ha.pid alpine
21+
# 5686 <5684> ssh-keygen -R [127.0.0.1]:60020 -R [localhost]:60020
22+
# 5687 <5684> ssh -o ControlMaster=auto -o ControlPath=/Users/jan/.lima/alpine/ssh.sock -o <...>
23+
# 5685 <5684> /usr/local/bin/qemu-system-x86_64 -cpu Haswell-v4 -machine q35,accel=hvf -smp <...>
24+
# 5689 <5684> ssh -o ControlMaster=auto -o ControlPath=/Users/jan/.lima/alpine/ssh.sock -o <...>
25+
# ... many more ssh sub-processes like the one above ...
26+
# 5800 <777> limactl stop alpine
27+
# 5801 <5684> ssh -o ControlMaster=auto -o ControlPath=/Users/jan/.lima/alpine/ssh.sock -o <...>
28+
# 5896 <777> limactl delete alpine
29+
#
30+
# It shows the following binaries from /usr/local are called:
31+
32+
my $install_dir = "/usr/local";
33+
record("$install_dir/bin/limactl");
34+
record("$install_dir/bin/qemu-img");
35+
record("$install_dir/bin/qemu-system-x86_64");
36+
37+
# Capture any library and datafiles access with opensnoop
38+
my $opensnoop = "/tmp/opensnoop.log";
39+
END { system("sudo pkill dtrace") }
40+
print "sudo may prompt for password to run opensnoop\n";
41+
system("sudo -b opensnoop >$opensnoop 2>/dev/null");
42+
sleep(1) until -s $opensnoop;
43+
44+
my $repo_root = dirname($FindBin::Bin);
45+
for my $example (@ARGV) {
46+
my $config = "$repo_root/examples/$example.yaml", ;
47+
die "Config $config not found" unless -f $config;
48+
system("limactl delete -f $example") if -f "$ENV{HOME}/.lima/$example";
49+
system("limactl start --tty=false $config");
50+
system("limactl shell $example uname");
51+
system("limactl stop $example");
52+
system("limactl delete $example");
53+
}
54+
system("sudo pkill dtrace");
55+
56+
open(my $fh, "<", $opensnoop) or die "Can't read $opensnoop: $!";
57+
while (<$fh>) {
58+
# Only record files opened by limactl or qemu-*
59+
next unless /^\s*\d+\s+\d+\s+(limactl|qemu-)/;
60+
# Ignore files not under /usr/local
61+
next unless s|^.*($install_dir/\S+).*$|$1|s;
62+
# Skip files that don't exist
63+
next unless -f;
64+
record($_);
65+
}
66+
67+
my %deps;
68+
print "$_ $deps{$_}\n" for sort keys %deps;
69+
print "\n";
70+
71+
my $dist = "lima-and-qemu";
72+
system("rm -rf /tmp/$dist");
73+
74+
# Copy all files to /tmp tree and make all dylib references relative to the
75+
# /usr/local/bin directory using @executable_path/..
76+
my %resign;
77+
for my $file (keys %deps) {
78+
my $copy = $file =~ s|^$install_dir|/tmp/$dist|r;
79+
system("mkdir -p " . dirname($copy));
80+
system("cp -R $file $copy");
81+
next if -l $file;
82+
next unless qx(file $copy) =~ /Mach-O/;
83+
84+
open(my $fh, "otool -L $file |") or die "Failed to run 'otool -L $file': $!";
85+
while (<$fh>) {
86+
my($dylib) = m|$install_dir/(\S+)| or next;
87+
my $grep = "";
88+
if ($file =~ m|bin/qemu-system-x86_64$|) {
89+
# qemu-system-* is already signed with an entitlement to use the hypervisor framework
90+
$grep = "| grep -v 'will invalidate the code signature'";
91+
$resign{$copy}++;
92+
}
93+
system "install_name_tool -change $install_dir/$dylib \@executable_path/../$dylib $copy 2>&1 $grep";
94+
}
95+
close($fh);
96+
}
97+
# Replace invalidated signatures
98+
for my $file (keys %resign) {
99+
system("codesign --sign - --force --preserve-metadata=entitlements $file");
100+
}
101+
102+
unlink("$repo_root/$dist.tar.gz");
103+
my $files = join(" ", map s|^$install_dir/||r, keys %deps);
104+
system("tar cvfz $repo_root/$dist.tar.gz -C /tmp/$dist $files");
105+
exit;
106+
107+
# File references may involve multiple symlinks that need to be recorded as well, e.g.
108+
#
109+
# /usr/local/opt/libssh/lib/libssh.4.dylib
110+
#
111+
# turns into 2 symlinks and one file:
112+
#
113+
# /usr/local/opt/libssh → ../Cellar/libssh/0.9.5_1
114+
# /usr/local/Cellar/libssh/0.9.5_1/lib/libssh.4.dylib → libssh.4.8.6.dylib
115+
# /usr/local/Cellar/libssh/0.9.5_1/lib/libssh.4.8.6.dylib [394K]
116+
117+
my %seen;
118+
sub record {
119+
my $dep = shift;
120+
return if $seen{$dep}++;
121+
$dep =~ s|^/|| or die "$dep is not an absolute path";
122+
my $filename = "";
123+
my @segments = split '/', $dep;
124+
while (@segments) {
125+
my $segment = shift @segments;
126+
my $name = "$filename/$segment";
127+
my $link = readlink $name;
128+
if (defined $link) {
129+
# Record the symlink itself with the link target as the comment
130+
$deps{$name} = "$link";
131+
if ($link =~ m|^/|) {
132+
# Can't support absolute links pointing outside /usr/local
133+
die "$name$link" unless $link =~ m|^$install_dir/|;
134+
$link = join("/", $link, @segments);
135+
} else {
136+
$link = join("/", $filename, $link, @segments);
137+
}
138+
# Re-parse from the start because the link may contain ".." segments
139+
return record($link)
140+
}
141+
if ($segment eq "..") {
142+
$filename = dirname($filename);
143+
} else {
144+
$filename = $name;
145+
}
146+
}
147+
# Use human readable size of the file as the comment:
148+
# $ ls -lh /usr/local/Cellar/libssh/0.9.5_1/lib/libssh.4.8.6.dylib
149+
# -rw-r--r-- 1 jan staff 394K 5 Jan 11:04 /usr/local/Cellar/libssh/0.9.5_1/lib/libssh.4.8.6.dylib
150+
$deps{$filename} = sprintf "[%s]", (split / +/, qx(ls -lh $filename))[4];
151+
}
152+
153+
sub dirname {
154+
shift =~ s|/[^/]+$||r;
155+
}

0 commit comments

Comments
 (0)