]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/Tools.pm
fix #2618: increase maximum port for spice to 61999
[pve-common.git] / src / PVE / Tools.pm
index cd236b5d6249f7aabd988bbddfb6ac9d8cc66c0e..f02c0ae3a5acce5bec19cbb1e6906309410f65e5 100644 (file)
@@ -47,8 +47,17 @@ safe_print
 trim
 extract_param
 file_copy
+get_host_arch
 O_PATH
 O_TMPFILE
+AT_EMPTY_PATH
+AT_FDCWD
+CLONE_NEWNS
+CLONE_NEWUTS
+CLONE_NEWIPC
+CLONE_NEWUSER
+CLONE_NEWPID
+CLONE_NEWNET
 );
 
 my $pvelogdir = "/var/log/pve";
@@ -85,6 +94,9 @@ use constant {CLONE_NEWNS   => 0x00020000,
 use constant {O_PATH    => 0x00200000,
               O_TMPFILE => 0x00410000}; # This includes O_DIRECTORY
 
+use constant {AT_EMPTY_PATH => 0x1000,
+              AT_FDCWD => -100};
+
 sub run_with_timeout {
     my ($timeout, $code, @param) = @_;
 
@@ -896,9 +908,13 @@ sub next_vnc_port {
     return next_unused_port(5900, 6000, $family, $address);
 }
 
+sub spice_port_range {
+    return (61000, 61999);
+}
+
 sub next_spice_port {
     my ($family, $address) = @_;
-    return next_unused_port(61000, 61099, $family, $address);
+    return next_unused_port(spice_port_range(), $family, $address);
 }
 
 sub must_stringify {
@@ -995,8 +1011,8 @@ sub df {
     my $res = eval { run_fork_with_timeout($timeout, $df) } // {};
     warn $@ if $@;
 
-    # untaint the values
-    my ($blocks, $used, $bavail) = map { defined($_) ? (/^(\d+)$/) : 0 }
+    # untaint, but be flexible: PB usage can result in scientific notation
+    my ($blocks, $used, $bavail) = map { defined($_) ? (/^([\d\.e\-+]+)$/) : 0 }
        $res->@{qw(blocks used bavail)};
 
     return {
@@ -1384,6 +1400,11 @@ sub parse_host_and_port {
     return; # nothing
 }
 
+sub setresuid($$$) {
+    my ($ruid, $euid, $suid) = @_;
+    return 0 == syscall(PVE::Syscall::setresuid, $ruid, $euid, $suid);
+}
+
 sub unshare($) {
     my ($flags) = @_;
     return 0 == syscall(PVE::Syscall::unshare, $flags);
@@ -1551,6 +1572,11 @@ sub mkdirat($$$) {
     return syscall(PVE::Syscall::mkdirat, $dirfd, $name, $mode) == 0;
 }
 
+sub fchownat($$$$$) {
+    my ($dirfd, $pathname, $owner, $group, $flags) = @_;
+    return syscall(PVE::Syscall::fchownat, $dirfd, $pathname, $owner, $group, $flags) == 0;
+}
+
 my $salt_starter = time();
 
 sub encrypt_pw {
@@ -1618,18 +1644,126 @@ sub readline_nointr {
     return $line;
 }
 
+my $host_arch;
 sub get_host_arch {
+    $host_arch = (POSIX::uname())[4] if !$host_arch;
+    return $host_arch;
+}
 
-    my @uname = POSIX::uname();
-    my $machine = $uname[4];
+# Devices are: [ (12 bits minor) (12 bits major) (8 bits minor) ]
+sub dev_t_major($) {
+    my ($dev_t) = @_;
+    return (int($dev_t) & 0xfff00) >> 8;
+}
 
-    if ($machine eq 'x86_64') {
-       return 'amd64';
-    } elsif ($machine eq 'aarch64') {
-       return 'arm64';
-    } else {
-       die "unsupported host architecture '$machine'\n";
+sub dev_t_minor($) {
+    my ($dev_t) = @_;
+    $dev_t = int($dev_t);
+    return (($dev_t >> 12) & 0xfff00) | ($dev_t & 0xff);
+}
+
+# Given an array of array refs [ \[a b c], \[a b b], \[e b a] ]
+# Returns the intersection of elements as a single array [a b]
+sub array_intersect {
+    my ($arrays) = @_;
+
+    if (!ref($arrays->[0])) {
+       $arrays = [ grep { ref($_) eq 'ARRAY' } @_ ];
+    }
+
+    return [] if scalar(@$arrays) == 0;
+    return $arrays->[0] if scalar(@$arrays) == 1;
+
+    my $array_unique = sub {
+       my %seen = ();
+       return grep { ! $seen{ $_ }++ } @_;
+    };
+
+    # base idea is to get all unique members from the first array, then
+    # check the common elements with the next (uniquely made) one, only keep
+    # those. Repeat for every array and at the end we only have those left
+    # which exist in all arrays
+    my $return_arr = [ $array_unique->(@{$arrays->[0]}) ];
+    for my $i (1 .. $#$arrays) {
+       my %count = ();
+       # $return_arr is already unique, explicit at before the loop, implicit below.
+       foreach my $element (@$return_arr, $array_unique->(@{$arrays->[$i]})) {
+           $count{$element}++;
+       }
+       $return_arr = [];
+       foreach my $element (keys %count) {
+           push @$return_arr, $element if $count{$element} > 1;
+       }
+       last if scalar(@$return_arr) == 0; # empty intersection, early exit
     }
+
+    return $return_arr;
+}
+
+sub open_tree($$$) {
+    my ($dfd, $pathname, $flags) = @_;
+    return PVE::Syscall::file_handle_result(syscall(
+       &PVE::Syscall::open_tree,
+       $dfd,
+       $pathname,
+       $flags,
+    ));
+}
+
+sub move_mount($$$$$) {
+    my ($from_dirfd, $from_pathname, $to_dirfd, $to_pathname, $flags) = @_;
+    return 0 == syscall(
+       &PVE::Syscall::move_mount,
+       $from_dirfd,
+       $from_pathname,
+       $to_dirfd,
+       $to_pathname,
+       $flags,
+    );
+}
+
+sub fsopen($$) {
+    my ($fsname, $flags) = @_;
+    return PVE::Syscall::file_handle_result(syscall(&PVE::Syscall::fsopen, $fsname, $flags));
+}
+
+sub fsmount($$$) {
+    my ($fd, $flags, $mount_attrs) = @_;
+    return PVE::Syscall::file_handle_result(syscall(
+       &PVE::Syscall::fsmount,
+       $fd,
+       $flags,
+       $mount_attrs,
+    ));
+}
+
+sub fspick($$$) {
+    my ($dirfd, $pathname, $flags) = @_;
+    return PVE::Syscall::file_handle_result(syscall(
+       &PVE::Syscall::fspick,
+       $dirfd,
+       $pathname,
+       $flags,
+    ));
+}
+
+sub fsconfig($$$$$) {
+    my ($fd, $command, $key, $value, $aux) = @_;
+    return 0 == syscall(&PVE::Syscall::fsconfig, $fd, $command, $key, $value, $aux);
+}
+
+# "raw" mount, old api, not for generic use (as it does not invoke any helpers).
+# use for lower level stuff such as bind/remount/... or simple tmpfs mounts
+sub mount($$$$$) {
+    my ($source, $target, $filesystemtype, $mountflags, $data) = @_;
+    return 0 == syscall(
+       &PVE::Syscall::mount,
+       $source,
+       $target,
+       $filesystemtype,
+       $mountflags,
+       $data,
+    );
 }
 
 1;