]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/protected/API/Class/Bconsole.php
4ecdb66cb0f6e2dbb62db23ca276af21f304a712
[bacula/bacula] / gui / baculum / protected / API / Class / Bconsole.php
1 <?php
2 /*
3  * Bacula(R) - The Network Backup Solution
4  * Baculum   - Bacula web interface
5  *
6  * Copyright (C) 2013-2016 Kern Sibbald
7  *
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.
11  *
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.
16  *
17  * This notice must be preserved when any source code is
18  * conveyed and/or propagated.
19  *
20  * Bacula(R) is a registered trademark of Kern Sibbald.
21  */
22
23 Prado::using('Application.Common.Class.Errors');
24 Prado::using('Application.API.Class.BException');
25 Prado::using('Application.API.Class.APIModule');
26
27 class Bconsole extends APIModule {
28
29         const SUDO = 'sudo';
30
31         const BCONSOLE_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\n%s\nquit\nEND_OF_DATA";
32
33         const BCONSOLE_DIRECTORS_PATTERN = "%s%s -c %s -l 2>&1";
34
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');
36
37         private $use_sudo;
38
39         private static $cmd_path;
40
41         private static $cfg_path;
42
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);
51                 }
52         }
53
54         public static function setCmdPath($path) {
55                 // possible to set only once
56                 if (is_null(self::$cmd_path)) {
57                          self::$cmd_path = $path;
58                 }
59         }
60
61         public static function getCmdPath() {
62                 return self::$cmd_path;
63         }
64
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;
69                 }
70         }
71
72         public static function getCfgPath() {
73                 return self::$cfg_path;
74         }
75
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;
80                 }
81         }
82
83         public function getUseSudo() {
84                 return $this->use_sudo;
85         }
86
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);
91         }
92
93         private function isCommandValid($command) {
94                 $command = trim($command);
95                 return in_array($command, $this->allowed_commands);
96         }
97
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) {
102                                 unset($output[$i]);
103                         } else {
104                                 break;
105                         }
106                 }
107                 $output = count($output) > 1 ? array_values($output) : array_shift($output);
108                 return (object)array('output' => $output, 'exitcode' => (integer)$exitcode);
109         }
110
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);
115                 } else {
116                         throw new BConsoleException(
117                                 BconsoleError::MSG_ERROR_INVALID_COMMAND,
118                                 BconsoleError::ERROR_INVALID_COMMAND
119                         );
120                 }
121                 return $result;
122         }
123
124         private function execCommand($director, array $command, $user) {
125                 $cmd = '';
126                 $result = null;
127                 if(!is_null($director) && $this->isValidDirector($director) === false) {
128                         throw new BConsoleException(
129                                 BconsoleError::MSG_ERROR_INVALID_DIRECTOR,
130                                 BconsoleError::ERROR_INVALID_DIRECTOR
131                         );
132                 } else {
133                         $dir = is_null($director) ? '': '-D ' . $director;
134                         $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
135                         $bconsole_command = implode(' ', $command);
136                         $cmd = sprintf(
137                                 self::BCONSOLE_COMMAND_PATTERN,
138                                 $sudo,
139                                 self::getCmdPath(),
140                                 self::getCfgPath(),
141                                 $dir,
142                                 $bconsole_command
143                         );
144                         exec($cmd, $output, $exitcode);
145                         if($exitcode != 0) {
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
150                                 );
151                         } else {
152                                 $result = $this->prepareResult($output, $exitcode, $bconsole_command);
153                         }
154                 }
155                 $this->Application->getModule('logging')->log(
156                         $cmd,
157                         $output,
158                         Logging::CATEGORY_EXECUTE,
159                         __FILE__,
160                         __LINE__
161                 );
162
163                 return $result;
164         }
165
166         public function getDirectors() {
167                 $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
168                 $cmd = sprintf(
169                         self::BCONSOLE_DIRECTORS_PATTERN,
170                         $sudo,
171                         self::getCmdPath(),
172                         self::getCfgPath()
173                 );
174                 exec($cmd, $output, $exitcode);
175                 if($exitcode != 0) {
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
180                         );
181                 }
182                 $result = (object)array('output' => $output, 'exitcode' => $exitcode);
183                 return $result;
184         }
185
186         private function isValidDirector($director) {
187                 return in_array($director, $this->getDirectors()->output);
188         }
189
190         public function testBconsoleCommand(array $command, $cmd_path, $cfg_path, $use_sudo) {
191                 $this->setEnvironmentParams($cmd_path, $cfg_path, $use_sudo);
192                 $director = '';
193                 $result = null;
194                 try {
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()
201                         );
202                 }
203                 return $result;
204         }
205 }
206 ?>