package PVE::ProcFSTools;
use strict;
+use warnings;
use POSIX;
use Time::HiRes qw (gettimeofday);
use IO::File;
my $cpuinfo;
-# cycles_per_jiffy = frequency_of_your_cpu/jiffies_per_second
-# jiffies_per_second = 1000
-
-# frequency_of_your_cpu can be read from /proc/cpuinfo, as:
-# cpu MHz : <frequency_of_your_cpu>
-
sub read_cpuinfo {
my $fn = '/proc/cpuinfo';
return $cpuinfo if $cpuinfo;
my $res = {
+ user_hz => $clock_ticks,
model => 'unknown',
mhz => 0,
cpus => 1,
- cpu_cycles_per_jiffy => 0,
+ sockets => 1,
};
my $fh = IO::File->new ($fn, "r");
return $res if !$fh;
+ my $idhash = {};
my $count = 0;
while (defined(my $line = <$fh>)) {
if ($line =~ m/^processor\s*:\s*\d+\s*$/i) {
$res->{model} = $1 if $res->{model} eq 'unknown';
} elsif ($line =~ m/^cpu\s+MHz\s*:\s*(\d+\.\d+)\s*$/i) {
$res->{mhz} = $1 if !$res->{mhz};
- $res->{cpu_cycles_per_jiffy} += $1 * 1000;
} elsif ($line =~ m/^flags\s*:.*(vmx|svm)/) {
$res->{hvm} = 1; # Hardware Virtual Machine (Intel VT / AMD-V)
+ } elsif ($line =~ m/^physical id\s*:\s*(\d+)\s*$/i) {
+ $idhash->{$1} = 1;
}
}
+ $res->{sockets} = scalar(keys %$idhash) || 1;
+
$res->{cpus} = $count;
$fh->close;
my $line = PVE::Tools::file_read_firstline("/proc/uptime");
if ($line && $line =~ m|^(\d+\.\d+)\s+(\d+\.\d+)\s*$|) {
if ($ticks) {
- return (int($1*100), int($2*100));
+ return (int($1*$clock_ticks), int($2*$clock_ticks));
} else {
return (int($1), int($2));
}
return $res;
}
-sub read_proc_starttime {
+sub read_proc_pid_stat {
my $pid = shift;
my $statstr = PVE::Tools::file_read_firstline("/proc/$pid/stat");
- if ($statstr && $statstr =~ m/^$pid \(.*\) \S (-?\d+) -?\d+ -?\d+ -?\d+ -?\d+ \d+ \d+ \d+ \d+ \d+ (\d+) (\d+) (-?\d+) (-?\d+) -?\d+ -?\d+ -?\d+ 0 (\d+) (\d+) (-?\d+) \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ -?\d+ -?\d+ \d+ \d+ \d+/) {
- my $starttime = $6;
-
- return $starttime;
+ if ($statstr && $statstr =~ m/^$pid \(.*\) (\S) (-?\d+) -?\d+ -?\d+ -?\d+ -?\d+ \d+ \d+ \d+ \d+ \d+ (\d+) (\d+) (-?\d+) (-?\d+) -?\d+ -?\d+ -?\d+ 0 (\d+) (\d+) (-?\d+) \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ -?\d+ -?\d+ \d+ \d+ \d+/) {
+ return {
+ status => $1,
+ utime => $3,
+ stime => $4,
+ starttime => $7,
+ vsize => $8,
+ rss => $9 * 4096,
+ };
}
- return 0;
+ return undef;
+}
+
+sub check_process_running {
+ my ($pid, $pstart) = @_;
+
+ # note: waitpid only work for child processes, but not
+ # for processes spanned by other processes.
+ # kill(0, pid) return succes for zombies.
+ # So we read the status form /proc/$pid/stat instead
+
+ my $info = read_proc_pid_stat($pid);
+
+ return $info && (!$pstart || ($info->{starttime} eq $pstart)) && ($info->{status} ne 'Z') ? $info : undef;
+}
+
+sub read_proc_starttime {
+ my $pid = shift;
+
+ my $info = read_proc_pid_stat($pid);
+ return $info ? $info->{starttime} : 0;
}
sub read_meminfo {
memtotal => 0,
memfree => 0,
memused => 0,
+ memshared => 0,
swaptotal => 0,
swapfree => 0,
swapused => 0,
$res->{swapfree} = $d->{swapfree};
$res->{swapused} = $res->{swaptotal} - $res->{swapfree};
+ my $spages = PVE::Tools::file_read_firstline("/sys/kernel/mm/ksm/pages_sharing");
+ $res->{memshared} = int($spages) * 4096;
+
return $res;
}
my $line = PVE::Tools::file_read_firstline("/proc/$$/statm");
- if ($line =~ m/^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) {
+ if ($line =~ m/^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*/) {
$res->{size} = $1*$ps;
$res->{resident} = $2*$ps;
$res->{shared} = $3*$ps;
return $res;
}
+sub write_proc_entry {
+ my ($filename, $data) = @_;#
+
+ my $fh = IO::File->new($filename, O_WRONLY);
+ die "unable to open file '$filename' - $!\n" if !$fh;
+ die "unable to write '$filename' - $!\n" unless print $fh $data;
+ die "closing file '$filename' failed - $!\n" unless close $fh;
+ $fh->close();
+}
+
+sub read_proc_net_route {
+ my $filename = "/proc/net/route";
+
+ my $res = [];
+
+ my $fh = IO::File->new ($filename, "r");
+ return $res if !$fh;
+
+ my $int_to_quad = sub {
+ return join '.' => map { ($_[0] >> 8*(3-$_)) % 256 } (3, 2, 1, 0);
+ };
+
+ while (defined(my $line = <$fh>)) {
+ next if $line =~/^Iface\s+Destination/; # skip head
+ my ($iface, $dest, $gateway, $metric, $mask, $mtu) = (split(/\s+/, $line))[0,1,2,6,7,8];
+ push @$res, {
+ dest => &$int_to_quad(hex($dest)),
+ gateway => &$int_to_quad(hex($gateway)),
+ mask => &$int_to_quad(hex($mask)),
+ metric => $metric,
+ mtu => $mtu,
+ iface => $iface,
+ };
+ }
+
+ return $res;
+}
+
1;