<?php
$g_data_dir="data";
/**
* Retrieve a backup row from the database using it's ID.
*
* Returns the following data as an array:
*
* [ BUName, Dir_Src, Dir_Dest, Files_Ex, Bu_Type, BuRunning, BuError, LastRunDt ]
*
*/
function get_bu_item( $id ){
if(!is_numeric($id) ) return null;
$id=(int)$id;
[$table, $colIdxs] = rpc( 'f:getbu_list_all', "where BUID=$id" );
if( !array_key_exists( $id, $table ) ) return null;
$row = $table[$id];
return array(
$row[ $colIdxs['BUName']],
$row[ $colIdxs['Dir_Src']],
$row[ $colIdxs['Dir_Dest']],
$row[ $colIdxs['Files_Ex']],
$row[ $colIdxs['BuType']],
$row[ $colIdxs['BuRunning']],
$row[ $colIdxs['BuError']],
$row[ $colIdxs['LastRunDt']]
);
}
/**
* Set the error string in the database.
*/
function set_bu_error( $buid, $str_errs ){
[$err] = rpc( 'f:set_bu_error', $buid, $str_errs );
return $err;
}
/**
* Set (unset) the running datbase flag. Return true on success. The flag is
* unaltered if running in test mode.
*/
function set_bu_running( $id, bool $setit, bool $bu_test ){
if($bu_test) return true;
[$err] = rpc( 'f:set_bu_running', $id, (bool)$setit );
return $err;
}
function run_backup_block( $buid, $row, $bu_test ){
//$row = get_bu_item( $buid );
if( !$bu_test && $row[5]==1){
return "Backup for item($buid) is already running\n";
}
$bu_name = $row[0];
$bu_src = $row[1];
$bu_dest = $row[2];
$exFiles = $row[3];
$bu_type = $row[4];
$bu_rnng = $row[5];
// To ensure uniqueness, we add the backup ID on the end of the path as a subdirectory.
$bu_dest = "$bu_dest/bu_$buid";
// Make sure that the directory exists
if( !file_exists($bu_dest) ) {
if( false===mkdir( $bu_dest, 0777, true )){
return "Failed to create directory $bu_dest";
}
}
if($bu_type==1 ){
return run_backup_DB( $bu_test, $buid, $bu_src, $bu_dest );
}
return run_backup_F( $bu_test, $buid, $bu_src, $bu_dest, $exFiles );
}
/**
* This function is now used directly by the backup service.
*/
function run_backup_F( $bu_test, $buid, $bu_src, $bu_dest, $exFiles ){
global $g_data_dir;
if(!set_bu_running( $buid, true, $bu_test )){
return "Could not set the DB flag ";//.SQLite3::lastErrorMsg();
}
if($bu_test){
$flags = '-anv'; // n is the dry run indicator
}else{
$flags = '-av';
set_bu_error( $buid, '' ); //clear any previous error
//set_last_run_date( $buid, gmdate("Y-m-d H:i:s") );
}
$fn_o = getFilename_out( $buid, $bu_test, false );
$fn_e = getFilename_out( $buid, $bu_test, true );
// create the output files with the ID in the first line
file_put_contents("$g_data_dir/$fn_o","ID: $buid");
file_put_contents("$g_data_dir/$fn_e","ID: $buid");
if( !file_exists( "$g_data_dir/$fn_e" )){
return "exec failed to create file $fn_e";
}
$str_exPaths = '';
if(trim( $exFiles )!=''){
$fn_x = getFilename_tmp( $buid, 'x' );
file_put_contents( "$g_data_dir/$fn_x", $exFiles );
$str_exPaths = "--exclude-from=$g_data_dir/$fn_x";
}
// bash command
//rsync -a --exclude-from=to-exclude.txt $PATH_SRC $BKUP_DEST
//rsync -anv --exclude-from=to-exclude.txt $PATH_SRC $BKUP_DEST <-- for testing
$command = "rsync $flags $str_exPaths $bu_src $bu_dest 2>> $g_data_dir/$fn_e 1>> $g_data_dir/$fn_o";
$output = array();
$result_code = null;
if( exec( $command, $output, $result_code )===FALSE){
set_bu_running( $buid, false, $bu_test );
return "rsync failed";
}
set_bu_running( $buid, false, $bu_test );
// can we find any error strings in the error file?
$str_errs = file_get_contents( "$g_data_dir/$fn_e" );
$pos = strpos($str_errs, 'error' );
if($pos===FALSE){
$pos = strpos($str_errs, 'failed' );
}
if($pos===FALSE) return;
//place it in the database
set_bu_error( $buid, $str_errs );
}
/**
* This function is now used directly by the backup service.
*/
function run_backup_DB( $bu_test, $buid, $bu_src, $bu_dest ){
global $g_data_dir;
if(!set_bu_running( $buid, true, $bu_test )){
return "Could not set the DB flag";
}
if(!is_dir($bu_dest) ){
return "Destination ($bu_dest) is not a directory";
}
if($bu_test){
$fn_o = getFilename_out( $buid, $bu_test, false );
$bu_dest = "$g_data_dir";
}else{
$fn_o = "$bu_src.sql";
set_bu_error( $buid, '' ); //clear any previous error
//set_last_run_date( $buid, gmdate("Y-m-d H:i:s") );
}
// create the error files with the ID in the first line
$fn_e = getFilename_out( $buid, $bu_test, true );
exec("echo 'ID: $buid' > $g_data_dir/$fn_e");
// bash command
//mysqldump johntest > /home/johnp/tmp/dbs/johntest.sql
$command = "mysqldump $bu_src 2>> $g_data_dir/$fn_e 1>> $bu_dest/$fn_o";
$output = array();
$result_code = null;
if( exec( $command, $output, $result_code )===FALSE){
set_bu_running( $buid, false, $bu_test );
return "mysqldump failed";
}
set_bu_running( $buid, false, $bu_test );
// can we find any error strings in the error file?
$str_errs = file_get_contents( "$g_data_dir/$fn_e" );
$pos = strpos($str_errs, 'error' );
if($pos===FALSE){
$pos = strpos($str_errs, 'failed' );
}
if($pos===FALSE) return;
//place it in the database
set_bu_error( $buid, $str_errs );
}
function getFilename_out( $buid, bool $bu_test, bool $isErr=false ){
return getFilename_tmp( $buid, $bu_test?'t':'n', $isErr? 'err': 'op' );
}
/**
* Create an output file for the backup (forked) process to use. These are essentually
* temporary files which may be deleted after the back process completes.
*
* buid: backup record id
*
* fn_type:
* t: for test files
* n: for non-test files
* x: for file exclusion list
*
* fn_stream:
* op: output stream
* err: error stream
*/
function getFilename_tmp( $buid, $fn_type='t', $fn_stream='op' ){
return "bu-$fn_type-$fn_stream-$buid.txt";
}
function set_last_run_date( $buid, $str_dt ){
global $g_database_path;
$db = new SQLite3( __DIR__."/$g_database_path" );
$p = $db->prepare("update BULIST set LastRunDt=:str_dt where BUID=:buid");
$p->bindValue(':str_dt', $str_dt );
$p->bindValue(':buid', $buid );
$p->execute();
if( $db->lastErrorCode()!==0){
return $db->lastErrorCode();
}
}
function set_sched_date( $buid, $dt_new ){
global $g_database_path;
$db = new SQLite3( __DIR__."/$g_database_path" );
$p = $db->prepare("update BULIST set BU_DATE=:str_dt where BUID=:buid");
$p->bindValue(':str_dt', $dt_new );
$p->bindValue(':buid', $buid );
$p->execute();
if( $db->lastErrorCode()!==0){
return $db->lastErrorCode();
}
}
?>