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

/www/_lib/compare_classes.php

http://s-audit.googlecode.com/
PHP | 1113 lines | 620 code | 313 blank | 180 comment | 62 complexity | 5c7eb70a138d81ada9eb7c64639c41a6 MD5 | raw file
  1. <?php
  2. //============================================================================
  3. //
  4. // compare_classes.php
  5. // -------------------
  6. //
  7. // Classes for server comparision
  8. //
  9. // Part of s-audit. (c) 2011 SearchNet Ltd
  10. // see http://snltd.co.uk/s-audit for licensing and documentation
  11. //
  12. //============================================================================
  13. //============================================================================
  14. // SERVER LIST PAGE
  15. class compareListPage extends audPage {
  16. // This is the default landing page for the compare servers page. (As
  17. // opposed to comparePage, which is used for the comparisons proper.)
  18. protected $no_class_link = true;
  19. // There's no "this class" documentation link
  20. protected $group;
  21. // The audit group we're looking at
  22. protected $ff;
  23. // Path to friends file
  24. protected $map;
  25. // as usual
  26. // We need the "compare" stylesheet
  27. protected $styles = array("basic.css", "audit.css", "compare.css");
  28. public function __construct($title, $map)
  29. {
  30. if (!isset($_GET["g"]))
  31. die("no group");
  32. $this->group = $_GET["g"];
  33. $this->map = $map;
  34. $this->ff = AUDIT_DIR . "/$this->group/friends.txt";
  35. // Expand the map. We need all the local zone names, so create the
  36. // servers[] array in the map, just like GetServers normally does
  37. foreach($map->map as $global=>$file) {
  38. $this->map->servers[$global] =
  39. array_slice(array_unique(preg_grep("/^hostname=/",
  40. file($file))), 1);
  41. }
  42. parent::__construct($title, false);
  43. }
  44. public function ff_list()
  45. {
  46. // Say whether or not we're using a friends file. If we are, display
  47. // the list
  48. $ff_link = "<a href=\"" . DOC_URL .
  49. "/04_extras/friends.php\">friends file</a>";
  50. $ret = "\n\n<p class=\"center\">";
  51. if (file_exists($this->ff)) {
  52. $friends = file($this->ff);
  53. // Read in the friends file and make a key=>value array of the
  54. // pairs inside it
  55. foreach($friends as $row) {
  56. if (preg_match("/^\w/", $row)) {
  57. $a = preg_split("/\s+/", $row);
  58. if (count($a) == 3) $pairs[$a[0]] = $a[1];
  59. }
  60. }
  61. $ret .= "The following server comparisons are defined in the
  62. $ff_link at <tt>$this->ff</tt>.</p>";
  63. $ret .= "\n\n<ul>";
  64. foreach($pairs as $key=>$val) {
  65. // Only display pairs which both exist in the map
  66. if ($this->map->has_data($key) &&
  67. $this->map->has_data($val))
  68. $ret .= "\n <li><a href=\"$_SERVER[PHP_SELF]?g="
  69. . $this->group . "&amp;z1=$key&amp;z2=$val\">"
  70. ."$key and $val</a></li>";
  71. }
  72. $ret .= "\n</ul>";
  73. }
  74. else
  75. $ret .= "You do not have a $ff_link for this audit group.</p>";
  76. return $ret . new compareCyc($this->map->list_all(), $this->group);
  77. }
  78. }
  79. //----------------------------------------------------------------------------
  80. class compareCyc {
  81. // The dual cycle gadget on the server comparison page
  82. private $html;
  83. // The HTML generated by the constructor
  84. public function __construct($z_list, $group, $z1 = false, $z2 = false)
  85. {
  86. // This is the bar at the bottom of the screen that lets you choose
  87. // the servers to compare from cycle gadgets.
  88. $h = new html;
  89. $this->html = "<p class=\"center\">Select a pair of servers or zones
  90. to compare with the following gadgets.</p>"
  91. . "\n<div id=\"cycle_row\">"
  92. . $h->dialog_form($_SERVER["PHP_SELF"])
  93. . $h->dialog_submit("c", "compare")
  94. . $h->dialog_cycle("z1", $z_list, $z1, false) . " with "
  95. . $h->dialog_cycle("z2", $z_list, $z2, false)
  96. . $h->dialog_hidden("g", $group)
  97. . "</form>\n</div>";
  98. }
  99. public function __toString()
  100. {
  101. return $this->html;
  102. }
  103. }
  104. //============================================================================
  105. // COMPARISON PAGE
  106. class comparePage extends audPage {
  107. // The basic HTML template for the page used for the actual comparison.
  108. protected $no_class_link = true;
  109. // There's no "this class" documentation link
  110. protected $styles = array("basic.css", "audit.css", "compare.css");
  111. }
  112. //----------------------------------------------------------------------------
  113. class compareView {
  114. // This class groups together functions needed to compare two servers,
  115. // and display the results of that comparison. It works like the
  116. // serverView class does for single server pages.
  117. // We have to extend the HostGrid because we use its methods to display
  118. // data
  119. private $a;
  120. private $b;
  121. // The two servers on which we're doing an a/b comparison
  122. private $classes;
  123. // Audit classes we're going to compare
  124. public function __construct($data, $map)
  125. {
  126. // Call this constructor to create the whole compare grid.
  127. $this->map = $map;
  128. // Populate the $fields array with the hostnames of the servers to
  129. // compare and get a list of classes. Servers should always have the
  130. // same classes, but make sure we get everything anyway.
  131. $classes = array();
  132. // create $this->data, which puts the class data for each machine in
  133. // the same level of the data structure
  134. //
  135. // [class] -> [server_a]
  136. // [server_b]
  137. foreach($data as $host=>$h_data) {
  138. $this->fields[] = $host;
  139. foreach($h_data as $class=>$c_data) {
  140. $this->data[$class][$host] = $c_data;
  141. if (!in_array($class, $classes))
  142. $classes[] = $class;
  143. }
  144. }
  145. $this->classes = $classes;
  146. }
  147. public function show_grid()
  148. {
  149. // The grid in this case is a list of tables, one for each audit
  150. // type. Each table is created by its own class
  151. $ret = false;
  152. foreach($this->classes as $type) {
  153. $class = (class_exists("compare$type"))
  154. ? "compare$type"
  155. : "compareGeneric";
  156. // Call the class with its name, the data for servers, and the
  157. // map
  158. $ret .= new $class($type, $this->data[$type], $this->map);
  159. }
  160. return $ret;
  161. }
  162. }
  163. //----------------------------------------------------------------------------
  164. // Generic compare. Every audit class has its own compareClass which is an
  165. // extension of this
  166. class compareGeneric {
  167. // Some fields need pre-processing. This could be because they, like
  168. // NICs, come machine-parseable so aren't easy to read, or it could be
  169. // because, like network port information, we discard some data. For
  170. // that reason we can create preproc_field() methods. If they exist,
  171. // they're called.
  172. private $hosts;
  173. protected $cols;
  174. // columns, excluding the key - size of the hosts array
  175. private $html;
  176. protected $no_colour = array();
  177. // Don't colour these even if they're different. Used for things
  178. // like IP addresses, or for numbers of packages, where one number
  179. // isn't necessarily "better" than the other.
  180. protected $no_compare = array();
  181. // Don't compare fields in this array. You won't see them on the
  182. // grid at all
  183. protected $sparse_list = array();
  184. // Fields which are displayed with "holes" in them
  185. private $width = "width:80em";
  186. // The width of the compare grid (all columns combined)
  187. private $colwidth;
  188. // the % width of each column in the comparison table
  189. public function __construct($type, $data, $map)
  190. {
  191. // Start off by printing the header
  192. if (!isset($this->disp_name))
  193. $this->disp_name = $type;
  194. $this->html = "\n\n<table align=\"center\" style=\"$this->width\">"
  195. . "\n<tr><td class=\"nocol\"><h1>" . ucfirst($this->disp_name)
  196. . " audit comparison</h1></td>"
  197. . "</tr>\n</table>\n";
  198. // If all we have is hostname and audit completed, we're done
  199. $i = 0;
  200. foreach($data as $svr => $dat) {
  201. $i += count($dat);
  202. }
  203. if ($i == 4) {
  204. $this->html .= "<p class=\"center\">No data to compare.</p>";
  205. return;
  206. }
  207. $this->map = $map;
  208. // Get the hostnames and all the rows we're going to compare
  209. $this->hosts = array_keys($data);
  210. $this->cols = count($this->hosts);
  211. // This is slow and messy, but I can't think of a better way to do
  212. // it right now
  213. $rows = array();
  214. foreach($this->hosts as $host) {
  215. foreach($data[$host] as $key=>$value) {
  216. if (!in_array($key, $rows)) $rows[] = $key;
  217. }
  218. }
  219. // We may need to move "audit completed" to the last row
  220. if (end($rows) != "audit completed") {
  221. $k = array_search("audit completed", $rows);
  222. unset($rows[$k]);
  223. $rows[] = "audit completed";
  224. }
  225. $this->data = $data;
  226. $this->rows = $rows;
  227. $this->colwidth = round(100 / $this->cols) . "%";
  228. $this->html .= $this->compare_class();
  229. if (method_exists($this, "cmp_key")) {
  230. $this->html .= "\n\n<table align=\"center\" style=\""
  231. . $this->width . "\">\n<tr><td class=\"nocol\"><p class=\"center\">"
  232. . $this->cmp_key() . "</p></td></tr></table>";
  233. }
  234. }
  235. protected function compare_class()
  236. {
  237. // Print the comparison tables for the class
  238. $ret = "\n\n<table cellspacing=\"1\" class=\"audit\" align=\"center\""
  239. . " style=\"$this->width\">\n";
  240. // Step through each row
  241. foreach($this->rows as $row) {
  242. // Some fields have can special functions which we use to
  243. // compare them. The rest use the compare_generic() method.
  244. // Work out what that method should be called, see if it exists,
  245. // and call
  246. $method_base = preg_replace("/\s/", "_", $row);
  247. $pre_method = "preproc_$method_base";
  248. $cmp_method = "compare_$method_base";
  249. $post_method = "postproc_$method_base";
  250. // Application and tool have a preproc_generic
  251. if (!method_exists($this, $pre_method) && method_exists($this,
  252. "preproc_generic"))
  253. $pre_method = "preproc_generic";
  254. $cmp_data =$this->get_cmp_data($row);
  255. if (method_exists($this, $pre_method)) {
  256. // We have at least two servers to compare, so there are at
  257. // least two arrays of data to process. Put a loop here to
  258. // do them all, rather than having to loop in every single
  259. // preproc_() method
  260. $proc_arr = array();
  261. foreach($cmp_data as $svr) {
  262. $proc_arr[] = $this->$pre_method($svr);
  263. }
  264. $cmp_data = $proc_arr;
  265. }
  266. // the $no_compare[] array may tell us we don't wish to compare
  267. // this row.
  268. if (in_array($row, $this->no_compare)) {
  269. $rowdat = "don't compare";
  270. continue;
  271. }
  272. elseif(method_exists($this, $cmp_method)) {
  273. $rowdat = $this->$cmp_method($cmp_data);
  274. }
  275. else {
  276. $rowdat = (in_array($row, $this->sparse_list))
  277. ? $this->compare_sparse($cmp_data, $row)
  278. : $this->compare_generic($cmp_data, $row);
  279. }
  280. // Do we need to post-process the compared data?
  281. if (method_exists($this, $post_method))
  282. $rowdat = $this->$post_method($rowdat);
  283. // We colour the left-hand column red or green, depending on
  284. // whether we found a difference or not. First, though, we work
  285. // out all the host rows
  286. $d = "";
  287. $keycol = "solidgreen";
  288. foreach($rowdat as $line) {
  289. if ($d != "")
  290. $d .= "\n<tr>";
  291. if (isset($line["all"])) {
  292. $cl = (isset($line["call"]))
  293. ? $line["call"]
  294. : false;
  295. $d .= new Cell($line["all"], $cl, false, false,
  296. $this->cols);
  297. }
  298. else {
  299. if (!isset($line["ca"])) $line["ca"] = false;
  300. if (!isset($line["cb"])) $line["cb"] = false;
  301. $d .= new Cell($line["a"], $line["ca"], false,
  302. $this->colwidth) . new Cell($line["b"], $line["cb"], false,
  303. $this->colwidth);
  304. $keycol = "solidred";
  305. }
  306. $d .= "</tr>";
  307. }
  308. if ($row == "hostname") {
  309. $ret .= "\n\n<tr><td class=\"blank\"></td>$d";
  310. }
  311. else {
  312. $ret .= "\n<tr><th class=\"$keycol\" ";
  313. if (count($rowdat) > 1)
  314. $ret .= "rowspan=\"" . count($rowdat) . "\"";
  315. $ret .= ">$row</th>$d";
  316. }
  317. }
  318. return $ret . "\n</table>";
  319. }
  320. protected function get_cmp_data($row)
  321. {
  322. // Get the "row" data for all hosts, and put it in an array. For
  323. // now, this only operates on two hosts. May increase later, which
  324. // is why it's in a separate method
  325. $ret = array();
  326. foreach($this->hosts as $host) {
  327. $ret[] = isset($this->data[$host][$row])
  328. ? $this->data[$host][$row]
  329. : array(false);
  330. }
  331. return $ret;
  332. }
  333. protected function compare_generic($data, $row)
  334. {
  335. // This is the method which does 90% of the comparisons. Returns an
  336. // array of arrays, each of which has these possible elements:
  337. // [all] = value : both values are the same
  338. // [a] = value in LH column
  339. // [b] = value in RH column
  340. // [ca] = class for LH column
  341. // [cb] = class for RH column
  342. // First find things that are the same
  343. $ret = array();
  344. foreach(array_intersect($data[0], $data[1]) as $match) {
  345. $ret[] = array("all" => $match, "ca" => false, "cb" => false);
  346. }
  347. // Now get the differences looking both ways. We do the
  348. // array_values() call so the indicies start at zero
  349. $ma = array_values(array_diff($data[0], $data[1]));
  350. $mb = array_values(array_diff($data[1], $data[0]));
  351. // We have to make the arrays the same size
  352. $sa = $diffs = count($ma);
  353. $sb = count($mb);
  354. if ($sa > $sb)
  355. $mb = array_pad($mb, $sa, false);
  356. elseif ($sb > $sa) {
  357. $ma = array_pad($ma, $sa, false);
  358. $diffs = $sb;
  359. }
  360. // Do we need to get the highest version?
  361. if (method_exists($this, "get_highver") && !in_array($row,
  362. $this->no_colour))
  363. $hv = $this->get_highver($data);
  364. // Go through the differences, colouring (or not) as we go
  365. for($i = 0; $i < $diffs; $i++) {
  366. if (!isset($ma[$i])) $ma[$i] = false;
  367. if (!isset($mb[$i])) $mb[$i] = false;
  368. $tmp_arr = array("a" => $ma[$i], "b" => $mb[$i]);
  369. if (in_array($row, $this->no_colour)) {
  370. $tmp_arr["ca"] = $tmp_arr["cb"] = false;
  371. }
  372. elseif(isset($hv)) {
  373. if (preg_match("/$hv/", $ma[$i]))
  374. $tmp_arr["ca"] = "ver_l";
  375. elseif(!empty($ma[$i]))
  376. $tmp_arr["ca"] = "ver_o";
  377. if (preg_match("/$hv/", $mb[$i]))
  378. $tmp_arr["cb"] = "ver_l";
  379. elseif(!empty($mb[$i]))
  380. $tmp_arr["cb"] = "ver_o";
  381. }
  382. else {
  383. if ($this->safe_compare($ma[$i], $mb[$i])) {
  384. $tmp_arr["ca"] = "ver_l";
  385. $tmp_arr["cb"] = "ver_o";
  386. }
  387. else {
  388. $tmp_arr["ca"] = "ver_o";
  389. $tmp_arr["cb"] = "ver_l";
  390. }
  391. }
  392. $ret[] = $tmp_arr;
  393. }
  394. return $ret;
  395. }
  396. protected function compare_sparse($data)
  397. {
  398. // Make a big array of everything, sort it, then see what's in
  399. // what. It's not really a comparison, just separates everthing on
  400. // both hosts into one, the other, or both.
  401. $whole = $tmp_arr = $ret = array();
  402. $a = $data[0];
  403. $b = $data[1];
  404. $whole = array_merge($a, $b);
  405. $whole = array_unique($whole);
  406. natsort($whole);
  407. foreach($whole as $el) {
  408. if (in_array($el, $a) && in_array($el, $b))
  409. $tmp_arr["all"] = $el;
  410. elseif (in_array($el, $a))
  411. $tmp_arr = array("a" => $el, "b" => false);
  412. else
  413. $tmp_arr = array("a" => false, "b" => $el);
  414. $ret[] = $tmp_arr;
  415. }
  416. return $ret;
  417. }
  418. protected function compare_hostname($data)
  419. {
  420. // Hostname gets a special row so we can set classes
  421. $a = array(
  422. array(
  423. "a" => $data[0][0],
  424. "b" => $data[1][0],
  425. "ca" => "keyhead",
  426. "cb" => "keyhead"
  427. )
  428. );
  429. return $a;
  430. }
  431. protected function compare_audit_completed($data)
  432. {
  433. // Work out the time difference between oldest and newest audits,
  434. // and colour accordingly. First row spans both columns and tells
  435. // you the time difference between the oldest and newest audits.
  436. // Seconds row displays the time of each
  437. $d_arr = array();
  438. $now = mktime();
  439. foreach($data as $datum) {
  440. $d = preg_split("/[:\s\/]+/", $datum[0]);
  441. $d_arr[] = mktime($d[0], $d[1], $d[2], $d[3], $d[4], $d[5]);
  442. }
  443. sort($d_arr);
  444. reset($d_arr);
  445. $first = current($d_arr);
  446. $last = end($d_arr);
  447. $diff = $last - $first;
  448. // If we're comparing two dates, say they're x apart, if it's more
  449. // than two, talk about a spread
  450. $string = (count($data) == 2)
  451. ? "apart"
  452. : "spread";
  453. $diff_col = "green";
  454. if ($diff == 0) {
  455. $txt = "identical times";
  456. }
  457. elseif ($diff < 60) {
  458. $txt = "$diff second(s) $string";
  459. }
  460. elseif ($diff < 3600) {
  461. $txt = round($diff / 60) . " minute(s) $string";
  462. }
  463. elseif ($diff < 216000) {
  464. $txt = round(($diff / 3660), 1) . " hour(s) $string";
  465. $diff_col = "amber";
  466. }
  467. else {
  468. $txt = round($diff / 216000) . " day(s) $string";
  469. $diff_col = "red";
  470. }
  471. return array(
  472. array("all" => "$txt", "call" => "solid$diff_col"),
  473. array("a" => $data[0][0], "b" => $data[1][0], "ca" => false,
  474. "cb" => false)
  475. );
  476. }
  477. public function safe_compare($a, $b)
  478. {
  479. // If you're comparing version numbers and you hit, say, 2.2.4 and
  480. // 2.2.11, a normal >/< type comparison will tell you 2.2.4 is the
  481. // later version, which it plainly isn't. This functon uses PHP's
  482. // natural sort algorithm to get the higher version. It also ignores
  483. // anything that's not part of the version string. (i.e. anything
  484. // after the first space)
  485. // returns true if a > b
  486. // returns false otherwise
  487. $ea = preg_replace("/ .*$/", "", $a);
  488. $eb = preg_replace("/ .*$/", "", $b);
  489. $arr = array($a, $b);
  490. natsort($arr);
  491. return (current($arr) == $a) ? false : true;
  492. }
  493. protected function preproc_bold_first_word($data, $sep = ":")
  494. {
  495. // For things that start "something:", put "something" in bold
  496. return preg_replace("/^(.*)($sep)/U", "<strong>$1$2</strong>",
  497. $data);
  498. }
  499. public function __toString()
  500. {
  501. return $this->html;
  502. }
  503. }
  504. //----------------------------------------------------------------------------
  505. // PLATFORM AUDITS
  506. class comparePlatform extends compareGeneric {
  507. protected $no_colour = array("hostname", "audit completed", "hardware",
  508. "virtualization", "serial number", "ALOM IP", "card", "memory",
  509. "storage", "EEPROM");
  510. protected function preproc_storage($data)
  511. {
  512. return $this->preproc_bold_first_word($data);
  513. }
  514. protected function preproc_EEPROM($data)
  515. {
  516. return $this->preproc_bold_first_word($data, "=");
  517. }
  518. }
  519. //----------------------------------------------------------------------------
  520. // O/S AUDITS
  521. class compareOS extends compareGeneric {
  522. protected $no_colour = array("hostname", "audit completed", "hostid",
  523. "uptime", "local zone", "distribution", "VM", "scheduler",
  524. "SMF services", "packages", "patches", "boot env", "publisher");
  525. protected $disp_name = "O/S";
  526. public function __construct($type, $data, $map)
  527. {
  528. // If the distributions aren't the same. don't colour the version or
  529. // kernel
  530. $dist_arr = array();
  531. foreach($data as $svr=>$dat) {
  532. $dist_arr[] = $dat["distribution"];
  533. }
  534. $dists = array_unique($dist_arr);
  535. if (count($dists > 1)) {
  536. $this->no_colour[] = "version";
  537. $this->no_colour[] = "kernel";
  538. $this->no_colour[] = "release";
  539. }
  540. parent::__construct($type, $data, $map);
  541. }
  542. protected function preproc_boot_env($data)
  543. {
  544. return $this->preproc_bold_first_word($data);
  545. }
  546. protected function preproc_VM($data)
  547. {
  548. // For now I'm just going to bold the VM type and strip out any [].
  549. // Might do more with this in future
  550. return $this->preproc_bold_first_word(preg_replace("/\[\]/", "",
  551. $data));
  552. }
  553. }
  554. //----------------------------------------------------------------------------
  555. // NETWORK AUDITS
  556. class compareNet extends compareGeneric {
  557. protected $no_colour = array("hostname", "audit completed", "NTP",
  558. "name service", "DNS server", "port", "route", "NIC", "routing");
  559. protected $sparse_list = array("port");
  560. protected function preproc_name_service($data)
  561. {
  562. return $this->preproc_bold_first_word($data);
  563. }
  564. protected function preproc_route($data)
  565. {
  566. return $this->preproc_bold_first_word($data, "\s");
  567. }
  568. protected function preproc_port($data)
  569. {
  570. // As on the net audit, we may want to remove high numbered ports.
  571. // Process the info in the same way too
  572. $ret = array();
  573. foreach($data as $datum) {
  574. $a = explode(":", $datum);
  575. if ((defined("OMIT_PORT_THRESHOLD")) && ($a[0] >
  576. OMIT_PORT_THRESHOLD))
  577. continue;
  578. if (empty($a[1])) $a[1] = "-";
  579. if (empty($a[2])) $a[2] = "-";
  580. $ret[] = "<strong>$a[0]</strong> ($a[1]/$a[2])";
  581. }
  582. return $ret;
  583. }
  584. protected function preproc_nic($data)
  585. {
  586. $ret = array();
  587. foreach($data as $datum) {
  588. $a = explode("|", $datum);
  589. $speed = "unknown speed";
  590. // Split the speed/duplex into two parts
  591. $sa = preg_split("/:|-/", $a[4]);
  592. // Now $sa[0] is the speed, $sa[1] is the duplex. I don't want
  593. // the "b" on the speed.
  594. $sa[0] = str_replace("b", "", $sa[0]);
  595. // Make the speed "1G" if it's 1000M. Also look out for long
  596. // strings from kstat.
  597. if ($sa[0] == "1000M" || $sa[0] == "1000000000")
  598. $sa[0] = "1G";
  599. elseif ($sa[0] == "100000000")
  600. $sa[0] = "100M";
  601. elseif ($sa[0] == "10000000")
  602. $sa[0] = "10M";
  603. // Make the duplex part "full" if it's only "f", and "half" if
  604. // it's only "h"
  605. if (sizeof($sa) > 1) {
  606. if ($sa[1] == "f")
  607. $sa[1] = "full";
  608. elseif ($sa[1] == "h")
  609. $sa[1] = "half";
  610. $speed = "${sa[0]}bit/$sa[1] duplex";
  611. }
  612. $ret[] = "<strong>$a[0]:</strong> $a[1] ($speed) $a[5]";
  613. }
  614. return $ret;
  615. }
  616. protected function cmp_key()
  617. {
  618. // If we've stripped out high numbered ports, say so
  619. if (defined("OMIT_PORT_THRESHOLD"))
  620. return "NOTE: in the &quot;port&quot; comparison, open ports
  621. above " . OMIT_PORT_THRESHOLD . " are not being displayed.";
  622. }
  623. }
  624. //----------------------------------------------------------------------------
  625. // FILESYSTEM AUDITS
  626. class compareFS extends compareGeneric {
  627. protected $no_colour = array("hostname", "audit completed", "zpool",
  628. "root fs", "fs", "export", "capacity", "disk group");
  629. protected $disp_name = "Filesystem";
  630. protected function preproc_zpool($data)
  631. {
  632. // Bold the pool name and bin the scrub info
  633. $data = preg_replace("/\(.*\) /", "", $data);
  634. return $this->preproc_bold_first_word($data, "\s");
  635. }
  636. protected function preproc_capacity($data)
  637. {
  638. // Bold the capacity. Might do more with this one day. Can't decide
  639. // now.
  640. return $this->preproc_bold_first_word($data, "\s");
  641. }
  642. protected function preproc_disk_group($data)
  643. {
  644. // Just bold the disk group name and show the number of disks in it.
  645. // Bin the rest.
  646. $data = preg_replace("/ .*\[(\d+ disk).*$/", " [$1(s)]", $data);
  647. return $this->preproc_bold_first_word($data, "\s");
  648. }
  649. protected function preproc_fs($data)
  650. {
  651. // Keep the mountpoint, filesystem type and device. Leaving anything
  652. // else makes comparisons pointless because it'll never match. Omit
  653. // options.
  654. $ret = array();
  655. foreach($data as $datum) {
  656. if (!preg_match("/unmounted/", $datum))
  657. $ret[] = $datum;
  658. }
  659. return preg_replace("/^(\S+) (\w+).*\(([^;]*);.*$/",
  660. "<strong>$1</strong> $3 ($2)", $ret);
  661. }
  662. protected function preproc_export($data)
  663. {
  664. // Bold the export name, keep the export type, bin the rest
  665. return preg_replace("/^(\S+) (\(\w+\)).*$/", "<strong>$1</strong> $2",
  666. $data);
  667. }
  668. }
  669. //----------------------------------------------------------------------------
  670. // APPLICATION AUDITS
  671. class compareApp extends compareGeneric {
  672. protected $disp_name = "Application";
  673. protected $no_colour = array("AI server");
  674. private $cmp_vals = array();
  675. protected function preproc_generic($data)
  676. {
  677. // Split up the version and the path info
  678. return preg_replace("/@=(.*).*$/", " [$1]$2", $data);
  679. }
  680. protected function postproc_sshd($data)
  681. {
  682. // Don't colour if we're comparing SunSSH and OpenSSH. Just look at
  683. // the first letter
  684. $cmp_arr = array();
  685. foreach($data as $row => $dat) {
  686. if (!empty($dat["a"])) $cmp_arr[] = $dat["a"][0];
  687. if (!empty($dat["b"])) $cmp_arr[] = $dat["b"][0];
  688. }
  689. $cmp_arr = array_unique($cmp_arr);
  690. return (count($cmp_arr) == 1)
  691. ? $data
  692. : $this->uncolour($data);
  693. }
  694. protected function postproc_x_server($data)
  695. {
  696. // Don't colour if we have XSun. (We'd be either comparing to Xorg,
  697. // or always get an identical match as XSun doesn't report a
  698. // version.)
  699. $xsun = false;
  700. foreach($data as $row => $dat) {
  701. if (!isset($dat["a"])) $dat["a"] = false;
  702. if (!isset($dat["b"])) $dat["b"] = false;
  703. if (preg_match("/Xsun/", $dat["a"]) || preg_match("/Xsun/",
  704. $dat["b"])) {
  705. $xsun = true;
  706. break;
  707. }
  708. }
  709. return ($xsun)
  710. ? $this->uncolour($data)
  711. : $data;
  712. }
  713. private function uncolour($data)
  714. {
  715. // strip colouring info out of an array
  716. $ret = array();
  717. $cols = array("ca" => true, "cb" => true);
  718. foreach($data as $datum) {
  719. $ret[] = array_diff_key($datum, $cols);
  720. }
  721. return $ret;
  722. }
  723. protected function get_highver($data)
  724. {
  725. // We may have two versions of python on one box and four on
  726. // another. This attempts to handle that by finding the highest
  727. // version. This information is fed back into the compare_generic()
  728. // method.
  729. $vers = array();
  730. foreach($data as $svr) {
  731. $vers = array_merge($vers, $svr);
  732. }
  733. // strip off the path, and sort. Get the highest version
  734. $vers = preg_replace("/\s*[\(\[].*$/", "", $vers);
  735. natsort($vers);
  736. return end($vers);
  737. }
  738. }
  739. //----------------------------------------------------------------------------
  740. // TOOL AUDITS
  741. class compareTool extends compareApp {
  742. protected $disp_name = "Tool";
  743. protected $no_colour = array();
  744. }
  745. //----------------------------------------------------------------------------
  746. // SECURITY AUDITS
  747. class compareSecurity extends compareGeneric {
  748. protected $sparse_list = array("user");
  749. protected $no_colour = array("user_attr", "root shell", "dtlogin",
  750. "cron job");
  751. protected function preproc_user_attr($data)
  752. {
  753. return $this->preproc_bold_first_word($data);
  754. }
  755. protected function preproc_dtlogin($data)
  756. {
  757. // Split up the version and the path info
  758. return preg_replace("/@=(.*).*$/", " [$1]$2", $data);
  759. }
  760. protected function preproc_cron_job($data)
  761. {
  762. // Cron jobs need HTMLizing. Also put the user in bold
  763. $ret = array();
  764. foreach($data as $datum) {
  765. $ret[] = htmlentities($datum);
  766. }
  767. return $this->preproc_bold_first_word($ret);
  768. }
  769. }
  770. //----------------------------------------------------------------------------
  771. // HOSTED SERVICES AUDITS
  772. class compareHosted extends compareGeneric {
  773. protected $disp_name = "Hosted Services";
  774. }
  775. //----------------------------------------------------------------------------
  776. // PATCH AND PACKAGE AUDITS
  777. class comparePatch extends compareGeneric {
  778. protected $disp_name = "Patch and Package";
  779. protected $sparse_list = array("patch", "package");
  780. }
  781. ?>