X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=data%2FPVE%2FTools.pm;h=b222debf24ebdd2ee81808e0ecf5ed43a15e7edb;hb=b192b930181e922dc7f51e3c937dede2ec41f4c0;hp=735cbdeda65eaac934437315d7ac6553c8b32354;hpb=602ec0cd717a41b34711aa6776bca058a08da35e;p=pve-common.git diff --git a/data/PVE/Tools.pm b/data/PVE/Tools.pm index 735cbde..b222deb 100644 --- a/data/PVE/Tools.pm +++ b/data/PVE/Tools.pm @@ -17,6 +17,10 @@ use Encode; use Digest::SHA; use Text::ParseWords; use String::ShellQuote; +use Time::HiRes qw(usleep gettimeofday tv_interval); + +# avoid warning when parsing long hex values with hex() +no warnings 'portable'; # Support for 64-bit ints required our @EXPORT_OK = qw( $IPV6RE @@ -141,8 +145,7 @@ sub lock_file_full { $err = $@; } - if ($lock_handles->{$$}->{$filename}) { - my $fh = $lock_handles->{$$}->{$filename}; + if (my $fh = $lock_handles->{$$}->{$filename}) { $lock_handles->{$$}->{$filename} = undef; close ($fh); } @@ -627,13 +630,16 @@ sub extract_param { return $res; } -# Note: we use this to wait until vncterm is ready +# Note: we use this to wait until vncterm/spiceterm is ready sub wait_for_vnc_port { my ($port, $timeout) = @_; $timeout = 5 if !$timeout; + my $sleeptime = 0; + my $starttime = [gettimeofday]; + my $elapsed; - for (my $i = 0; $i < $timeout; $i++) { + while (($elapsed = tv_interval($starttime)) < $timeout) { if (my $fh = IO::File->new ("/proc/net/tcp", "r")) { while (defined (my $line = <$fh>)) { if ($line =~ m/^\s*\d+:\s+([0-9A-Fa-f]{8}):([0-9A-Fa-f]{4})\s/) { @@ -645,7 +651,8 @@ sub wait_for_vnc_port { } close($fh); } - sleep(1); + $sleeptime += 100000 if $sleeptime < 1000000; + usleep($sleeptime); } return undef; @@ -724,6 +731,10 @@ sub next_vnc_port { return next_unused_port(5900, 6000); } +sub next_spice_port { + return next_unused_port(61000, 61099); +} + # NOTE: NFS syscall can't be interrupted, so alarm does # not work to provide timeouts. # from 'man nfs': "Only SIGKILL can interrupt a pending NFS operation" @@ -765,6 +776,8 @@ sub df { sub upid_encode { my $d = shift; + # Note: pstart can be > 32bit if uptime > 497 days, so this can result in + # more that 8 characters for pstart return sprintf("UPID:%s:%08X:%08X:%08X:%s:%s:%s:", $d->{node}, $d->{pid}, $d->{pstart}, $d->{starttime}, $d->{type}, $d->{id}, $d->{user}); @@ -777,7 +790,8 @@ sub upid_decode { my $filename; # "UPID:$node:$pid:$pstart:$startime:$dtype:$id:$user" - if ($upid =~ m/^UPID:([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/) { + # Note: allow up to 9 characters for pstart (work until 20 years uptime) + if ($upid =~ m/^UPID:([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/) { $res->{node} = $1; $res->{pid} = hex($3); $res->{pstart} = hex($4); @@ -870,7 +884,9 @@ sub decode_utf8_parameters { sub random_ether_addr { - my $rand = Digest::SHA::sha1_hex(rand(), time()); + my ($seconds, $microseconds) = gettimeofday; + + my $rand = Digest::SHA::sha1_hex($$, rand(), $seconds, $microseconds); my $mac = ''; for (my $i = 0; $i < 6; $i++) { @@ -918,7 +934,7 @@ sub split_args { } sub dump_logfile { - my ($filename, $start, $limit) = @_; + my ($filename, $start, $limit, $filter) = @_; my $lines = []; my $count = 0; @@ -934,12 +950,25 @@ sub dump_logfile { $limit = 50 if !$limit; my $line; - while (defined($line = <$fh>)) { - next if $count++ < $start; - next if $limit <= 0; - chomp $line; - push @$lines, { n => $count, t => $line}; - $limit--; + + if ($filter) { + # duplicate code, so that we do not slow down normal path + while (defined($line = <$fh>)) { + next if $line !~ m/$filter/; + next if $count++ < $start; + next if $limit <= 0; + chomp $line; + push @$lines, { n => $count, t => $line}; + $limit--; + } + } else { + while (defined($line = <$fh>)) { + next if $count++ < $start; + next if $limit <= 0; + chomp $line; + push @$lines, { n => $count, t => $line}; + $limit--; + } } close($fh); @@ -984,4 +1013,34 @@ sub dir_glob_foreach { } } +sub assert_if_modified { + my ($digest1, $digest2) = @_; + + if ($digest1 && $digest2 && ($digest1 ne $digest2)) { + die "detected modified configuration - file changed by other user? Try again.\n"; + } +} + +# Digest for short strings +# like FNV32a, but we only return 31 bits (positive numbers) +sub fnv31a { + my ($string) = @_; + + my $hval = 0x811c9dc5; + + foreach my $c (unpack('C*', $string)) { + $hval ^= $c; + $hval += ( + (($hval << 1) ) + + (($hval << 4) ) + + (($hval << 7) ) + + (($hval << 8) ) + + (($hval << 24) ) ); + $hval = $hval & 0xffffffff; + } + return $hval & 0x7fffffff; +} + +sub fnv31a_hex { return sprintf("%X", fnv31a(@_)); } + 1;