use Data::Dumper;
use Cwd qw(abs_path);
use Fcntl ':mode';
+use File::Basename;
use File::stat;
use JSON;
sub check_bin {
my ($path) = @_;
-
return -x $path;
}
return $type eq 'ssd' || $type eq 'nvme';
}
-sub get_disks {
- my ($disks, $nosmart, $include_partitions) = @_;
- my $disklist = {};
-
+sub mounted_blockdevs {
my $mounted = {};
my $mounts = PVE::ProcFSTools::parse_proc_mounts();
$mounted->{abs_path($mount->[0])} = $mount->[1];
};
+ return $mounted;
+}
+
+sub get_disks {
+ my ($disks, $nosmart, $include_partitions) = @_;
+ my $disklist = {};
+
+ my $mounted = mounted_blockdevs();
+
my $lsblk_info = get_lsblk_info();
my $journalhash = get_ceph_journals($lsblk_info);
next if $partitions->{$part}->{used} eq 'partition';
$used //= $partitions->{$part}->{used};
}
+ } else {
+ # fstype might be set even if there are partitions, but showing that is confusing
+ $used = 'partitions' if scalar(keys %{$partitions});
}
$used //= 'partitions' if scalar(keys %{$partitions});
# multipath, software raid, etc.
my $st = stat($part_path);
- next if !$st->mode || !S_ISBLK($st->mode) || !$st->rdev;
+ die "error detecting block device '$part_path'\n"
+ if !$st || !$st->mode || !S_ISBLK($st->mode) || !$st->rdev;
+
my $major = PVE::Tools::dev_t_major($st->rdev);
my $minor = PVE::Tools::dev_t_minor($st->rdev);
my $partnum_path = "/sys/dev/block/$major:$minor/";
return $partition;
}
+my sub strip_dev :prototype($) {
+ my ($devpath) = @_;
+ $devpath =~ s|^/dev/||;
+ return $devpath;
+}
+
+# Check if a disk or any of its partitions has a holder.
+# Can also be called with a partition.
+# Expected to be called with a result of verify_blockdev_path().
+sub has_holder {
+ my ($devpath) = @_;
+
+ my $dev = strip_dev($devpath);
+
+ return $devpath if !dir_is_empty("/sys/class/block/${dev}/holders");
+
+ my $found;
+ dir_glob_foreach("/sys/block/${dev}", "${dev}.+", sub {
+ my ($part) = @_;
+ $found = "/dev/${part}" if !dir_is_empty("/sys/class/block/${part}/holders");
+ });
+
+ return $found;
+}
+
+# Basic check if a disk or any of its partitions is mounted.
+# Can also be called with a partition.
+# Expected to be called with a result of verify_blockdev_path().
+sub is_mounted {
+ my ($devpath) = @_;
+
+ my $mounted = mounted_blockdevs();
+
+ return $devpath if $mounted->{$devpath};
+
+ my $dev = strip_dev($devpath);
+
+ my $found;
+ dir_glob_foreach("/sys/block/${dev}", "${dev}.+", sub {
+ my ($part) = @_;
+ my $partpath = "/dev/${part}";
+
+ $found = $partpath if $mounted->{$partpath};
+ });
+
+ return $found;
+}
+
+# Wipes all labels and the first 200 MiB of a disk/partition (or the whole if it is smaller).
+# Expected to be called with a result of verify_blockdev_path().
+sub wipe_blockdev {
+ my ($devpath) = @_;
+
+ my $devname = basename($devpath);
+ my $dev_size = PVE::Tools::file_get_contents("/sys/class/block/$devname/size");
+
+ ($dev_size) = $dev_size =~ m|(\d+)|; # untaint $dev_size
+ die "Couldn't get the size of the device $devname\n" if !defined($dev_size);
+
+ my $size = ($dev_size * 512 / 1024 / 1024);
+ my $count = ($size < 200) ? $size : 200;
+
+ print "wiping disk/partition: ${devpath}\n";
+
+ run_command(['wipefs', '--all', $devpath], errmsg => "error wiping '${devpath}'");
+
+ run_command(
+ ['dd', 'if=/dev/zero', "of=${devpath}", 'bs=1M', 'conv=fdatasync', "count=${count}"],
+ errmsg => "error wiping '${devpath}'",
+ );
+}
+
1;