3 * Bacula(R) - The Network Backup Solution
4 * Baculum - Bacula web interface
6 * Copyright (C) 2013-2016 Kern Sibbald
8 * The main author of Baculum is Marcin Haba.
9 * The original author of Bacula is Kern Sibbald, with contributions
10 * from many others, a complete list can be found in the file AUTHORS.
12 * You may use this file and others of this release according to the
13 * license defined in the LICENSE file, which includes the Affero General
14 * Public License, v3.0 ("AGPLv3") and some additional permissions and
15 * terms pursuant to its AGPLv3 Section 7.
17 * This notice must be preserved when any source code is
18 * conveyed and/or propagated.
20 * Bacula(R) is a registered trademark of Kern Sibbald.
23 Prado::using('Application.Common.Class.Errors');
24 Prado::using('Application.API.Class.BException');
25 Prado::using('Application.API.Class.APIModule');
27 class Bconsole extends APIModule {
31 const BCONSOLE_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\n%s\nquit\nEND_OF_DATA";
33 const BCONSOLE_DIRECTORS_PATTERN = "%s%s -c %s -l 2>&1";
35 private $allowed_commands = array('version', 'status', 'list', 'messages', 'show', 'mount', 'umount', 'release', 'prune', 'purge', 'update', 'estimate', 'run', '.bvfs_update', '.bvfs_lsdirs', '.bvfs_lsfiles', '.bvfs_versions', '.bvfs_get_jobids', '.bvfs_restore', '.bvfs_clear_cache', 'restore', 'cancel', 'delete', '.jobs', 'label', 'reload', '.fileset', '.storage', '.client', '.pool');
39 private static $cmd_path;
41 private static $cfg_path;
43 public function init($param) {
44 $config = $this->getModule('api_config')->getConfig('bconsole');
45 if(count($config) > 0) {
46 $use_sudo = ((integer)$config['use_sudo'] === 1);
47 $cmd_path = $config['bin_path'];
48 $custom_cfg_path = self::getCfgPath();
49 $cfg_path = isset($custom_cfg_path) ? $custom_cfg_path : $config['cfg_path'];
50 $this->setEnvironmentParams($cmd_path, $cfg_path, $use_sudo);
54 public static function setCmdPath($path) {
55 // possible to set only once
56 if (is_null(self::$cmd_path)) {
57 self::$cmd_path = $path;
61 public static function getCmdPath() {
62 return self::$cmd_path;
65 public static function setCfgPath($path, $force = false) {
66 // possible to set only once
67 if (is_null(self::$cfg_path) || $force) {
68 self::$cfg_path = $path;
72 public static function getCfgPath() {
73 return self::$cfg_path;
76 public function setUseSudo($use_sudo) {
77 // possible to set only once
78 if (is_null($this->use_sudo)) {
79 $this->use_sudo = $use_sudo;
83 public function getUseSudo() {
84 return $this->use_sudo;
87 private function setEnvironmentParams($cmd_path, $cfg_path, $use_sudo) {
88 self::setCmdPath($cmd_path);
89 self::setCfgPath($cfg_path);
90 $this->setUseSudo($use_sudo);
93 private function isCommandValid($command) {
94 $command = trim($command);
95 return in_array($command, $this->allowed_commands);
98 private function prepareResult(array $output, $exitcode, $bconsole_command) {
99 array_pop($output); // deleted 'quit' bconsole command
100 for($i = 0; $i < count($output); $i++) {
101 if(strstr($output[$i], $bconsole_command) == false) {
107 $output = count($output) > 1 ? array_values($output) : array_shift($output);
108 return (object)array('output' => $output, 'exitcode' => (integer)$exitcode);
111 public function bconsoleCommand($director, array $command, $user = null) {
112 $base_command = count($command) > 0 ? $command[0] : null;
113 if($this->isCommandValid($base_command) === true) {
114 $result = $this->execCommand($director, $command, $user);
116 throw new BConsoleException(
117 BconsoleError::MSG_ERROR_INVALID_COMMAND,
118 BconsoleError::ERROR_INVALID_COMMAND
124 private function execCommand($director, array $command, $user) {
127 if(!is_null($director) && $this->isValidDirector($director) === false) {
128 throw new BConsoleException(
129 BconsoleError::MSG_ERROR_INVALID_DIRECTOR,
130 BconsoleError::ERROR_INVALID_DIRECTOR
133 $dir = is_null($director) ? '': '-D ' . $director;
134 $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
135 $bconsole_command = implode(' ', $command);
137 self::BCONSOLE_COMMAND_PATTERN,
144 exec($cmd, $output, $exitcode);
146 $emsg = ' Output=>' . implode("\n", $output) . ', Exitcode=>' . $exitcode;
147 throw new BConsoleException(
148 BconsoleError::MSG_ERROR_BCONSOLE_CONNECTION_PROBLEM . $emsg,
149 BconsoleError::ERROR_BCONSOLE_CONNECTION_PROBLEM
152 $result = $this->prepareResult($output, $exitcode, $bconsole_command);
155 $this->Application->getModule('logging')->log(
158 Logging::CATEGORY_EXECUTE,
166 public function getDirectors() {
167 $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
169 self::BCONSOLE_DIRECTORS_PATTERN,
174 exec($cmd, $output, $exitcode);
176 $emsg = ' Output=>' . implode("\n", $output) . ', Exitcode=>' . $exitcode;
177 throw new BConsoleException(
178 BconsoleError::MSG_ERROR_BCONSOLE_CONNECTION_PROBLEM . $emsg,
179 BconsoleError::ERROR_BCONSOLE_CONNECTION_PROBLEM
182 $result = (object)array('output' => $output, 'exitcode' => $exitcode);
186 private function isValidDirector($director) {
187 return in_array($director, $this->getDirectors()->output);
190 public function testBconsoleCommand(array $command, $cmd_path, $cfg_path, $use_sudo) {
191 $this->setEnvironmentParams($cmd_path, $cfg_path, $use_sudo);
195 $director = array_shift($this->getDirectors()->output);
196 $result = $this->bconsoleCommand($director, $command);
197 } catch (BException $e) {
198 $result = (object)array(
199 'output' => $e->getErrorMessage(),
200 'exitcode' => $e->getErrorCode()