PageRenderTime 27ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/web-app/du.php

https://bitbucket.org/lordgnu/greyhole
PHP | 326 lines | 64 code | 16 blank | 246 comment | 12 complexity | 98199ef1cb7f861aff56e03f541d6bac MD5 | raw file
  1. <?php
  2. /*
  3. Copyright 2010 Guillaume Boudreau
  4. This file is part of Greyhole.
  5. Greyhole is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. Greyhole is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Greyhole. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. $data_file = '/usr/local/greyhole/gh-disk-usage.log';
  17. if (!file_exists($data_file)) {
  18. render_header('Greyhole Disk Usage');
  19. ?>
  20. <h1>Greyhole Storage Pool Disk Usage - All Shares</h1>
  21. <div>Greyhole disk usage stats are computed during the nightly fsck run.</div>
  22. <div>Those stats have not yet been computed.</div>
  23. <div>Please wait for fsck to run once.</div>
  24. <?php
  25. render_footer();
  26. exit(0);
  27. }
  28. $base_url = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  29. require_once('includes/common.php');
  30. exec("tail -2 $data_file | grep '^# '", $results);
  31. $shares_options = unserialize(substr($results[0], 2));
  32. unset($results);
  33. if (!isset($_GET['d'])) {
  34. $root_dir = '/';
  35. $start_level = 1;
  36. } else {
  37. $root_dir = $_GET['d'];
  38. $chars_count = count_chars($root_dir, 1);
  39. $start_level = $chars_count[ord('/')] + 1;
  40. }
  41. $table_data = array();
  42. $legend = array();
  43. for ($i = 0; $i < 2; $i++) {
  44. $level = $start_level + $i;
  45. exec("grep '^$level $root_dir' $data_file", $results);
  46. $sizes = array();
  47. foreach ($results as $result) {
  48. $path = substr($result, 2, strrpos($result, ' ')-2);
  49. if ($level == $start_level) {
  50. $path .= '/';
  51. }
  52. $share = substr($path, 1, strpos(substr($path, 1), '/'));
  53. $num_copies = $shares_options[$share]['num_copies'];
  54. $sizes[$path] = (int) substr($result, strrpos($result, ' ')) * $num_copies;
  55. }
  56. unset($results);
  57. if ($level > $start_level) {
  58. foreach ($sizes as $path => $size) {
  59. if (100*$size/$total_size < 1) {
  60. $parent_path = substr($path, 0, strrpos($path, '/'));
  61. @$sizes["$parent_path/.../"] += $size;
  62. unset($sizes[$path]);
  63. }
  64. }
  65. }
  66. ksort($sizes);
  67. // Add the $sizes for files...
  68. if ($level == $start_level) {
  69. // ... for the root_dir
  70. if ($start_level > 1) {
  71. $share = substr($path, 1, strpos(substr($path, 1), '/'));
  72. $num_copies = $shares_options[$share]['num_copies'];
  73. exec("grep '^". ($start_level-1) ." $root_dir' $data_file", $results);
  74. $results = explode(' ', $results[0]);
  75. $files_size = (int) $results[count($results)-1] * $num_copies;
  76. unset($results);
  77. foreach ($sizes as $size) {
  78. $files_size -= $size;
  79. }
  80. $sizes["$root_dir/*"] = $files_size;
  81. }
  82. } else {
  83. // ... and for the 2nd level
  84. foreach ($previous_sizes as $previous_path => $previous_size) {
  85. $files_size = $previous_size;
  86. foreach ($sizes as $path => $size) {
  87. if (strpos($path, $previous_path) === 0) {
  88. $files_size -= $size;
  89. }
  90. }
  91. $sizes["$previous_path*"] = $files_size;
  92. }
  93. }
  94. ksort($sizes);
  95. $total_size = array_sum($sizes);
  96. if ($level > $start_level) {
  97. // Keep $sizes sorted to match the previous level, but sort them by size desc otherwise.
  98. $sorted_sizes = array();
  99. list($path, $size) = array_kshift($sizes);
  100. foreach ($previous_sizes as $previous_path => $previous_size) {
  101. $to_sort = array();
  102. while (strstr($path, $previous_path) == $path) {
  103. $to_sort[$path] = $size;
  104. if (count($sizes) == 0) {
  105. break;
  106. }
  107. list($path, $size) = array_kshift($sizes);
  108. }
  109. arsort($to_sort);
  110. unset($final);
  111. foreach ($to_sort as $p => $s) {
  112. if (strpos($p, '/.../') == strlen($p)-5) {
  113. $final = array($p, $s);
  114. } else {
  115. $sorted_sizes[$p] = $s;
  116. }
  117. }
  118. if (isset($final)) {
  119. list($p, $s) = $final;
  120. $sorted_sizes[$p] = $s;
  121. }
  122. }
  123. $sizes = $sorted_sizes;
  124. }
  125. $table_data[$i] = array();
  126. foreach ($sizes as $path => $size) {
  127. $table_data[$i][] = number_format(100*$size/$total_size, 10);
  128. if ($level == $start_level) {
  129. $legend[] = urlencode(get_legend($path, $size));
  130. }
  131. }
  132. $table_data[$i] = implode(',', $table_data[$i]);
  133. if ($level == $start_level) {
  134. $previous_sizes = $sizes;
  135. } else {
  136. $colors = colorize($previous_sizes, $sizes);
  137. }
  138. }
  139. // Add a legend to the legend! :D
  140. array_kunshift($previous_sizes, 'Legend', 0.0000000001);
  141. $table_data[0] = $previous_sizes['Legend'] .','. $table_data[0];
  142. array_unshift($colors[0], 'FFFFFF');
  143. array_unshift($legend, urlencode('Directory (Files size x # copies = Disk Used)'));
  144. // Add a total to the legend!
  145. $previous_sizes['Total'] = 0.0000000001;
  146. $table_data[0] = $table_data[0] .','. $previous_sizes['Total'];
  147. array_push($colors[0], 'FFFFFF');
  148. array_push($legend, urlencode(get_legend('Total Disk Used', array_sum($previous_sizes))));
  149. $img_url = "http://chart.apis.google.com/chart?cht=pc&chd=t:$table_data[0]|$table_data[1]&chs=720x388&chco=". implode('|', $colors[0]) .','. implode('|', $colors[1]) .'&chdl='. implode('|', $legend);
  150. ?>
  151. <?php render_header('Greyhole Disk Usage') ?>
  152. <h1>Greyhole Storage Pool Disk Usage
  153. <?php if ($root_dir == '/'): ?>
  154. - All Shares
  155. <?php else: ?>
  156. - <?php echo substr($root_dir, 1) ?>
  157. <?php endif; ?>
  158. </h1>
  159. <?php if ($start_level > 1): ?>
  160. [<a href="javascript:window.history.go(-1)">back</a>]<br/>
  161. <?php endif; ?>
  162. <?php echo get_map_html($img_url) ?>
  163. <img id="graph" src="<?php echo $img_url ?>" usemap="#disk_usage_map" />
  164. <?php render_footer() ?>
  165. <?php
  166. function render_header($title) {
  167. global $base_url;
  168. ?>
  169. <html>
  170. <head>
  171. <title><?php echo htmlentities($title) ?></title>
  172. <script type="text/javascript" src="<?php echo $base_url ?>javascript/prototype.js"></script>
  173. <style type="text/css">
  174. </style>
  175. </head>
  176. <body>
  177. <?php
  178. }
  179. function render_footer() {
  180. ?>
  181. </body>
  182. </html>
  183. <?php
  184. }
  185. // Colorize slices, except ... ones
  186. function colorize($previous_sizes, $sizes) {
  187. $colors = array();
  188. $colors[0] = colorize_serie($previous_sizes);
  189. $colors[1] = colorize_serie($sizes);
  190. return $colors;
  191. }
  192. function colorize_serie($sizes) {
  193. $color_min = array(hexdec('66'), hexdec('00'), hexdec('00'));
  194. $color_max = array(hexdec('FF'), hexdec('BB'), hexdec('00'));
  195. $color_range = $color_max[0]-$color_min[0] + $color_max[1]-$color_min[1] + $color_max[2]-$color_min[2];
  196. $colors = array();
  197. $num_no_colors = 0;
  198. foreach ($sizes as $path => $size) {
  199. if (strpos($path, '/.../') == strlen($path)-5) {
  200. $num_no_colors++;
  201. }
  202. }
  203. $color_step = round($color_range / (count($sizes)-1-$num_no_colors));
  204. $current_color = $color_min;
  205. foreach ($sizes as $path => $size) {
  206. if (strpos($path, '/.../') == strlen($path)-5) {
  207. $colors[] = 'CCCCCC';
  208. } else if (strpos($path, '/**') == strlen($path)-3) {
  209. $colors[] = 'FFFFFF';
  210. } else {
  211. $colors[] = dechex(256*256*$current_color[0]+256*$current_color[1]+$current_color[2]);
  212. if ($current_color[0] < $color_max[0]) {
  213. $current_color[0] += $color_step;
  214. if ($current_color[0] > 255) { $current_color[0] = 255; }
  215. } else if ($current_color[1] < $color_max[1]) {
  216. $current_color[1] += $color_step;
  217. if ($current_color[1] > 255) { $current_color[1] = 255; }
  218. } else if ($current_color[2] < $color_max[2]) {
  219. $current_color[2] += $color_step;
  220. if ($current_color[2] > 255) { $current_color[2] = 255; }
  221. }
  222. }
  223. }
  224. return $colors;
  225. }
  226. function get_map_html($img_url) {
  227. global $previous_sizes, $sizes;
  228. require_once('PEAR.php');
  229. pear::loadExtension('json');
  230. $json = exec('curl "'. $img_url .'&chof=json"');
  231. $map = json_decode($json)->chartshape;
  232. $map_html = "<map name=\"disk_usage_map\">\n";
  233. foreach ($map as $area) {
  234. if (count($previous_sizes) > 0) {
  235. list($path, $size) = array_kshift($previous_sizes);
  236. } else {
  237. list($path, $size) = array_kshift($sizes);
  238. }
  239. $href_dir = $path;
  240. if (strrpos($path, '/.../') == strlen($path)-5) {
  241. $href_dir = substr($path, 0, strlen($path)-5);
  242. } else if (strrpos($path, '/*') == strlen($path)-2) {
  243. $href_dir = substr($path, 0, strlen($path)-2);
  244. } else if (strrpos($path, '/') == strlen($path)-1) {
  245. $href_dir = substr($path, 0, strlen($path)-1);
  246. }
  247. if (strrpos($path, '/**') != strlen($path)-3 && $href_dir != 'Legend') {
  248. $map_html .= " <area name=\"$area->name\" shape=\"$area->type\" coords=\"". implode(',', $area->coords) ."\" href=\"du.php?d=". urlencode($href_dir) ."\" title=\"". htmlentities(get_legend($path, $size, TRUE), ENT_COMPAT, 'UTF-8') ."\">\n";
  249. }
  250. }
  251. $map_html .= "</map>\n";
  252. return $map_html;
  253. }
  254. function get_legend($path, $size, $simplified=FALSE) {
  255. global $shares_options;
  256. $share = substr($path, 1, strpos(substr($path, 1), '/'));
  257. $num_copies = $shares_options[$share]['num_copies'];
  258. if (!$simplified) {
  259. if (strpos($path, '/*') == strlen($path)-2) {
  260. $path .= " (files)";
  261. }
  262. }
  263. if ($simplified || $num_copies == null) {
  264. return "$path (". bytes_to_human($size, FALSE) .")";
  265. } else {
  266. return "$path (". bytes_to_human($size/$num_copies, FALSE) ." x $num_copies = ". bytes_to_human($size, FALSE) .")";
  267. }
  268. }
  269. function array_kshift(&$arr) {
  270. list($k) = array_keys($arr);
  271. $r = $arr[$k];
  272. unset($arr[$k]);
  273. return array($k, $r);
  274. }
  275. function array_kunshift(&$arr, $key, $value) {
  276. $arr = array_reverse($arr);
  277. $arr[$key] = $value;
  278. $arr = array_reverse($arr);
  279. }