<?php

/**
 * Create a pie chart of harddisk space.
 *
 * @param size integer
 *	Height of the returned image
 * @param mount string
 *	If present just shows the selected mount point,
 *	otherwise shows all partitions.
 * @param nolegend bool
 *	Suppresses the legend if true.
 *	The legend is automatically suppressed if the image
 *	is smaller than 200px.
 */

// calculate degrees from bytes
function calcdegrees($values) {
  $sum = 0.0;
  foreach ($values as $value)
    $sum += $value;
  if ($sum)
    foreach ($values as $value)
      $degrees[] = 360 * $value / $sum;
  else
    $degrees = array();
  return $degrees;
}

// revert "human-readable" size from df output to MBytes
$units = array(
  'K' => 1. / 1024,
  'M' => 1,
  'G' => 1024,
  'T' => 1024 * 1024
);

function unit($s) {
  global $units;
  return floatval(substr($s, 0, -1)) * $units[substr($s, -1)];
}

// get disk capacity, collapse more than one space
$df = explode("\n", `df -PH | sed -ne "/^\/dev/s/  */ /gp"`);

foreach ($df as $part) {
  $words = explode(' ', $part);
  // $words = array(device, size, used, avail, used%, mountpoint)
  // partition selection
  if (isset($_GET['mount']) && $_GET['mount'] != $words[5])
    continue;
  if (sizeof($words) == 6) {
    $values[] = unit($words[2]);
    $labels[] = sprintf('%-12s  %4s or %4s used', $words[5], $words[2], $words[4]);
    $values[] = unit($words[3]);
    $labels[] = sprintf('%-12s  %4s of %4s free', '', $words[3], $words[1]);
  }
}

$values = calcdegrees($values);

// determine image size and legend position
$size = isset($_GET['size']) ? intval($_GET['size']) : 0;
if ($size <= 0)
  $size = 400;
$radius = $size - 2;
$legend_size = ($size <= 200 || isset($_GET['nolegend'])) ? 0 : 240;	// no legend on small images
$legend_dy = 16;
$legend_x = $size + 16;
$legend_y = $size / 20;

// create the image
$im = imagecreatetruecolor($size + $legend_size, $size);

// fill with a transparent background
$bg = imagecolorallocate($im, 1, 1, 1);
imagecolortransparent($im, $bg);
imagefill($im, 0, 0, $bg);

$black = imagecolorallocate($im, 0, 0, 0);

$offset = 270;
foreach ($values as $i => $value) {

  // get color
  if ($i & 1) {			// free part
    $r += 0x18;			// lighter color than the used part
    $g += 0x18;
    $b += 0x18;
  }
  else {			// used part
    $r = rand(128, 224);
    $g = rand(128, 224);
    $b = rand(128, 224);
  }
  $color = imagecolorallocate($im, $r, $g, $b);
  // display circle segment
  if ($value >= 0.5)
    imagefilledarc(
      $im,
      $size / 2, $size / 2,
      $radius, $radius,
      $offset, $offset + $value,
      $color, IMG_ARC_PIE
    );
  if ($legend_size) {
    // display legend
    imagefilledrectangle($im,
      $legend_x, $legend_y,
      $legend_x + 8, $legend_y + 8,
      $color
    );
    imagestring($im, 2, $legend_x + 16, $legend_y - 3, $labels[$i], $black);
    $legend_y += $legend_dy;
  }
  $offset += $value;
  imagecolordeallocate($im, $color);
}
imagecolordeallocate($im, $black);

// return the image
header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
?>