From cc1caa78f4dc963669b7a9cc5529b04cbe957d88 Mon Sep 17 00:00:00 2001 From: Niclas Berglind Date: Tue, 30 Sep 2014 20:48:52 +0200 Subject: [PATCH] Another attempt to integrate with OMV shared folders. Signed-off-by: Niclas Berglind --- .../omv/module/admin/storage/zfs/Overview.js | 14 ++-- gui/rpc/zfs.inc | 69 +++++++++++----- src/Utils.php | 78 ++++++++++++------- 3 files changed, 108 insertions(+), 53 deletions(-) diff --git a/gui/js/omv/module/admin/storage/zfs/Overview.js b/gui/js/omv/module/admin/storage/zfs/Overview.js index 3230435..2a3fe15 100644 --- a/gui/js/omv/module/admin/storage/zfs/Overview.js +++ b/gui/js/omv/module/admin/storage/zfs/Overview.js @@ -181,7 +181,10 @@ Ext.define("OMV.module.admin.storage.zfs.AddPool", { name: "force", fieldLabel: _("Force creation"), checked: false, - boxLabel: _("Forces the creation of the pool even if errors are reported. Use with extreme caution!") + plugins: [{ + ptype: "fieldinfo", + text: _("Forces the creation of the pool even if errors are reported. Use with extreme caution!") + }] }]; }, @@ -305,10 +308,7 @@ Ext.define("OMV.module.admin.storage.zfs.EditProperties", { e.record.set("modified", "true"); }, beforeedit: function(editor, e, eOpts) { - if (e.record.get("property") === "mountpoint") { - e.grid.getPlugin('rowEditing').editor.form.findField("value").disable(); - e.grid.getPlugin('rowEditing').editor.form.findField("property").disable(); - } else if (e.record.get("newproperty") === "false") { + if (e.record.get("newproperty") === "false") { e.grid.getPlugin('rowEditing').editor.form.findField("value").enable(); e.grid.getPlugin('rowEditing').editor.form.findField("property").disable(); } else { @@ -495,8 +495,8 @@ Ext.define("OMV.module.admin.storage.zfs.CreateShare", { xtype: "textfield", name: "mountpoint", fieldLabel: _("Path"), - allowBlank: false, - readOnly: true + allowBlank: true, + readOnly: false },{ xtype: "combo", name: "mode", diff --git a/gui/rpc/zfs.inc b/gui/rpc/zfs.inc index 7a6b364..f52f5db 100644 --- a/gui/rpc/zfs.inc +++ b/gui/rpc/zfs.inc @@ -190,8 +190,6 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and type='zfs']"; $object = $xmlConfig->get($xpath); $xmlConfig->delete($xpath); - $dispatcher = &OMVNotifyDispatcher::getInstance(); - $dispatcher->notify(OMV_NOTIFY_DELETE,"org.openmediavault.system.fstab.mntent", $object); OMVModuleZFSUtil::clearZFSLabel($disks); break; default: @@ -262,7 +260,7 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { "value":{"type":"string"}}}} } }'); - $objects = array(); + global $xmlConfig; switch ($params['type']) { case "Filesystem": case "Clone": @@ -282,9 +280,14 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { break; } foreach ($params['properties'] as $property) { + unset($objects); + $objects = array(); $objects[$property['property']] = $property['value']; + $tmp->setProperties($objects); + if ((strcmp($property['property'], "mountpoint") === 0) && (strcmp($params['type'], "Filesystem") === 0)) { + OMVModuleZFSUtil::relocateFilesystem($params['name']); + } } - $tmp->setProperties($objects); } public function inherit($params, $context) { @@ -348,10 +351,10 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { } }'); $objects = array(); - $ds = new OMVModuleZFSDataset($params['name']); - $mountpoint = $ds->getMountPoint(); + //$ds = new OMVModuleZFSDataset($params['name']); + //$mountpoint = $ds->getMountPoint(); return array( - "mountpoint" => $mountpoint, + //"mountpoint" => $mountpoint, "name" => $params['name'], "type" => $params['type']); } @@ -372,16 +375,15 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { "mountpoint":{"type":"string"} } }'); - - //Get the UUID of the Pool - $poolname = OMVModuleZFSUtil::getPoolname($params['name']); - $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); - - //Get the mntent object and fetch it's uuid. - $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "']"; - $mountpoint = $xmlConfig->get($xpath); - $mntentref = $mountpoint['uuid']; - + + // The field 'reldirpath' may not contain the characters '..'. This + // is because of security reasons: the given canonicalized absolute + // path MUST be below the given mount point. + if(1 == preg_match("/\.\./", $params['mountpoint'])) { + throw new OMVException(OMVErrorMsg::E_RPC_SERVICE_METHOD_INVALID_PARAMS, + sprintf(gettext("The field '%s' contains forbidden two-dot symbols"), "mountpoint")); + } + // Prepare the configuration object. Use the name of the shared // folder as the relative directory name of the share. switch ($params['type']) { @@ -396,13 +398,22 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { break; } + $poolname = OMVModuleZFSUtil::getPoolname($params['name']); + $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); + $dir = $tmp->getMountPoint(); + + //Get the mntent object and fetch it's uuid. + $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and dir='" . $dir . "' and type='zfs']"; + $mountpoint = $xmlConfig->get($xpath); + $mntentref = $mountpoint['uuid']; + $uuid = OMVUtil::uuid(); - $pathName = $tmp->getMountPoint(); - $reldirpath = OMVModuleZFSUtil::getReldirpath($pathName); + $pathName = $dir . "/" . trim($params['mountpoint'], "/"); + $reldirpath = trim($params['mountpoint'], "/"); $object = array( "uuid" => $uuid, "name" => $params['sharename'], - "comment" => $params['comment'], + "comment" => $params['comment'] . "*** ZFS share on " . $params['name'] . " ***", "mntentref" => $mntentref, "reldirpath" => $reldirpath ); @@ -436,6 +447,24 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $object['mode'] = $params['mode']; } + // Create the shared folder directory if necessary. + if(FALSE === file_exists($pathName)) { + // Create the directory. Note, the function seems to have a bug + // when using the mask parameter. E.g. octdec("777") does not + // create the correct permissions as expected, thus change the + // mode using chmod. + if(FALSE === mkdir($pathName, 0700, TRUE)) { + throw new OMVException(OMVErrorMsg::E_MISC_FAILURE, + sprintf("Failed to create the directory '%s'", $pathName)); + } + // Change the directory mode. + if(FALSE === chmod($pathName, octdec($object['mode']))) { + throw new OMVException(OMVErrorMsg::E_MISC_FAILURE, + sprintf("Failed to set file mode to '%s' for '%s'", + $object['mode'], $pathName)); + } + } + // Change group owner of directory to configured default group, // e.g. 'users'. if(FALSE === chgrp($pathName, $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'])) { diff --git a/src/Utils.php b/src/Utils.php index 1f1e8eb..0f67e36 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -11,6 +11,24 @@ require_once("Zpool.php"); */ class OMVModuleZFSUtil { + /** + * Manages relocation of ZFS filesystem mountpoints in the OMV backend. + * Needed when the user changes mountpoint of a filesystem in the GUI. + * + */ + public static function relocateFilesystem($name) { + global $xmlConfig; + $poolname = OMVModuleZFSUtil::getPoolname($name); + $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); + $ds = new OMVModuleZFSDataset($name); + $dir = $ds->getMountPoint(); + $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and dir='" . $dir . "' and type='zfs']"; + $object = $xmlConfig->get($xpath); + $object['dir'] = $property['value']; + $xmlConfig->replace($xpath, $object); + return null; + } + /** * Clears all ZFS labels on specified devices. * Needed for blkid to display proper data. @@ -21,6 +39,7 @@ class OMVModuleZFSUtil { $cmd = "zpool labelclear /dev/" . $disk . "1"; OMVModuleZFSUtil::exec($cmd,$out,$res); } + return null; } /** @@ -58,15 +77,22 @@ class OMVModuleZFSUtil { */ public static function deleteShares($name) { global $xmlConfig; - $tmp = new OMVModuleZFSDataset($name); - $reldirpath = OMVModuleZFSUtil::getReldirpath($tmp->getMountPoint()); $poolname = OMVModuleZFSUtil::getPoolname($name); $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); - $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "']"; + $ds = new OMVModuleZFSDataset($name); + $dir = $ds->getMountPoint(); + $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and dir='" . $dir . "' and type='zfs']"; $mountpoint = $xmlConfig->get($xpath); $mntentuuid = $mountpoint['uuid']; - $xpath = "//system/shares/sharedfolder[mntentref='" . $mntentuuid . "' and reldirpath='" . $reldirpath . "']"; - $object = $xmlConfig->get($xpath); + $xpath = "//system/shares/sharedfolder[mntentref='" . $mntentuuid . "']"; + $objects = $xmlConfig->getList($xpath); + foreach ($objects as $object) { + $tmpxpath = sprintf("//*[contains(name(),'sharedfolderref')]". + "[contains(.,'%s')]", $object['uuid']); + if ($xmlConfig->exists($tmpxpath)) { + throw new OMVModuleZFSException("The Filesystem is shared and in use. Please delete all references and try again."); + } + } $xmlConfig->delete($xpath); $dispatcher = &OMVNotifyDispatcher::getInstance(); $dispatcher->notify(OMV_NOTIFY_DELETE,"org.openmediavault.system.shares.sharedfolder",$object); @@ -136,33 +162,33 @@ class OMVModuleZFSUtil { } /** - * Add any missing ZFS pool to the OMV backend + * Add any missing ZFS filesystems to the OMV backend * */ public static function addMissingOMVMntEnt() { global $xmlConfig; - $cmd = "zpool list -H -o name"; + $cmd = "zfs list -H -o name -t filesystem"; OMVModuleZFSUtil::exec($cmd, $out, $res); foreach($out as $name) { - $pooluuid = OMVModuleZFSUtil::getUUIDbyName($name); - $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "']"; - $mountpoint = $xmlConfig->get($xpath); - if (is_null($mountpoint)) { - $uuid = OMVUtil::uuid(); - $pool = new OMVModuleZFSZpool($name); - $dir = $pool->getMountPoint(); - $object = array( - "uuid" => $uuid, - "fsname" => $pooluuid, - "dir" => $dir, - "type" => "zfs", - "opts" => "rw,relatime,xattr,noacl", - "freq" => "0", - "passno" => "0" - ); - $xmlConfig->set("//system/fstab",array("mntent" => $object)); - $dispatcher = &OMVNotifyDispatcher::getInstance(); - $dispatcher->notify(OMV_NOTIFY_CREATE,"org.openmediavault.system.fstab.mntent", $object); + if (preg_match('/[\/]+/', $name)) { + $poolname = OMVModuleZFSUtil::getPoolname($name); + $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); + $ds = new OMVModuleZFSDataset($name); + $dir = $ds->getMountPoint(); + $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and dir='" . $dir . "' and type='zfs']"; + if (!($xmlConfig->exists($xpath))) { + $uuid = OMVUtil::uuid(); + $object = array( + "uuid" => $uuid, + "fsname" => $pooluuid, + "dir" => $dir, + "type" => "zfs", + "opts" => "rw,relatime,xattr,noacl", + "freq" => "0", + "passno" => "0" + ); + $xmlConfig->set("//system/fstab",array("mntent" => $object)); + } } } return null; -- 2.39.2