use Fcntl;
use File::Path;
use File::Spec;
+use File::Basename;
use PVE::INotify;
use PVE::Tools;
use PVE::Network;
sub new {
- my ($class, $conf, $rootdir) = @_;
+ my ($class, $conf, $rootdir, $os_release) = @_;
- return bless { conf => $conf, rootdir => $rootdir }, $class;
+ return bless { conf => $conf, rootdir => $rootdir, os_release => $os_release }, $class;
}
sub lookup_dns_conf {
sub setup_systemd_console {
my ($self, $conf) = @_;
- my $systemd_dir_rel = -x "/lib/systemd/systemd" ?
+ my $systemd_dir_rel = $self->ct_is_executable("/lib/systemd/systemd") ?
"/lib/systemd/system" : "/usr/lib/systemd/system";
my $systemd_getty_service_rel = "$systemd_dir_rel/getty\@.service";
}
}
+# A few distros as well as unprivileged containers cannot deal with the
+# /dev/lxc/ tty subdirectory.
+sub devttydir {
+ my ($self, $conf) = @_;
+ return $conf->{unprivileged} ? '' : 'lxc/';
+}
+
sub setup_container_getty_service {
- my ($self, $nosubdir) = @_;
- my $systemd_dir_rel = -x "/lib/systemd/systemd" ?
+ my ($self, $conf) = @_;
+
+ my $systemd_dir_rel = $self->ct_is_executable("/lib/systemd/systemd") ?
"/lib/systemd/system" : "/usr/lib/systemd/system";
my $servicefile = "$systemd_dir_rel/container-getty\@.service";
my $raw = $self->ct_file_get_contents($servicefile);
- my $ttyname = ($nosubdir ? '' : 'lxc/') . 'tty%I';
- if ($raw =~ s@pts/%I@$ttyname@g) {
+ my $ttyname = $self->devttydir($conf) . 'tty%I';
+ if ($raw =~ s@pts/%I|lxc/tty%I@$ttyname@g) {
$self->ct_file_set_contents($servicefile, $raw);
}
}
}
if (defined(my $gw = $d->{gw6})) {
$data .= "Gateway = $gw\n";
- if ($has_ipv6 && !PVE::Network::is_ip_in_cidr($gw, $d->{ip6}, 6)) {
+ if ($has_ipv6 && !PVE::Network::is_ip_in_cidr($gw, $d->{ip6}, 6) &&
+ !PVE::Network::is_ip_in_cidr($gw, 'fe80::/10', 6)) {
$routes .= "\n[Route]\nDestination = $gw/128\nScope = link\n";
}
}
my ($self, $conf, @add) = @_;
my $filename = "/etc/securetty";
+ # root login is already allowed on every device if no securetty present
+ return if !$self->ct_file_exists($filename);
+
+ if (!scalar(@add)) {
+ @add = qw(console tty1 tty2 tty3 tty4);
+ if (my $dir = $self->devttydir($conf)) {
+ @add = map { "${dir}$_" } @add;
+ }
+ }
+
my $data = $self->ct_file_get_contents($filename);
chomp $data; $data .= "\n";
foreach my $dev (@add) {
# File access wrappers for container setup code.
# For user-namespace support these might need to take uid and gid maps into account.
+sub ct_is_file_ignored {
+ my ($self, $file) = @_;
+ my ($name, $path) = fileparse($file);
+ return -f "$path/.pve-ignore.$name";
+}
+
sub ct_reset_ownership {
my ($self, @files) = @_;
my $conf = $self->{conf};
return if !$self->{id_map};
+
+ @files = grep { !$self->ct_is_file_ignored($_) } @files;
+ return if !@files;
+
my $uid = $self->{rootuid};
my $gid = $self->{rootgid};
chown($uid, $gid, @files);
sub ct_unlink {
my ($self, @files) = @_;
foreach my $file (@files) {
+ next if $self->ct_is_file_ignored($file);
CORE::unlink($file);
}
}
sub ct_rename {
my ($self, $old, $new) = @_;
+ return if $self->ct_is_file_ignored($new);
CORE::rename($old, $new);
}
sub ct_open_file_write {
my $self = shift;
my $file = shift;
+ $file = '/dev/null' if $self->ct_is_file_ignored($file);
my $fh = IO::File->new($file, O_WRONLY | O_CREAT, @_);
$self->ct_reset_ownership($fh);
return $fh;
sub ct_symlink {
my ($self, $old, $new) = @_;
+ return if $self->ct_is_file_ignored($new);
return CORE::symlink($old, $new);
}
return -l $file;
}
+sub ct_is_executable {
+ my ($self, $file) = @_;
+ return -x $file
+}
+
sub ct_stat {
my ($self, $file) = @_;
return File::stat::stat($file);
sub ct_file_set_contents {
my ($self, $file, $data, $perms) = @_;
+ return if $self->ct_is_file_ignored($file);
PVE::Tools::file_set_contents($file, $data, $perms);
$self->ct_reset_ownership($file);
}
# Optionally if the file becomes empty it will be deleted.
sub ct_modify_file {
my ($self, $file, $data, %options) = @_;
+ return if $self->ct_is_file_ignored($file);
my $head = "# --- BEGIN PVE ---\n";
my $tail = "# --- END PVE ---\n";