3 +-------------------------------------------------------------------------+
4 | Copyright (C) 2004 Juan Luis Francés Jiménez |
5 | Copyright 2010-2011, Davide Franco |
7 | This program is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU General Public License |
9 | as published by the Free Software Foundation; either version 2 |
10 | of the License, or (at your option) any later version. |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 +-------------------------------------------------------------------------+
23 public $db_link; // Database link
25 private $config_file; // Config filename
26 private $config; // Loaded config from bacula.conf
27 private $catalogs = array(); // Catalog array
29 private $catalog_current_id;
32 function __construct()
34 $this->bwcfg = new Config();
37 // Loading configuration from config file
38 $this->bwcfg->Load_Config();
39 $this->catalog_nb = $this->bwcfg->Count_Catalogs();
41 // Initialize smarty template classe
43 // Initialize smarty gettext function
44 $this->init_gettext();
47 if( isset($_POST['catalog_id']) ) {
48 $this->catalog_current_id = $_POST['catalog_id'];
49 $_SESSION['catalog_id'] = $this->catalog_current_id;
51 elseif( isset( $_SESSION['catalog_id'] ) )
52 $this->catalog_current_id = $_SESSION['catalog_id'];
54 $this->catalog_current_id = 0;
55 $_SESSION['catalog_id'] = $this->catalog_current_id;
58 $this->tpl->assign( 'catalog_current_id', $this->catalog_current_id );
61 $dsn = $this->bwcfg->Get_Dsn( $this->catalog_current_id );
63 // Connect to the database
64 $options = array( 'portability' => DB_PORTABILITY_ALL );
65 $this->db_link = $this->connect( $dsn, $options );
67 // Database connection
69 $this->db_link = new CDB( $this->bwcfg->getDSN($this->catalog_current_id),
70 $this->bwcfg->getUser($this->catalog_current_id),
71 $this->bwcfg->getPwd($this->catalog_current_id) );
72 $this->db_link->makeConnection();
74 }catch( PDOException $e ) {
75 CDBError::raiseError( $e );
78 if (DB::isError($this->db_link)) {
79 $this->TriggerDBError('Unable to connect to catalog', $this->db_link);
81 $this->driver = $dsn['phptype'];
82 register_shutdown_function(array(&$this,'close') );
83 $this->db_link->setFetchMode(DB_FETCHMODE_ASSOC);
87 if( $this->catalog_nb > 1 ) {
89 $this->tpl->assign( 'catalogs', $this->bwcfg->Get_Catalogs() );
91 $this->tpl->assign( 'catalog_nb', $this->catalog_nb );
95 // Initialize Smarty template classe
98 $this->tpl = new Smarty();
100 $this->tpl->compile_check = true;
101 $this->tpl->debugging = false;
102 $this->tpl->force_compile = true;
104 $this->tpl->template_dir = "./templates";
105 $this->tpl->compile_dir = "./templates_c";
108 function init_gettext()
110 global $smarty_gettext_path;
112 if ( function_exists("gettext") ) {
113 require_once( BW_SMARTY_GETTEXT . "smarty_gettext.php" );
114 $this->tpl->register_block('t','smarty_translate');
116 $language = $this->bwcfg->Get_Config_Param("lang");
117 $domain = "messages";
118 putenv("LANG=$language");
119 setlocale(LC_ALL, $language);
120 bindtextdomain($domain,"./locale");
124 function smarty_translate($params, $text, &$smarty) {
127 $smarty->register_block('t','smarty_translate');
133 $this->db_link->disconnect();
142 switch( $this->db_link->getDriver() )
145 $query = "SELECT table_schema AS 'database', sum( data_length + index_length) AS 'dbsize' ";
146 $query .= "FROM information_schema.TABLES ";
147 $query .= "WHERE table_schema = 'bacula' ";
148 $query .= "GROUP BY table_schema";
151 $query = "SELECT pg_database_size('bacula') AS dbsize";
154 // Not yet implemented
159 // Execute SQL statment
161 $result = $this->db_link->runQuery( $query );
162 $db_size = $result->fetch();
163 $db_size = CUtils::Get_Human_Size( $db_size['dbsize'] );
164 }catch( PDOException $e) {
165 CDBError::raiseError($e);
169 $result = $this->db_link->query( $query );
171 if(! PEAR::isError( $result ) )
173 $db = $result->fetchRow();
174 $database_size = $db['dbsize'];
176 $this->TriggerDBError( 'Unable to get database size', $result);
178 return CUtils::Get_Human_Size( $database_size );
180 } // end function GetDbSize()
182 public function Get_Nb_Clients()
186 $query = "SELECT COUNT(*) AS nb_client FROM Client";
189 $clients = $this->db_link->runQuery( $query );
190 $clients_nb = $clients->fetch();
191 }catch( PDOException $e ) {
192 CDBError::raiseError( $e );
197 $clients = $this->db_link->query("SELECT COUNT(*) AS nb_client FROM Client");
198 if( PEAR::isError($clients) )
199 $this->TriggerDBError("Unable to get client number", $clients );
201 return $clients->fetchRow( DB_FETCHMODE_ASSOC );
205 // Return an array of volumes ordered by poolid and volume name
206 function GetVolumeList()
210 $volumes_list = array();
214 // Get the list of pools id
215 $query = "SELECT Pool.poolid, Pool.name FROM Pool ORDER BY Pool.poolid";
218 foreach( $this->getPools() as $pool ) {
219 switch( $this->db_link->getDriver() )
223 $query = "SELECT Media.volumename, Media.volbytes, Media.volstatus, Media.mediatype, Media.lastwritten, Media.volretention
224 FROM Media LEFT JOIN Pool ON Media.poolid = Pool.poolid
225 WHERE Media.poolid = '". $pool['poolid'] . "' ORDER BY Media.volumename";
228 $query = "SELECT media.volumename, media.volbytes, media.volstatus, media.mediatype, media.lastwritten, media.volretention
229 FROM media LEFT JOIN pool ON media.poolid = pool.poolid
230 WHERE media.poolid = '". $pool['poolid'] . "' ORDER BY media.volumename";
234 $volumes = $this->db_link->runQuery($query);
236 if( !array_key_exists( $pool['name'], $volumes_list) )
237 $volumes_list[ $pool['name'] ] = array();
239 foreach( $volumes->fetchAll() as $volume ) {
240 if( $volume['lastwritten'] != "0000-00-00 00:00:00" ) {
242 // Calculate expiration date if the volume is Full
243 if( $volume['volstatus'] == 'Full' ) {
244 $expire_date = strtotime($volume['lastwritten']) + $volume['volretention'];
245 $volume['expire'] = strftime("%Y-%m-%d", $expire_date);
247 $volume['expire'] = 'N/A';
250 // Media used bytes in a human format
251 $volume['volbytes'] = CUtils::Get_Human_Size( $volume['volbytes'] );
253 $volume['lastwritten'] = "N/A";
254 $volume['expire'] = "N/A";
255 $volume['volbytes'] = "0 KB";
259 if( count( $volumes_list[ $pool['name'] ] ) % 2)
260 $volume['class'] = 'odd';
262 // Add the media in pool array
263 array_push( $volumes_list[ $pool['name']], $volume);
264 } // end foreach volumes
265 } // end foreach pools
267 }catch(PDOException $e) {
268 CDBError::raiseError($e);
271 return $volumes_list;
273 $pools = $this->db_link->query( $query );
275 if( PEAR::isError( $pools ) )
276 $this->TriggerDBError("Failed to get pool list", $pools );
279 while( $pool = $pools->fetchRow( DB_FETCHMODE_ASSOC ) ) {
280 switch( $this->db_link->getDriver() )
283 $query = "SELECT Media.volumename, Media.volbytes, Media.volstatus, Media.mediatype, Media.lastwritten, Media.volretention
284 FROM Media LEFT JOIN Pool ON Media.poolid = Pool.poolid
285 WHERE Media.poolid = '". $pool['poolid'] . "' ORDER BY Media.volumename";
288 $query = "SELECT media.volumename, media.volbytes, media.volstatus, media.mediatype, media.lastwritten, media.volretention
289 FROM media LEFT JOIN pool ON media.poolid = pool.poolid
290 WHERE media.poolid = '". $pool['poolid'] . "' ORDER BY media.volumename";
293 $query = ""; // not yet implemented
299 $medias = $this->db_link->query( $query );
301 if( PEAR::isError( $medias ) ) {
302 $this->TriggerDBError("Failed to get media list for pool", $medias);
304 if( $debug ) echo "Found " . $medias->numRows() . " medias for pool " . $pool['name'] . " <br />";
306 // Create array key for each pool
307 if( !array_key_exists( $pool['name'], $volumes) )
309 $volumes[ $pool['name'] ] = array();
311 while( $media = $medias->fetchRow( DB_FETCHMODE_ASSOC ) ) {
315 // If the pool is empty (no volumes in this pool)
316 if( $medias->numRows() == 0 ) {
317 if( $debug ) echo "No media in pool " . $pool['name'] . "<br />";
319 if( $media['lastwritten'] != "0000-00-00 00:00:00" ) {
320 // Calculate expiration date if the volume is Full
321 if( $media['volstatus'] == 'Full' ) {
322 $expire_date = strtotime($media['lastwritten']) + $media['volretention'];
323 $media['expire'] = strftime("%Y-%m-%d", $expire_date);
325 $media['expire'] = 'N/A';
327 // Media used bytes in a human format
328 $media['volbytes'] = CUtils::Get_Human_Size( $media['volbytes'] );
330 $media['lastwritten'] = "N/A";
331 $media['expire'] = "N/A";
332 $media['volbytes'] = "0 KB";
336 if( count( $volumes[ $pool['name'] ] ) % 2)
337 $media['class'] = 'odd';
339 // Add the media in pool array
340 array_push( $volumes[ $pool['name']], $media);
348 } // end function GetVolumeList()
350 public function countJobs( $start_timestamp, $end_timestamp, $status = 'ALL', $level = 'ALL', $jobname = 'ALL', $client = 'ALL' )
353 $where_interval = "";
354 $where_conditions = array();
357 // Calculate sql query interval
358 $start_date = date( "Y-m-d H:i:s", $start_timestamp);
359 $end_date = date( "Y-m-d H:i:s", $end_timestamp);
361 switch( $this->db_link->getDriver() )
365 $query .= "SELECT COUNT(*) AS job_nb FROM Job ";
366 $where_conditions[] = "(EndTime BETWEEN '$start_date' AND '$end_date')";
369 $query .= "SELECT COUNT(*) AS job_nb FROM job ";
370 $where_conditions[] = "(EndTime BETWEEN timestamp '$start_date' AND timestamp '$end_date')";
374 if( $status != 'ALL' ) {
375 switch( strtolower($status) )
378 array_pop( $where_conditions );
379 $where_conditions[] = "JobStatus = 'R' ";
382 $where_conditions[] = "JobStatus = 'T' ";
385 $where_conditions[] = "JobStatus IN ('f','E') ";
388 $where_conditions[] = "JobStatus = 'A' ";
391 array_pop( $where_conditions );
392 $where_conditions[] = "Job.JobStatus IN ('F','S','M','m','s','j','c','d','t','p','C') ";
398 if( $level != 'ALL' )
399 $where_conditions[] = "Level = '$level' ";
401 // Construct SQL query
402 foreach( $where_conditions as $k => $condition ) {
404 $query .= "WHERE $condition ";
406 $query .= "AND $condition ";
411 $jobs = $this->db_link->runQuery($query);
412 $result = $jobs->fetch();
413 }catch(PDOException $e) {
414 CDBError::raiseError($e);
417 return $result['job_nb'];
419 $jobs = $this->db_link->query( $query );
421 if (!PEAR::isError( $jobs ) ) {
422 $jobs = $jobs->fetchRow();
423 return $jobs['job_nb'];
426 $this->TriggerDBError("Unable to get last $status jobs number from catalog", $jobs);
430 // Return the list of Pools in a array
431 public function getPools()
436 switch( $this->db_link->getDriver() )
440 $query = "SELECT name, poolid FROM Pool";
443 $query = "SELECT name, poolid FROM pool";
447 $result = $this->db_link->runQuery($query);
448 foreach( $result->fetchAll() as $pool )
450 }catch(PDOException $e) {
451 CDBError::raiseError($e);
456 $result = $this->db_link->query ( $query );
458 if( !PEAR::isError( $result ) ) {
459 while( $pool = $result->fetchRow() )
463 $this->TriggerDBError( "Unable to get the pool list from catalog", $result );
467 public function Get_BackupJob_Names()
471 $backupjobs = array();
473 switch( $this->db_link->getDriver() )
477 $query = "SELECT name FROM Job GROUP BY name ORDER BY name";
480 $query = "SELECT name FROM Job GROUP BY name ORDER BY name";
484 $result = $this->db_link->runQuery($query);
485 foreach( $result->fetchAll() as $jobname )
486 $backupjobs[] = $jobname['name'];
487 }catch(PDOException $e) {
488 CDBError::raiseError($e);
493 $result = $this->db_link->query( $query );
495 if (PEAR::isError( $result ) ) {
496 $this->TriggerDBError("Unable to get BackupJobs list from catalog", $result );
498 while( $backupjob = $result->fetchRow() ) {
499 array_push( $backupjobs, $backupjob["name"] );
506 public function countVolumes( $pool_id = 'ALL' )
512 switch( $this->db_link->getDriver() )
516 $query = 'SELECT COUNT(*) as vols_count ';
517 $query .= 'FROM Media ';
518 if( $pool_id != 'ALL' )
519 $query .= ' WHERE Media.poolid = ' . $pool_id;
522 $query = 'SELECT COUNT(*) as vols_count ';
523 $query .= 'FROM Media ';
524 if( $pool_id != 'ALL' )
525 $query .= ' WHERE media.poolid = ' . $pool_id;
531 $result = $this->db_link->runQuery($query);
532 $vols = $result->fetch();
533 }catch( PDOException $e) {
534 CDBError::raiseError($e);
537 return $vols['vols_count'];
539 $res = $this->db_link->query( $query );
541 if( !PEAR::isError( $res ) ) {
542 $vols = $res->fetchRow( );
543 return $vols['vols_count'];
545 $this->triggerDBError( 'Unable to get volume number from pool', $res );
549 public function getStoredFiles( $start_timestamp, $end_timestamp, $job_name = 'ALL' )
552 $start_date = date( "Y-m-d H:i:s", $start_timestamp);
553 $end_date = date( "Y-m-d H:i:s", $end_timestamp);
555 switch( $this->db_link->getDriver() )
559 $query = "SELECT SUM(JobFiles) AS stored_files FROM Job ";
560 $query .= "WHERE ( EndTime BETWEEN '$start_date' AND '$end_date' )";
563 $query = "SELECT SUM(JobFiles) AS stored_files FROM job ";
564 $query .= "WHERE ( endtime BETWEEN timestamp '$start_date' AND timestamp '$end_date' )";
568 if( $job_name != 'ALL' )
569 $query .= " AND name = '$job_name'";
573 $result = $this->db_link->runQuery( $query );
574 $result = $result->fetch();
575 }catch( PDOException $e) {
576 CDBError::raiseError($e);
579 if( isset($result['stored_files']) and !empty($result['stored_files']) )
580 return $result['stored_files'];
584 $result = $this->db_link->query( $query );
586 if( !PEAR::isError($result) ) {
587 $result = $result->fetchRow();
589 if( isset($result['stored_files']) and !empty($result['stored_files']) )
590 return $result['stored_files'];
594 $this->TriggerDBError("Unable to get protected files from catalog", $result);
599 // Function: getStoredBytes
601 // $start_timestamp: start date in unix timestamp format
602 // $end_timestamp: end date in unix timestamp format
603 // $job_name: optional job name
605 public function getStoredBytes( $start_timestamp, $end_timestamp, $job_name = 'ALL' )
609 $start_date = date( "Y-m-d H:i:s", $start_timestamp);
610 $end_date = date( "Y-m-d H:i:s", $end_timestamp);
612 switch( $this->db_link->getDriver() )
616 $query = "SELECT SUM(JobBytes) as stored_bytes FROM Job ";
617 $query .= "WHERE ( EndTime BETWEEN '$start_date' AND '$end_date' )";
620 $query = "SELECT SUM(jobbytes) as stored_bytes FROM job ";
621 $query .= "WHERE ( endtime BETWEEN timestamp '$start_date' AND timestamp '$end_date' )";
625 if( $job_name != 'ALL' )
626 $query .= " AND name = '$job_name'";
628 // Execute SQL statment
630 $result = $this->db_link->runQuery( $query );
631 $result = $result->fetch();
632 }catch(PDOException $e) {
633 CDBError::raiseError( $e );
636 if( isset($result['stored_bytes']) and !empty($result['stored_bytes']) )
637 return $result['stored_bytes'];
641 $result = $this->db_link->query( $query );
643 // Testing query result
644 if( PEAR::isError( $result ) ) {
645 $this->TriggerDBError("Unable to get Job Bytes from catalog", $result );
647 $result = $result->fetchRow();
649 if( !PEAR::isError($result) ) {
650 if( isset($result['stored_bytes']) and !empty($result['stored_bytes']) )
651 return $result['stored_bytes'];
655 $this->TriggerDBError( "Error fetching query result", $result);
660 public function TriggerDBError( $message, $db_error)
662 echo 'Error: ' . $message . '<br />';
663 echo 'Standard Message: ' . $db_error->getMessage() . '<br />';
664 echo 'Standard Code: ' . $db_error->getCode() . '<br />';
665 echo 'DBMS/User Message: ' . $db_error->getUserInfo() . '<br />';
666 echo 'DBMS/Debug Message: ' . $db_error->getDebugInfo() . '<br />';