3 require_once("openmediavault/object.inc");
4 require_once("openmediavault/config.inc");
5 require_once("openmediavault/error.inc");
6 require_once("openmediavault/util.inc");
7 require_once("openmediavault/rpcservice.inc");
8 require_once("openmediavault/notify.inc");
9 require_once("zfs/Utils.php");
10 require_once("zfs/Dataset.php");
11 require_once("zfs/Snapshot.php");
12 require_once("zfs/Zvol.php");
13 require_once("zfs/Zpool.php");
14 require_once("zfs/NotifyListener.php");
16 class OMVRpcServiceZFS extends OMVRpcServiceAbstract {
17 public function getName() {
18 return "ZFS"; // RPC Service name. Same as in .js files
21 /* Initialize the RPC service. Different methods of the RPC service are declared here*/
22 public function initialize() {
23 $this->registerMethod("addPool");
24 $this->registerMethod("getObjectTree");
25 $this->registermethod("passParam");
26 $this->registermethod("addObject");
27 $this->registermethod("deleteObject");
28 $this->registermethod("getProperties");
29 $this->registermethod("setProperties");
30 $this->registermethod("inherit");
31 $this->registermethod("getSharedParams");
32 $this->registermethod("createShare");
35 public function addPool($params, $context) {
36 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
37 switch ($params['pooltype']) {
39 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSPLAIN;
42 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSMIRROR;
45 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1;
48 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2;
51 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3;
54 throw new OMVModuleZFSException("Incorrect pool type specified");
57 //Check for user supplied options
59 if ($params['force']) {
62 if (strlen($params['mountpoint']) > 0) {
63 $opts .= "-m " . $params['mountpoint'] . " ";
66 //Use /dev/disk/by-path as deafult when creating new pools as suggested in ZoL FAQ.
67 $disks = preg_split("/[,;]/", $params['devices']);
68 if (file_exists("/dev/disk/by-path/")) {
70 foreach ($disks as $disk) {
71 $tmp_disks[] = OMVModuleZFSUtil::getDiskPath($disk);
76 $vdev = new OMVModuleZFSVdev($params['name'], $pooltype, $disks);
77 $pool = new OMVModuleZFSZpool($vdev, $opts);
78 //Ugly fix to solve the problem of blkid not displaying info on newly created pools
80 $pool->import($pool->getName());
83 public function getObjectTree($params, $context) {
84 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
85 $objects = OMVModuleZFSUtil::getZFSFlatArray();
87 foreach ($objects as $a){
88 $new[$a['parentid']][] = $a;
90 $tree = OMVModuleZFSUtil::createTree($new, $new['root']);
91 OMVModuleZFSUtil::addMissingOMVMntEnt(); //Adds missing ZFS filesystems to the OMV core
95 public function passParam($params, $context) {
96 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
97 //$msg = "Key=" . $params['key'] . ";Value=" . $params['value'] . ";";
98 //throw new OMVModuleZFSException($msg);
99 return array($params['key'] => $params['value']);
102 public function addObject($params, $context) {
103 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
104 switch ($params['type']) {
106 $name = $params['path'] . "/" . $params['name'];
107 $tmp = new OMVModuleZFSDataset($name);
110 $name = $params['path'] . "@" . $params['name'];
111 $tmp = new OMVModuleZFSSnapshot($name);
114 $name = $params['path'] . "/" . $params['name'];
115 $tmp = new OMVModuleZFSZvol($name);
116 $tmp->create($params['size']);
119 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
124 public function deleteObject($params, $context) {
125 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
126 switch ($params['type']) {
128 $name = $params['name'];
129 OMVModuleZFSUtil::deleteShares($name);
130 $tmp = new OMVModuleZFSDataset($name);
134 $name = $params['name'];
135 $tmp = new OMVModuleZFSDataset($name);
139 $name = $params['name'];
140 $tmp = new OMVModuleZFSSnapshot($name);
144 $name = $params['name'];
145 $tmp = new OMVModuleZFSZvol($name);
149 $name = $params['name'];
150 $tmp = new OMVModuleZFSZpool($name);
154 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
159 public function getProperties($params, $context) {
160 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
162 $name = $params['name'];
163 switch ($params['type']) {
166 $tmp = new OMVModuleZFSDataset($name);
169 $tmp = new OMVModuleZFSSnapshot($name);
172 $tmp = new OMVModuleZFSZvol($name);
175 $tmp = new OMVModuleZFSZpool($name);
178 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
181 $properties = $tmp->getProperties();
182 foreach ($properties as $propertyk => $propertyv) {
183 if (!(strcmp($propertyv['source'], "-") == 0)) {
184 $objects[] = array('property' => $propertyk,
185 'value' => $propertyv['value'],
186 'source' => $propertyv['source'],
187 'modified' => "false");
193 public function setProperties($params, $context) {
194 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
196 switch ($params['type']) {
199 $tmp = new OMVModuleZFSDataset($params['name']);
202 $tmp = new OMVModuleZFSSnapshot($params['name']);
205 $tmp = new OMVModuleZFSZvol($params['name']);
208 $tmp = new OMVModuleZFSZpool($params['name']);
211 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
214 foreach ($params['properties'] as $property) {
215 $objects[$property['property']] = $property['value'];
217 $tmp->setProperties($objects);
220 public function inherit($params, $context) {
221 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
222 // Create a background process.
223 $bgStatusFilename = $this->createBgProcStatus();
224 $pid = $this->fork();
225 if($pid > 0) { // Parent process.
226 $this->initializeBgProcStatus($bgStatusFilename, $pid);
227 return $bgStatusFilename;
231 $bgOutputFilename = $this->createBgProcOutput();
232 $this->updateBgProcStatus($bgStatusFilename, "outputfilename", $bgOutputFilename);
233 switch ($params['type']) {
236 $tmp = new OMVModuleZFSDataset($params['name']);
239 $tmp = new OMVModuleZFSSnapshot($params['name']);
242 $tmp = new OMVModuleZFSZvol($params['name']);
245 $tmp = new OMVModuleZFSZpool($params['name']);
248 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
251 $tmp->inherit($params['property']);
252 $this->finalizeBgProcStatus($bgStatusFilename, $output);
254 } catch(Exception $e) {
255 $this->finalizeBgProcStatus($bgStatusFilename, "", $e);
260 public function getSharedParams($params, $context) {
261 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
263 $ds = new OMVModuleZFSDataset($params['name']);
264 $mountpoint = $ds->getMountPoint();
266 "mountpoint" => $mountpoint,
267 "name" => $params['name'],
268 "type" => $params['type']);
271 public function createShare($params, $context) {
273 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
275 //Get the UUID of the Pool
276 $poolname = OMVModuleZFSUtil::getPoolname($params['name']);
277 $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname);
279 //Get the mntent object and fetch it's uuid.
280 $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "']";
281 $mountpoint = $xmlConfig->get($xpath);
282 $mntentref = $mountpoint['uuid'];
284 // Prepare the configuration object. Use the name of the shared
285 // folder as the relative directory name of the share.
286 switch ($params['type']) {
288 $tmp = new OMVModuleZFSDataset($params['name']);
291 $tmp = new OMVModuleZFSDataset($params['name']);
294 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
298 $uuid = OMVUtil::uuid();
299 $pathName = $tmp->getMountPoint();
300 $reldirpath = OMVModuleZFSUtil::getReldirpath($pathName);
303 "name" => $params['sharename'],
304 "comment" => $params['comment'],
305 "mntentref" => $mntentref,
306 "reldirpath" => $reldirpath
309 // Set the configuration object.
311 // Check uniqueness. The share name must be global unique because
312 // the name is also used when exporting a shared folder via NFS for
314 $xpath = sprintf("//system/shares/sharedfolder[name='%s']",
316 if(TRUE === $xmlConfig->exists($xpath)) {
317 throw new OMVException(OMVErrorMsg::E_CONFIG_OBJECT_UNIQUENESS,
318 gettext("A shared folder with the given name already exists"));
321 // Add empty list of privileges per default.
322 $object['privileges'] = array();
324 // Append object to configuration.
325 $success = $xmlConfig->set("//system/shares",
326 array("sharedfolder" => $object));
327 if(FALSE === $success) {
328 throw new OMVException(OMVErrorMsg::E_CONFIG_SET_OBJECT_FAILED);
331 // Append the file mode field to the notification object if set.
333 $object['mode'] = "775";
334 if(array_key_exists("mode", $params)) {
335 $object['mode'] = $params['mode'];
338 // Change group owner of directory to configured default group,
340 if(FALSE === chgrp($pathName, $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'])) {
341 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
342 sprintf("Failed to set file group to '%s' for '%s'",
343 $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'], $pathName));
346 // Set the setgid bit. Setting this permission means that all files
347 // created in the folder will inherit the group of the folder rather
348 // than the primary group of the user who creates the file.
349 $mode = fileperms($pathName) | 02000;
350 if(FALSE === chmod($pathName, $mode)) {
351 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
352 sprintf("Failed to set file mode to '%o' for '%s'",
356 // Notify configuration changes.
357 $dispatcher = &OMVNotifyDispatcher::getInstance();
358 $dispatcher->notify(OMV_NOTIFY_CREATE,"org.openmediavault.system.shares.sharedfolder", $object);
359 // Return the configuration object.
365 // Register the RPC service.
366 $rpcServiceMgr = &OMVRpcServiceMgr::getInstance(); // Get the "root" instance for the Services
367 $rpcServiceMgr->registerService(new OMVRpcServiceZFS()); // Register a new instance of the RPC service described above