]> git.proxmox.com Git - pve-container.git/blob - src/lxc-pve-prestart-hook
ee4f7e2e5a717ec1e1a1df4c2d539045ac7c89b1
[pve-container.git] / src / lxc-pve-prestart-hook
1 #!/usr/bin/perl
2
3 package lxc_pve_prestart_hook;
4
5 use strict;
6 use warnings;
7
8 use Fcntl qw(O_DIRECTORY :mode);
9 use File::Path;
10 use POSIX;
11
12 use PVE::Cluster;
13 use PVE::LXC::Config;
14 use PVE::LXC::Setup;
15 use PVE::LXC::Tools;
16 use PVE::LXC;
17 use PVE::Storage;
18 use PVE::Syscall qw(:fsmount);
19 use PVE::Tools qw(AT_FDCWD O_PATH);
20
21 PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub {
22 my ($vmid, $vars, undef, undef) = @_;
23
24 my $skiplock_flag_fn = "/run/lxc/skiplock-$vmid";
25 my $skiplock = 1 if -e $skiplock_flag_fn;
26 unlink $skiplock_flag_fn if $skiplock;
27
28 PVE::Cluster::check_cfs_quorum(); # only start if we have quorum
29
30 return undef if ! -f PVE::LXC::Config->config_file($vmid);
31
32 my $conf = PVE::LXC::Config->load_config($vmid);
33 my $storage_cfg = PVE::Storage::config();
34
35 # apply pending changes if present
36 if ($conf->{pending}) {
37 PVE::LXC::Config->vmconfig_apply_pending($vmid, $conf, $storage_cfg);
38 $conf = PVE::LXC::Config->load_config($vmid); # just to be sure
39 }
40
41 if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) {
42 PVE::LXC::Config->check_lock($conf);
43 }
44
45
46 my $vollist = PVE::LXC::Config->get_vm_volumes($conf);
47 my $loopdevlist = PVE::LXC::Config->get_vm_volumes($conf, 'rootfs');
48
49 PVE::Storage::activate_volumes($storage_cfg, $vollist);
50
51 my $rootdir = $vars->{ROOTFS_PATH};
52
53 # Delete any leftover reboot-trigger file
54 unlink("/var/lib/lxc/$vmid/reboot");
55
56 my $devlist_file = "/var/lib/lxc/$vmid/devices";
57 unlink $devlist_file;
58 my $devices = [];
59
60 my (undef, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf);
61
62 # Unmount first when the user mounted the container with "pct mount".
63 eval {
64 PVE::Tools::run_command(['umount', '--recursive', $rootdir], outfunc => sub {}, errfunc => sub {});
65 };
66
67 my $setup_mountpoint;
68 if (!PVE::LXC::Tools::can_use_new_mount_api()) {
69 # Legacy mode for old kernels:
70 $setup_mountpoint = sub {
71 my ($opt, $mountpoint) = @_;
72
73 my (undef, undef, $dev) = PVE::LXC::mountpoint_mount(
74 $mountpoint,
75 $rootdir,
76 $storage_cfg,
77 undef,
78 $rootuid,
79 $rootgid,
80 );
81 push @$devices, $dev if $dev && $mountpoint->{quota};
82 };
83 } else {
84 # With newer kernels we stage mount points and then use move_mount().
85 my $rootdir_fd = undef;
86 $setup_mountpoint = sub {
87 my ($opt, $mountpoint) = @_;
88
89 my $dir = PVE::LXC::get_staging_mount_path($opt);
90 my (undef, undef, $dev, $mount_fd) = PVE::LXC::mountpoint_stage(
91 $mountpoint,
92 $dir,
93 $storage_cfg,
94 undef,
95 $rootuid,
96 $rootgid,
97 );
98
99 my $ddir;
100 if ($rootdir_fd) {
101 # Mount relative to the rootdir fd.
102 $ddir = './' . $mountpoint->{mp};
103 } else {
104 # Assert that 'rootfs' is the first one:
105 die "foreach_mount() error\n" if $opt ne 'rootfs';
106
107 # Mount the rootfs absolutely (rootdir_fd=undef uses AT_FDCWD).
108 # $rootdir is not controlled by the container, so this is fine.
109 $ddir = $rootdir;
110 }
111
112 PVE::LXC::mountpoint_insert_staged(
113 $mount_fd,
114 $rootdir_fd,
115 $ddir,
116 $opt,
117 $rootuid,
118 $rootgid,
119 );
120
121 # From now on we mount inside our rootfs:
122 if (!$rootdir_fd) {
123 $rootdir_fd = $mount_fd;
124 }
125
126 push @$devices, $dev if $dev && $mountpoint->{quota};
127 };
128 }
129
130 PVE::LXC::Config->foreach_mountpoint($conf, $setup_mountpoint);
131
132 my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir);
133 $lxc_setup->pre_start_hook();
134
135 if (@$devices) {
136 my $devlist = '';
137 foreach my $dev (@$devices) {
138 my ($mode, $rdev) = (stat($dev))[2,6];
139 next if !$mode || !S_ISBLK($mode) || !$rdev;
140 my $major = PVE::Tools::dev_t_major($rdev);
141 my $minor = PVE::Tools::dev_t_minor($rdev);
142 $devlist .= "b:$major:$minor:$dev\n";
143 }
144 PVE::Tools::file_set_contents($devlist_file, $devlist);
145 }
146 });