1
package Mogstored::ChildProcess::DiskUsage;
3
use base 'Mogstored::ChildProcess';
9
$SIG{TERM} = 'DEFAULT'; # override custom one from earlier
10
$ENV{MOG_DOCROOT} = Perlbal->service('mogstored')->{docroot};
14
$docroot = $ENV{MOG_DOCROOT};
15
die "\$ENV{MOG_DOCROOT} not set" unless $docroot;
16
die "\$ENV{MOG_DOCROOT} not set to a directory" unless -d $docroot;
18
# (runs in exec'd child process)
19
$0 = "mogstored [diskusage]";
20
select((select(STDOUT), $|++)[0]);
22
my $start_ppid = getppid();
24
# Discover whether or not we have GNU df.
26
`df -P / 2>/dev/null >/dev/null`;
32
look_at_disk_usage($gnu_df);
35
# shut ourselves down if our parent mogstored
38
exit(0) unless $ppid == $start_ppid && kill(0,$ppid);
42
sub look_at_disk_usage {
43
my $err = sub { warn "$_[0]\n"; };
44
my $path = $ENV{MOG_DOCROOT};
48
# find all devices below us
50
if (opendir(D, $path)) {
51
@devnum = grep { /^dev\d+$/ } readdir(D);
54
return $err->("Failed to open $path: $!");
57
foreach my $devnum (@devnum) {
58
my $rval = `df $gnu_df -l -k $path/$devnum`;
59
my $uperK = ($rval =~ /512-blocks/i) ? 2 : 1; # units per kB
60
foreach my $l (split /\r?\n/, $rval) {
61
next unless $l =~ /^(.+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)\s+(.+)$/;
62
my ($dev, $total, $used, $avail, $useper, $disk) = ($1, $2, $3, $4, $5, $6);
64
unless ($disk =~ m!$devnum/?$!) {
65
$disk = "$path/$devnum";
68
# FIXME: We're stupidly throwing away the 'avail' value here.
69
# This causes mogilefs to run aground when used with ext
70
# partitions using reserved space. Drop the reserved space from
71
# the total, and in the future add available to the device table
73
$total = $used + $avail;
75
# create string to print
79
device => $dev, # /dev/sdh1
80
total => int($total / $uperK), # integer: total KiB blocks
81
used => int($used / $uperK), # integer: used KiB blocks
82
available => int($avail / $uperK), # integer: available KiB blocks
83
'use' => $useper, # "45%"
84
disk => $disk, # mount point of disk (/var/mogdata/dev8), or path if not a mount
87
if ($ENV{MOG_DEV_USAGE_VIA_DU}) {
88
my $size = `du -k -c -s $path/$devnum`;
89
if ($size =~ /^(\d+)/) {
94
# size of old file we'll be overwriting in place (we'll want
95
# to pad with newlines/spaces, before we truncate it, for
97
my $ufile = "$disk/usage";
98
my $old_size = (-s $ufile) || 0;
99
my $mode = $old_size ? "+<" : ">";
101
# string we'll be writing
103
foreach (sort keys %$output) {
104
$new_data .= "$_: $output->{$_}\n";
107
my $new_size = length $new_data;
108
my $pad_len = $old_size > $new_size ? ($old_size - $new_size) : 0;
109
$new_data .= "\n" x $pad_len;
111
# write the file, all at once (with padding) then remove padding
112
my $rv = open(my $fh, $mode, $ufile);
114
$err->("Unable to open '$ufile' for writing: $!");
117
unless (syswrite($fh, $new_data)) {
119
$err->("Error writing to '$ufile': $!");
122
truncate($fh, $new_size) if $pad_len;