common/FileUtil.cpp       |   48 +++++++++++---------------
 common/JailUtil.cpp       |   84 ++++++++++++++++++++++------------------------
 common/JailUtil.hpp       |    3 +
 kit/Kit.cpp               |   15 ++++++--
 loolwsd-systemplate-setup |   11 ++++--
 5 files changed, 83 insertions(+), 78 deletions(-)

New commits:
commit bc8da0cb339cc685f9a24c78e8a92aadcd690479
Author:     Ashod Nakashian <ashod.nakash...@collabora.co.uk>
AuthorDate: Sun Aug 16 22:46:33 2020 -0400
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Mon Aug 17 13:51:56 2020 +0200

    wsd: support read-only systemplate
    
    For various reasons, systemplate may be read-only
    or under a different owner and therefore impossible
    to update the dynamic files in it.
    
    To support such a scenario, we first link the
    eight dynamic files in /etc when creating systemplate.
    If this fails, we copy the files.
    
    When creating jails, we always check that all the
    dynamic files are up-to-date. If they are, nothing
    further is necessary and we bind-mount, if enabled
    and possible.
    
    However, if the dynamic files are not up-to-date,
    we disable bind-mounting and force linking
    the files in the jails. Failing that, we copy them,
    which is not ideal, but allows us to ensure the
    dynamic files are up-to-date as we copy them too.
    
    Ideally, the dynamic files in question would be
    hard-link (or at least soft-linked) in systemplate
    at creation. From then on we would bind-mount
    the jails and everything would work perfectly and
    no files would need updating. This patch is fallback
    for when this scheme fails, which should be exceedingly
    rare anyway, but which still ensures correct operation.
    
    Change-Id: I09c6f057c49396579aaddb1b8bf4af0930dd4247
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/100834
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Tested-by: Jenkins
    Reviewed-by: Andras Timar <andras.ti...@collabora.com>

diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp
index 6a61b926e..7f8e767d7 100644
--- a/common/FileUtil.cpp
+++ b/common/FileUtil.cpp
@@ -12,7 +12,9 @@
 #include "FileUtil.hpp"
 
 #include <dirent.h>
+#include <exception>
 #include <ftw.h>
+#include <stdexcept>
 #include <sys/time.h>
 #ifdef __linux
 #include <sys/vfs.h>
@@ -89,27 +91,19 @@ namespace FileUtil
     bool copy(const std::string& fromPath, const std::string& toPath, bool 
log, bool throw_on_error)
     {
         int from = -1, to = -1;
-        try {
+        try
+        {
             from = open(fromPath.c_str(), O_RDONLY);
             if (from < 0)
-            {
-                LOG_SYS("Failed to open src " << anonymizeUrl(fromPath));
-                throw;
-            }
+                throw std::runtime_error("Failed to open src " + 
anonymizeUrl(fromPath));
 
             struct stat st;
             if (fstat(from, &st) != 0)
-            {
-                LOG_SYS("Failed to fstat src " << anonymizeUrl(fromPath));
-                throw;
-            }
+                throw std::runtime_error("Failed to fstat src " + 
anonymizeUrl(fromPath));
 
             to = open(toPath.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 
st.st_mode);
             if (to < 0)
-            {
-                LOG_SYS("Failed to fstat dest " << anonymizeUrl(toPath));
-                throw;
-            }
+                throw std::runtime_error("Failed to open dest " + 
anonymizeUrl(toPath));
 
             // Logging may be redundant and/or noisy.
             if (log)
@@ -120,14 +114,14 @@ namespace FileUtil
 
             int n;
             off_t bytesIn = 0;
-            do {
+            do
+            {
                 while ((n = ::read(from, buffer, sizeof(buffer))) < 0 && errno 
== EINTR)
                     LOG_TRC("EINTR reading from " << anonymizeUrl(fromPath));
                 if (n < 0)
-                {
-                    LOG_SYS("Failed to read from " << anonymizeUrl(fromPath) 
<< " at " << bytesIn << " bytes in");
-                    throw;
-                }
+                    throw std::runtime_error("Failed to read from " + 
anonymizeUrl(fromPath)
+                                             + " at " + 
std::to_string(bytesIn) + " bytes in");
+
                 bytesIn += n;
                 if (n == 0) // EOF
                     break;
@@ -140,13 +134,14 @@ namespace FileUtil
                         LOG_TRC("EINTR writing to " << anonymizeUrl(toPath));
                     if (written < 0)
                     {
-                        LOG_SYS("Failed to write " << n << " bytes to " << 
anonymizeUrl(toPath) << " at " <<
-                                bytesIn << " bytes into " << 
anonymizeUrl(fromPath));
-                        throw;
+                        throw std::runtime_error("Failed to write " + 
std::to_string(n)
+                                                 + " bytes to " + 
anonymizeUrl(toPath) + " at "
+                                                 + std::to_string(bytesIn) + " 
bytes into "
+                                                 + anonymizeUrl(fromPath));
                     }
                     j += written;
                 }
-            } while(true);
+            } while (true);
             if (bytesIn != st.st_size)
             {
                 LOG_WRN("Unusual: file " << anonymizeUrl(fromPath) << " 
changed size "
@@ -156,19 +151,18 @@ namespace FileUtil
             close(to);
             return true;
         }
-        catch (...)
+        catch (const std::exception& ex)
         {
             std::ostringstream oss;
-            oss << "Failed to copy from " << anonymizeUrl(fromPath) << " to "
-                << anonymizeUrl(toPath);
+            oss << "Error while copying from " << anonymizeUrl(fromPath) << " 
to "
+                << anonymizeUrl(toPath) << ": " << ex.what();
             const std::string err = oss.str();
-
             LOG_SYS(err);
             close(from);
             close(to);
             unlink(toPath.c_str());
             if (throw_on_error)
-                throw Poco::Exception(err);
+                throw std::runtime_error(err);
         }
 
         return false;
diff --git a/common/JailUtil.cpp b/common/JailUtil.cpp
index bc0138c0f..c7ce612df 100644
--- a/common/JailUtil.cpp
+++ b/common/JailUtil.cpp
@@ -247,17 +247,38 @@ namespace SysTemplate
 /// that systemplate will get re-generated after installation.
 static const auto DynamicFilePaths
     = { "/etc/passwd",        "/etc/group",       "/etc/host.conf", 
"/etc/hosts",
-        "/etc/nsswitch.conf", "/etc/resolv.conf", "etc/timezone",   
"etc/localtime" };
+        "/etc/nsswitch.conf", "/etc/resolv.conf", "/etc/timezone",  
"/etc/localtime" };
 
 /// Copy (false) by default for KIT_IN_PROCESS.
 static bool LinkDynamicFiles = false;
 
+static bool updateDynamicFilesImpl(const std::string& sysTemplate);
+
 void setupDynamicFiles(const std::string& sysTemplate)
 {
     LOG_INF("Setting up systemplate dynamic files in [" << sysTemplate << 
"].");
 
     const std::string etcSysTemplatePath = Poco::Path(sysTemplate, 
"etc").toString();
     LinkDynamicFiles = true; // Prefer linking, unless it fails.
+
+    if (!updateDynamicFilesImpl(sysTemplate))
+    {
+        // Can't copy!
+        LOG_WRN("Failed to update the dynamic files in ["
+                << sysTemplate
+                << "]. Will disable bind-mounting in this run and clone 
systemplate into the "
+                   "jails, which is more resource intensive.");
+        unsetenv("LOOL_BIND_MOUNT"); // We can't mount from incomplete 
systemplate.
+    }
+
+    if (LinkDynamicFiles)
+        LOG_INF("Systemplate dynamic files in ["
+                << sysTemplate << "] are linked and will remain up-to-date.");
+}
+
+bool updateDynamicFilesImpl(const std::string& sysTemplate)
+{
+    LOG_INF("Updating systemplate dynamic files in [" << sysTemplate << "].");
     for (const auto& srcFilename : DynamicFilePaths)
     {
         const Poco::File srcFilePath(srcFilename);
@@ -275,6 +296,7 @@ void setupDynamicFiles(const std::string& sysTemplate)
             continue;
         }
 
+        LOG_INF("File [" << dstFilename << "] needs to be updated.");
         if (LinkDynamicFiles)
         {
             LOG_INF("Linking [" << srcFilename << "] -> [" << dstFilename << 
"].");
@@ -290,8 +312,12 @@ void setupDynamicFiles(const std::string& sysTemplate)
             const int linkerr = errno;
 
             // With parallel tests, another test might have linked already.
-            if (Poco::File(dstFilename).exists()) // stat again.
+            FileUtil::Stat dstStat2(dstFilename);
+            if (dstStat2.isUpToDate(srcStat))
+            {
+                LOG_INF("File [" << dstFilename << "] now seems to be 
up-to-date.");
                 continue;
+            }
 
             // Failed to link a file. Disable linking and copy instead.
             LOG_WRN("Failed to link ["
@@ -301,55 +327,27 @@ void setupDynamicFiles(const std::string& sysTemplate)
         }
 
         // Linking failed, just copy.
-        LOG_INF("Copying [" << srcFilename << "] -> [" << dstFilename << "].");
-        if (!FileUtil::copyAtomic(srcFilename, dstFilename, true))
+        if (!LinkDynamicFiles)
         {
-            if (!Poco::File(dstFilename).exists()) // stat again.
-                LOG_ERR("Failed to copy [" << srcFilename << "] -> [" << 
dstFilename
-                                           << "], some functionality may be 
missing.");
+            LOG_INF("Copying [" << srcFilename << "] -> [" << dstFilename << 
"].");
+            if (!FileUtil::copyAtomic(srcFilename, dstFilename, true))
+            {
+                FileUtil::Stat dstStat2(dstFilename); // Stat again.
+                if (!dstStat2.isUpToDate(srcStat))
+                {
+                    return false; // No point in trying the remaining files.
+                }
+            }
         }
     }
 
-    if (LinkDynamicFiles)
-        LOG_INF("Successfully linked the systemplate dynamic files in ["
-                << sysTemplate << "] and will not need to update them again.");
+    return true;
 }
 
-void updateDynamicFiles(const std::string& sysTemplate)
+bool updateDynamicFiles(const std::string& sysTemplate)
 {
     // If the files are linked, they are always up-to-date.
-    if (!LinkDynamicFiles)
-    {
-        LOG_INF("Updating systemplate dynamic files in [" << sysTemplate << 
"].");
-
-        const std::string etcSysTemplatePath = Poco::Path(sysTemplate, 
"etc").toString();
-        for (const auto& srcFilename : DynamicFilePaths)
-        {
-            const Poco::File srcFilePath(srcFilename);
-            FileUtil::Stat srcStat(srcFilename);
-            if (!srcStat.exists())
-                continue;
-
-            const std::string dstFilename = Poco::Path(sysTemplate, 
srcFilename).toString();
-            FileUtil::Stat dstStat(dstFilename);
-
-            // Is it outdated?
-            if (dstStat.isUpToDate(srcStat))
-            {
-                LOG_INF("File [" << dstFilename << "] is already up-to-date.");
-            }
-            else
-            {
-                LOG_INF("Copying [" << srcFilename << "] -> [" << dstFilename 
<< "].");
-                if (!FileUtil::copyAtomic(srcFilename, dstFilename, true))
-                {
-                    if (!Poco::File(dstFilename).exists()) // stat again.
-                        LOG_ERR("Failed to copy [" << srcFilename << "] -> [" 
<< dstFilename
-                                                   << "], some functionality 
may be missing.");
-                }
-            }
-        }
-    }
+    return LinkDynamicFiles ? true : updateDynamicFilesImpl(sysTemplate);
 }
 
 void setupLoSymlink(const std::string& sysTemplate, const std::string& 
loTemplate,
diff --git a/common/JailUtil.hpp b/common/JailUtil.hpp
index d783b53d3..949fdca50 100644
--- a/common/JailUtil.hpp
+++ b/common/JailUtil.hpp
@@ -61,7 +61,8 @@ void setupRandomDeviceLinks(const std::string& root);
 void setupDynamicFiles(const std::string& sysTemplate);
 
 /// Update the dynamic files within the sysTemplate before each child fork.
-void updateDynamicFiles(const std::string& sysTemplate);
+/// Returns false on failure.
+bool updateDynamicFiles(const std::string& sysTemplate);
 
 } // namespace SysTemplate
 
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 8819947fd..2a312b986 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2135,10 +2135,10 @@ void lokit_main(
             if (std::getenv("LOOL_BIND_MOUNT"))
             {
                 const std::string destPath = jailPath.toString();
-                LOG_DBG("Mounting " << sysTemplate << " -> " << destPath);
+                LOG_INF("Mounting " << sysTemplate << " -> " << destPath);
                 if (!JailUtil::bind(sysTemplate, destPath))
                 {
-                    LOG_INF("Failed to mount [" << sysTemplate << "] -> [" << 
destPath
+                    LOG_WRN("Failed to mount [" << sysTemplate << "] -> [" << 
destPath
                                                 << "], will link/copy 
contents.");
                     linkOrCopy(sysTemplate, destPath, LinkOrCopyType::All);
                 }
@@ -2147,11 +2147,11 @@ void lokit_main(
 
                 // Mount lotemplate inside it.
                 const std::string loDestPath = Poco::Path(jailPath, 
"lo").toString();
-                LOG_DBG("Mounting " << loTemplate << " -> " << loDestPath);
+                LOG_INF("Mounting " << loTemplate << " -> " << loDestPath);
                 Poco::File(loDestPath).createDirectories();
                 if (!JailUtil::bind(loTemplate, loDestPath))
                 {
-                    LOG_INF("Failed to mount [" << loTemplate << "] -> [" << 
loDestPath
+                    LOG_WRN("Failed to mount [" << loTemplate << "] -> [" << 
loDestPath
                                                 << "], will link/copy 
contents.");
                     linkOrCopy(sysTemplate, loDestPath, LinkOrCopyType::LO);
                 }
@@ -2180,6 +2180,13 @@ void lokit_main(
                 linkOrCopy(loTemplate, jailLOInstallation, LinkOrCopyType::LO);
 
                 JailUtil::setupJailDevNodes(Poco::Path(jailPath, 
"/tmp").toString());
+
+                // Update the dynamic files inside the jail.
+                if 
(!JailUtil::SysTemplate::updateDynamicFiles(jailPath.toString()))
+                {
+                    LOG_WRN("Failed to update the dynamic files in the jail ["
+                            << jailPath.toString() << "]. Some functionality 
may be missing.");
+                }
             }
 
             ::setenv("TMPDIR", "/tmp", 1);
diff --git a/loolwsd-systemplate-setup b/loolwsd-systemplate-setup
index 2f6e462e0..b50d10cc3 100755
--- a/loolwsd-systemplate-setup
+++ b/loolwsd-systemplate-setup
@@ -58,13 +58,18 @@ grep -v dynamic | cut -d " " -f 3 | grep -E '^(/lib|/usr)' 
| sort -u | sed -e 's
 # This will now copy the file a symlink points to, but whatever.
 cpio -p -d -L $CHROOT
 
-# Remove the dynamic files, which are linked by loolwsd.
-rm -f 
$CHROOT/etc/{hosts,nsswitch.conf,resolv.conf,passwd,group,host.conf,timezone,localtime}
-
 mkdir -p $CHROOT/lo
 mkdir -p $CHROOT/dev
 mkdir -p $CHROOT/tmp/dev
 
+# Link the dynamic files, replacing any existing.
+for file in hosts nsswitch.conf resolv.conf passwd group host.conf timezone 
localtime
+do
+    #echo "Linking/Copying /etc/$file"
+    # Prefer hard linking, fallback to soft linking, and finally to just 
copying.
+    ln -f /etc/$file $CHROOT/etc/ 2> /dev/null || ln -f -s /etc/$file 
$CHROOT/etc/ || cp /etc/$file $CHROOT/etc/ || echo "Failed to link or copy 
$file"
+done
+
 # /usr/share/fonts needs to be taken care of separately because the
 # directory time stamps must be preserved for fontconfig to trust
 # its cache.
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to