]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC/Setup/Base.pm
use /etc/os-release
[pve-container.git] / src / PVE / LXC / Setup / Base.pm
index e65b04afca17201558c386d668c84d712818bc26..0228fe7655b1d59721503431c1d31a2fafe5a038 100644 (file)
@@ -10,15 +10,16 @@ use Encode;
 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 {
@@ -158,7 +159,7 @@ sub setup_init {
 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";
@@ -197,14 +198,22 @@ sub setup_systemd_console {
     }
 }
 
+# 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);
     }
 }
@@ -260,7 +269,8 @@ DATA
        }
        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";
            }
        }
@@ -276,6 +286,16 @@ sub setup_securetty {
     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) {
@@ -446,10 +466,20 @@ sub post_create_hook {
 # 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);
@@ -468,12 +498,14 @@ sub ct_mkdir {
 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);
 }
 
@@ -486,6 +518,7 @@ sub ct_open_file_read {
 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;
@@ -507,6 +540,7 @@ sub ct_make_path {
 
 sub ct_symlink {
     my ($self, $old, $new) = @_;
+    return if $self->ct_is_file_ignored($new);
     return CORE::symlink($old, $new);
 }
 
@@ -530,6 +564,11 @@ sub ct_is_symlink {
     return -l $file;
 }
 
+sub ct_is_executable {
+    my ($self, $file) = @_;
+    return -x $file
+}
+
 sub ct_stat {
     my ($self, $file) = @_;
     return File::stat::stat($file);
@@ -547,6 +586,7 @@ sub ct_file_get_contents {
 
 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);
 }
@@ -555,6 +595,7 @@ sub ct_file_set_contents {
 # 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";