X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=blobdiff_plain;f=src%2FPVE%2FProcFSTools.pm;h=80c04257783ea5db83b0fce6385fd390095103bd;hp=9c9eb8116c66f40b6842ef87b6d0cba0461b445d;hb=e97f807c388c10250f442b1f16c5315df2ffc2af;hpb=ef67212cf2d01b230d9b070d4e382bce15530fe4 diff --git a/src/PVE/ProcFSTools.pm b/src/PVE/ProcFSTools.pm index 9c9eb81..80c0425 100644 --- a/src/PVE/ProcFSTools.pm +++ b/src/PVE/ProcFSTools.pm @@ -8,6 +8,12 @@ use IO::File; use PVE::Tools; use Cwd qw(); +use Socket qw(PF_INET PF_INET6 SOCK_DGRAM IPPROTO_IP); + +use constant IFF_UP => 1; +use constant IFNAMSIZ => 16; +use constant SIOCGIFFLAGS => 0x8913; + my $clock_ticks = POSIX::sysconf(&POSIX::_SC_CLK_TCK); my $cpuinfo; @@ -286,7 +292,36 @@ sub read_proc_net_route { } sub read_proc_mounts { - return PVE::Tools::file_get_contents("/proc/mounts"); + return PVE::Tools::file_get_contents("/proc/mounts", 128*1024); +} + +# mounts encode spaces (\040), tabs (\011), newlines (\012), backslashes (\\ or \134) +sub decode_mount { + my ($str) = @_; + return $str =~ s/\\(?:040|01[12]|134|\\)/"\"$&\""/geer; +} + +sub parse_mounts { + my ($mounts) = @_; + my $mntent = []; + while ($mounts =~ /^\s*([^#].*)$/gm) { + # lines from the file are encoded so we can just split at spaces + my ($what, $dir, $fstype, $opts) = split(/[ \t]/, $1, 4); + my ($freq, $passno) = (0, 0); + # in glibc's parser frequency and pass seem to be optional + $freq = $1 if $opts =~ s/\s+(\d+)$//; + $passno = $1 if $opts =~ s/\s+(\d+)$//; + push @$mntent, [decode_mount($what), + decode_mount($dir), + decode_mount($fstype), + decode_mount($opts), + $freq, $passno]; + } + return $mntent; +} + +sub parse_proc_mounts { + return parse_mounts(read_proc_mounts()); } sub is_mounted { @@ -294,13 +329,10 @@ sub is_mounted { $mountpoint = Cwd::realpath($mountpoint); - my $mountdata = read_proc_mounts(); + return 0 if !defined($mountpoint); # path does not exist - if ($mountdata =~ m/\s$mountpoint\s/) { - return 1; - } else { - return 0; - } + my $mounts = parse_proc_mounts(); + return (grep { $_->[1] eq $mountpoint } @$mounts) ? 1 : 0; } sub read_proc_net_ipv6_route { @@ -328,4 +360,56 @@ sub read_proc_net_ipv6_route { return $res; } +sub upid_wait { + my ($upid, $waitfunc, $sleep_intervall) = @_; + + my $task = PVE::Tools::upid_decode($upid); + + $sleep_intervall = $sleep_intervall ? $sleep_intervall : 1; + + my $next_time = time + $sleep_intervall; + + while (check_process_running($task->{pid}, $task->{pstart})) { + + if (time >= $next_time && $waitfunc && ref($waitfunc) eq 'CODE'){ + &$waitfunc($task); + $next_time = time + $sleep_intervall; + } + + CORE::sleep(1); + } +} + +# struct ifreq { // FOR SIOCGIFFLAGS: +# char ifrn_name[IFNAMSIZ] +# short ifru_flags +# }; +my $STRUCT_IFREQ_SIOCGIFFLAGS = 'Z' . IFNAMSIZ . 's1'; +sub get_active_network_interfaces { + # Use the interface name list from /proc/net/dev + open my $fh, '<', '/proc/net/dev' + or die "failed to open /proc/net/dev: $!\n"; + # And filter by IFF_UP flag fetched via a PF_INET6 socket ioctl: + my $sock; + socket($sock, PF_INET6, SOCK_DGRAM, &IPPROTO_IP) + or socket($sock, PF_INET, SOCK_DGRAM, &IPPROTO_IP) + or return []; + + my $ifaces = []; + while(defined(my $line = <$fh>)) { + next if $line !~ /^\s*([^:\s]+):/; + my $ifname = $1; + my $ifreq = pack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifname, 0); + if (!defined(ioctl($sock, SIOCGIFFLAGS, $ifreq))) { + warn "failed to get interface flags for: $ifname\n"; + next; + } + my ($name, $flags) = unpack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifreq); + push @$ifaces, $ifname if ($flags & IFF_UP); + } + close $fh; + close $sock; + return $ifaces; +} + 1;