use File::Copy;
use IO::File;
use IO::Select;
+use IPC::Open2;
use IPC::Open3;
use UUID;
use Cwd;
my $long = $2;
$long =~ s/^\s+/ /;
$res->{description} = $long;
- chomp $res->{description};
+ chomp $res->{description};
} elsif ($rec =~ s/^([^:]+):\s*(.*\S)\s*\n//) {
my ($key, $value) = (lc ($1), $2);
if ($key eq 'source' || $key eq 'mirror') {
die "unable to parse config file" if $rec;
+ $res->{architecture} = 'amd64' if $res->{architecture} eq 'x86_64';
+
return $res;
}
die "no 'maintainer' specified\n" if !$config->{maintainer};
my $name = $config->{name} || die "no 'name' specified\n";
- $name =~ m/^[a-z][0-9a-z\-\*\.]+$/ ||
+ $name =~ m/^[a-z][0-9a-z\-\*\.]+$/ ||
die "illegal characters in name '$name'\n";
my $targetname;
return <<"CFG";
lxc.arch = $arch
lxc.include = /usr/share/lxc/config/archlinux.common.conf
-lxc.utsname = localhost
-lxc.rootfs = $self->{rootfs}
+lxc.uts.name = localhost
+lxc.rootfs.path = $self->{rootfs}
lxc.mount.entry = $self->{pkgcache} $self->{pkgdir} none bind 0 0
CFG
}
$fh = IO::File->new($self->{'pacman.conf'}, O_WRONLY|O_CREAT|O_EXCL) ||
die "unable to write pacman config file $self->{'pacman.conf'} - $!";
+ my $arch = $config->{architecture};
+ $arch = 'x86_64' if $arch eq 'amd64';
print $fh <<"EOF";
[options]
HoldPkg = pacman glibc
-Architecture = $config->{architecture}
+Architecture = $arch
CheckSpace
SigLevel = Never
$servers
[community]
$servers
-[multilib]
-$servers
EOF
+ if ($config->{architecture} eq 'x86_64') {
+ print $fh "[multilib]\n$servers\n";
+ }
+
mkdir $self->{rootfs} || die "unable to create rootfs - $!";
$self->logmsg("configured VE $self->{veid}\n");
}
}
close($fh);
-
+
return $res;
}
my $veid = $self->{veid};
+ my $conffile = $self->{veconffile};
$self->logmsg ("initialize VE $veid\n");
my $vestat = $self->ve_status();
if ($vestat->{running}) {
- $self->run_command ("lxc-stop -n $veid --kill");
- }
+ $self->run_command ("lxc-stop -n $veid --rcfile $conffile --kill");
+ }
rmtree $self->{rootfs};
mkpath $self->{rootfs};
my ($self, $cmd, $input) = @_;
my $veid = $self->{veid};
+ my $conffile = $self->{veconffile};
if (ref ($cmd) eq 'ARRAY') {
- unshift @$cmd, 'lxc-attach', '-n', $veid, '--clear-env', '--';
+ unshift @$cmd, 'lxc-attach', '-n', $veid, '--rcfile', $conffile,'--clear-env', '--';
$self->run_command ($cmd, $input);
} else {
- $self->run_command ("lxc-attach -n $veid --clear-env -- $cmd", $input);
+ $self->run_command ("lxc-attach -n $veid --rcfile $conffile --clear-env -- $cmd", $input);
}
}
my ($self, @cmd) = @_;
my $veid = $self->{veid};
+ my $conffile = $self->{veconffile};
my $reader;
- my $pid = open2($reader, "<&STDIN", 'lxc-attach', '-n', $veid, '--', @cmd)
+ my $pid = open2($reader, "<&STDIN", 'lxc-attach', '-n', $veid, '--rcfile', $conffile, '--', @cmd)
or die "unable to exec command";
while (defined (my $line = <$reader>)) {
# catch exec errors
if ($orig_pid != $$) {
$self->logmsg ("ERROR: command '$cmdstr' failed - fork failed\n");
- POSIX::_exit (1);
- kill ('KILL', $$);
+ POSIX::_exit (1);
+ kill ('KILL', $$);
}
die $err if $err;
sub stop_container {
my ($self) = @_;
my $veid = $self->{veid};
- $self->run_command ("lxc-stop -n $veid --kill");
+ my $conffile = $self->{veconffile};
+ $self->run_command ("lxc-stop -n $veid --rcfile $conffile --kill");
}
sub pacman_command {
my $root = $self->{rootfs};
return ('/usr/bin/pacman',
'--root', $root,
+ '--config', $self->{'pacman.conf'},
'--cachedir', $self->{pkgcache},
'--noconfirm');
}
mkpath $self->{pkgcache};
mkpath $self->{pkgdir};
mkpath "$root/var/lib/pacman";
- $self->run_command([@pacman, '-Sy']);
+ $self->run_command([@pacman, '-Syy']);
print "Figuring out what to install...\n";
my $incl = { map { $_ => 1 } @{$self->{incl}} };
}
print "Populating keyring...\n";
- $self->run_command(['mount', '-t', 'devtmpfs', '-o', 'mode=0755,nosuid', 'udev', "$root/dev"]);
- $self->run_command(['unshare', '--fork', '--pid', 'chroot', "$root", 'pacman-key', '--init']);
- $self->run_command(['unshare', '--fork', '--pid', 'chroot', "$root", 'pacman-key', '--populate']);
- $self->run_command(['umount', "$root/dev"]);
+ $self->populate_keyring();
print "Starting container...\n";
$self->start_container();
$self->ve_command(['pacman', '-S', '--needed', '--noconfirm', '--', @$packages]);
}
+sub populate_keyring {
+ my ($self) = @_;
+ my $root = $self->{rootfs};
+
+ # devices needed for gnupg to function:
+ my $devs = {
+ '/dev/null' => ['c', '1', '3'],
+ '/dev/random' => ['c', '1', '9'], # fake /dev/random (really urandom)
+ '/dev/urandom' => ['c', '1', '9'],
+ '/dev/tty' => ['c', '5', '0'],
+ };
+
+ my $cleanup_dev = sub {
+ # remove temporary device files
+ unlink "${root}$_" foreach keys %$devs;
+ };
+ local $SIG{INT} = $SIG{TERM} = $cleanup_dev;
+
+ # at least /dev/null exists as regular file after installing the filesystem package,
+ # and we want to replace /dev/random, so delete devices first
+ &$cleanup_dev();
+
+ foreach my $dev (keys %$devs) {
+ my ($type, $major, $minor) = @{$devs->{$dev}};
+ system('mknod', "${root}${dev}", $type, $major, $minor);
+ }
+
+ # generate weak master key and populate the keyring
+ system('unshare', '--fork', '--pid', 'chroot', "$root", 'pacman-key', '--init') == 0
+ or die "failed to initialize keyring: $?";
+ system('unshare', '--fork', '--pid', 'chroot', "$root", 'pacman-key', '--populate') == 0
+ or die "failed to populate keyring: $?";
+
+ &$cleanup_dev();
+ # reset to original state
+ system('touch', "$root/dev/null");
+}
+
sub install {
my ($self, $pkglist) = @_;
$data .= "Section: $config->{section}\n";
$data .= "Maintainer: $config->{maintainer}\n";
$data .= "Architecture: $config->{architecture}\n";
+ $data .= "Infopage: https://www.archlinux.org\n";
$data .= "Installed-Size: $size\n";
# optional
unlink $file;
rename_file($file.'.aab_orig', $file);
+ print "Removing weak temporary pacman keyring...\n";
+ rmtree("$rootdir/etc/pacman.d/gnupg");
+
my $sizestr = $self->run_command("du -sm $rootdir", undef, 1);
my $size;
if ($sizestr =~ m/^(\d+)\s+\Q$rootdir\E$/) {
sub enter {
my ($self) = @_;
my $veid = $self->{veid};
+ my $conffile = $self->{veconffile};
my $vestat = $self->ve_status();
if (!$vestat->{exist}) {
$self->start_container();
}
- system ("lxc-attach -n $veid --clear-env");
+ system ("lxc-attach -n $veid --rcfile $conffile --clear-env");
}
sub clean {