summaryrefslogblamecommitdiffstats
path: root/modules-available/backup/page.inc.php
blob: 9a2d08bec61a9b0af091418c358077fc0a5c51a3 (plain) (tree)
1
2
3
4
5
6
7




                              

                               




                                         
                                          
                                                                


                                                        

                                                         
                                        

                                                          
                                         


                                                         
                 
                                            



                                     
                                                                                                                      
                                                                            

                                                                                             
                        


                                                                        
                                                                                             




                                                                         
                                   

                                                       
                                                             

                                                                                                                               


                                                                                                           
                                                              




                                 



                                                                        
                                                                                



                                                              



                                                           
                                                                
                                                                                             
                                                                              




                                                                
                                                                                          

                                                     



                                                                                                             
                                                                       
                                                                               












                                                                                                                   
                                                                       












                                                                                                                    



                                                                        
                                                                                                              
                                                                                        
                                                                         

                                                     









                                                               
                                           

                                                                              
                                                                        
                                                                          










                                                                     
                                      
                                                              
                                                    
                                                        

                                                          


                                                                                                     
                   


                                                                       
                                                                              
                 

                                                               
                                               




                                                           




                                                            

                                                                   
                                         
                                                                      
                 
         
 





                                                                        





                                                                                                             




                                                                               
 
<?php

class Page_Backup extends Page
{

	/** @var ?string */
	private $action = null;
	private $templateData = array();

	protected function doPreprocess()
	{
		User::load();
		if (!User::isLoggedIn()) {
			Message::addError('main.no-permission');
			Util::redirect('?do=Main');
		}
		$this->action = Request::post('action');
		if ($this->action === 'backup') {
			User::assertPermission("create");
			$this->backup();
		} elseif ($this->action === 'restore') {
			User::assertPermission("restore");
			$this->restore();
		} elseif ($this->action === 'config') {
			User::assertPermission("config");
			$this->config();
		}
		User::assertPermission('*');
	}

	protected function doRender()
	{
		if ($this->action === 'restore') { // TODO: We're in post mode, redirect with all the taskids first...
			Render::addTemplate('restore', $this->templateData);
		} elseif (($taskid = Request::get('errtaskid', false, 'string')) !== false) {
			Render::addTemplate('task-error', ['taskid' => $taskid]);
		} else {
			// Normal page
			$title = Property::get('page-title-prefix', '');
			$bgcolor = Property::get('logo-background', '');
			$lastBackup = (int)Property::get(BackupRestore::PROP_LAST_BACKUP, 0);
			if ($lastBackup === 0) {
				$lastBackup = false;
			} else {
				$lastBackup = date('d.m.Y', $lastBackup);
			}
			$params = [
				'id_color' => $bgcolor,
				'id_prefix' => $title,
				'last_backup' => $lastBackup,
				'backup_' . Property::get(BackupRestore::PROP_AUTO_BACKUP_MODE, BackupRestore::BACKUP_MODE_OFF)
					. '_checked' => 'checked',
				'autoBackupPw' => Property::get(BackupRestore::PROP_AUTO_BACKUP_PASS, ''),
			];
			Permission::addGlobalTags($params['perms'], NULL, ['create', 'restore', 'config']);
			Render::addTemplate('_page', $params);
		}
	}

	private function backup()
	{
		$password = trim(Request::post('passwd', '', 'string'));
		if (empty($password)) {
			$password = null;
		}
		EventLog::info('Creating backup on ' . Property::getServerIp());
		$task = Taskmanager::submit('BackupRestore', [
			'mode' => 'backup',
			'password' => $password,
		]);
		if (!isset($task['id'])) {
			Message::addError('backup-failed');
			Util::redirect('?do=Backup');
		}
		$task = Taskmanager::waitComplete($task, 60000);
		if (!Taskmanager::isFinished($task) || !isset($task['data']['backupFile'])) {
			Util::redirect('?do=backup&errtaskid=' . $task['id']);
		}
		while ((@ob_get_level()) > 0)
			@ob_end_clean();
		$fh = @fopen($task['data']['backupFile'], 'rb');
		if ($fh === false) {
			Message::addError('main.error-read', $task['data']['backupFile']);
			Util::redirect('?do=Backup');
		}
		$userFn = 'satellite-backup_' . Property::getServerIp() . '_' . date('Y.m.d-H.i.s') . '.tgz';
		if ($password !== null) {
			$userFn .= '.aes';
		}
		Header('Content-Type: application/octet-stream', true);
		Header('Content-Disposition: attachment; filename=' . $userFn);
		Header('Content-Length: ' . @filesize($task['data']['backupFile']));
		while (!feof($fh)) {
			$data = fread($fh, 16000);
			if ($data === false) {
				EventLog::failure('Could not stream system backup to browser - backup corrupted!');
				die("\r\n\nDOWNLOAD INTERRUPTED!\n");
			}
			echo $data;
			@ob_flush();
			@flush();
		}
		@fclose($fh);
		@unlink($task['data']['backupFile']);
		Property::set(BackupRestore::PROP_LAST_BACKUP, time());
		die();
	}

	private function restore()
	{
		if (!isset($_FILES['backupfile'])) {
			Message::addError('missing-file');
			Util::redirect('?do=Backup');
		}
		if ($_FILES['backupfile']['error'] != UPLOAD_ERR_OK) {
			Message::addError('upload-failed', Util::uploadErrorString($_FILES['backupfile']['error']));
			Util::redirect('?do=Backup');
		}
		$password = trim(Request::post('passwd', '', 'string'));
		if (empty($password)) {
			$password = null;
		}
		$tempfile = '/tmp/bwlp-' . mt_rand(1, 100000) . '-' . crc32($_SERVER['REMOTE_ADDR']) . '.tgz';
		if (!move_uploaded_file($_FILES['backupfile']['tmp_name'], $tempfile)) {
			Message::addError('main.error-write', $tempfile);
			Util::redirect('?do=Backup');
		}
		copy($tempfile, $tempfile . '2');
		// Check if correct password first etc.
		$task = Taskmanager::submit('BackupRestore', [
			'mode' => 'test',
			'password' => $password,
			'backupFile' => $tempfile . '2',
		]);
		$task = Taskmanager::waitComplete($task, 5000);
		@unlink($tempfile . '2');
		if (Taskmanager::isFailed($task)) {
			@unlink($tempfile);
			Util::redirect('?do=backup&errtaskid=' . $task['id']);
		}
		// Got uploaded file, now shut down all the daemons etc.
		$parent = Trigger::stopDaemons(null, $this->templateData);
		// Unmount store
		$task = Taskmanager::submit('MountVmStore', array(
				'address' => 'null',
				'type' => 'images',
				'parentTask' => $parent,
				'failOnParentFail' => false
		));
		if (isset($task['id'])) {
			$this->templateData['mountid'] = $task['id'];
			$parent = $task['id'];
		}
		// Finally run restore
		$task = Taskmanager::submit('BackupRestore', [
				'mode' => 'restore',
				'password' => $password,
				'backupFile' => $tempfile,
				'parentTask' => $parent,
				'failOnParentFail' => false,
				'restoreOpenslx' => Request::post('restore_openslx', 'off') === 'on',
				'restoreDozmod' => Request::post('restore_dozmod', 'off') === 'on',
		]);
		if (isset($task['id'])) {
			$this->templateData['restoreid'] = $task['id'];
			$parent = $task['id'];
			TaskmanagerCallback::addCallback($task, 'dbRestored');
		}
		// Wait a bit
		$task = Taskmanager::submit('SleepTask', array(
				'seconds' => 6,
				'parentTask' => $parent,
				'failOnParentFail' => false
		));
		if (isset($task['id']))
			$parent = $task['id'];
		// Reboot
		$task = Taskmanager::submit('Reboot', array(
				'parentTask' => $parent,
				'failOnParentFail' => false
		));
		// Leave this comment so the i18n scanner finds it:
		// Message::addSuccess('restore-done');
		if (isset($task['id'])) {
			$this->templateData['rebootid'] = $task['id'];
		}
	}

	private function config()
	{
		$password = trim(Request::post('passwd', '', 'string'));
		if (empty($password)) {
			$password = null;
		}
		$mode = Request::post('auto-backup-mode', false, 'string');
		if ($mode !== BackupRestore::BACKUP_MODE_OFF && $mode !== BackupRestore::BACKUP_MODE_ROOTHOME
				&& $mode !== BackupRestore::BACKUP_MODE_VMSTORE) {
			Message::addError('invalid-auto-backup-mode', $mode);
			Util::redirect('?do=backup');
		}
		Property::set(BackupRestore::PROP_AUTO_BACKUP_MODE, $mode);
		Property::set(BackupRestore::PROP_AUTO_BACKUP_PASS, $password);
		Util::redirect('?do=backup');
	}

}