]>
git.proxmox.com Git - pve-container.git/blob - src/PVE/LXC/Tools.pm
1 # Module for lxc related functionality used mostly by our hooks.
3 package PVE
::LXC
::Tools
;
9 # LXC introduced an `lxc.hook.version` property which allows hooks to be executed in different
10 # manners. The old way passes a lot of stuff as command line parameter, the new way passes
11 # environment variables.
13 # This is supposed to be a common entry point for hooks, consuming the parameters passed by lxc and
14 # passing them on to a subroutine in a defined way.
16 my ($expected_type, $expected_section, $code) = @_;
18 my ($ct_name, $section, $type);
22 my $version = $ENV{LXC_HOOK_VERSION
} // '0';
23 if ($version eq '0') {
25 $ct_name = shift @ARGV;
26 $section = shift @ARGV;
29 if (!defined($ct_name) || !defined($section) || !defined($type)) {
30 die "missing hook parameters, expected to be called by lxc as hook\n";
33 if ($ct_name !~ /^\d+$/ || $section ne $expected_section || $type ne $expected_type) {
37 if ($type eq 'stop') {
38 foreach my $ns (@ARGV) {
39 if ($ns =~ /^([^:]+):(.+)$/) {
40 $namespaces->{$1} = $2;
42 die "unrecognized 'stop' hook parameter: $ns\n";
45 } elsif ($type eq 'clone') {
48 } elsif ($version eq '1') {
49 $ct_name = $ENV{LXC_NAME
}
50 or die "missing LXC_NAME environment variable\n";
51 $section = $ENV{LXC_HOOK_SECTION
}
52 or die "missing LXC_HOOK_SECTION environment variable\n";
53 $type = $ENV{LXC_HOOK_TYPE
}
54 or die "missing LXC_HOOK_TYPE environment variable\n";
56 if ($ct_name !~ /^\d+$/ || $section ne $expected_section || $type ne $expected_type) {
60 foreach my $var (keys %$ENV) {
61 if ($var =~ /^LXC_([A-Z]+)_NS$/) {
62 $namespaces->{lc($1)} = $ENV{$1};
66 die "lxc.hook.version $version not supported!\n";
69 my $logid = $ENV{PVE_LOG_ID
} || "pve-lxc-hook-$section-$type";
73 ROOTFS_MOUNT
=> ($ENV{LXC_ROOTFS_MOUNT
} or die "missing LXC_ROOTFS_MOUNT env var\n"),
74 ROOTFS_PATH
=> ($ENV{LXC_ROOTFS_PATH
} or die "missing LXC_ROOTFS_PATH env var\n"),
75 CONFIG_FILE
=> ($ENV{LXC_CONFIG_FILE
} or die "missing LXC_CONFIG_FILE env var\n"),
77 if (defined(my $target = $ENV{LXC_TARGET
})) {
78 $common_vars->{TARGET
} = $target;
81 $code->($ct_name, $common_vars, $namespaces, $args);
84 sub for_current_devices
($&) {
85 my ($vmid, $code) = @_;
87 my $devlist_file = "/var/lib/lxc/$vmid/devices";
90 if (! open $fd, '<', $devlist_file) {
91 exit 0 if $!{ENOENT
}; # If the list is empty the file might not exist.
92 die "failed to open device list: $!\n";
95 while (defined(my $line = <$fd>)) {
96 if ($line !~ m
@^(b
):(\d
+):(\d
+):/dev/(\S
+)\s
*$@) {
97 warn "invalid .pve-devices entry: $line\n";
101 my ($type, $major, $minor, $dev) = ($1, $2, $3, $4);
103 # Don't break out of $root/dev/
104 if ($dev =~ /\.\./) {
105 warn "skipping illegal device node entry: $dev\n";
109 # Never expose /dev/loop-control
110 if ($major == 10 && $minor == 237) {
111 warn "skipping illegal device entry (loop-control) for: $dev\n";
115 $code->($type, $major, $minor, $dev);
120 sub cgroup_do_write
($$) {
121 my ($path, $value) = @_;
123 if (!open($fd, '>', $path)) {
124 warn "failed to open cgroup file $path: $!\n";
127 if (!defined syswrite($fd, $value)) {
128 warn "failed to write value $value to cgroup file $path: $!\n";
135 # Check whether the kernel supports the new mount api. This is used in the pre-start hook and in
136 # the hotplugging code.
137 my $cached_can_use_new_mount_api = undef;
138 sub can_use_new_mount_api
() {
139 if (!defined($cached_can_use_new_mount_api)) {
140 if (PVE
::Tools
::move_mount
(-1, 0, -1, 0, 0)) {
141 # This should not be possible...
142 die "kernel behaved unexpectedly: move_mount(-1, NULL, -1, NULL) did not fail!\n";
144 # On older kernels the syscall doesn't exist and we get ENOSYS. (For newer kernels this call
145 # will fail with EFAULT instead, since we pass in a NULL pointer as file system name.)
146 $cached_can_use_new_mount_api = ($! != ENOSYS
);
148 return $cached_can_use_new_mount_api;