Blob Blame History Raw
From 640ff93b2835c02f2f317912e7e2abb20cf3c35d Mon Sep 17 00:00:00 2001
Message-Id: <640ff93b2835c02f2f317912e7e2abb20cf3c35d.1375465853.git.jdenemar@redhat.com>
From: "Daniel P. Berrange" <berrange@redhat.com>
Date: Wed, 31 Jul 2013 19:48:17 +0100
Subject: [PATCH] Add APIs for formatting systemd slice/scope names

https://bugzilla.redhat.com/show_bug.cgi?id=980929

There are some interesting escaping rules to consider when dealing
with systemd slice/scope names. Thus it is helpful to have APIs
for formatting names

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

(cherry picked from commit 4574b475df830da437aa6384fd1452cecbb4b7d2)
---
 src/libvirt_private.syms |  2 ++
 src/util/virsystemd.c    | 91 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/util/virsystemd.h    |  5 +++
 tests/virsystemdtest.c   | 49 ++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d9615ea..0247a46 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1935,6 +1935,8 @@ virSysinfoSetup;
 
 # util/virsystemd.h
 virSystemdCreateMachine;
+virSystemdMakeScopeName;
+virSystemdMakeSliceName;
 
 
 # util/virthread.h
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c
index 11d1153..251b846 100644
--- a/src/util/virsystemd.c
+++ b/src/util/virsystemd.c
@@ -27,9 +27,96 @@
 #include "viralloc.h"
 #include "virutil.h"
 #include "virlog.h"
+#include "virerror.h"
 
 #define VIR_FROM_THIS VIR_FROM_SYSTEMD
 
+
+static void virSystemdEscapeName(virBufferPtr buf,
+                                 const char *name)
+{
+    static const char hextable[16] = "0123456789abcdef";
+
+#define ESCAPE(c)                                                       \
+    do {                                                                \
+        virBufferAddChar(buf, '\\');                                    \
+        virBufferAddChar(buf, 'x');                                     \
+        virBufferAddChar(buf, hextable[(c >> 4) & 15]);                 \
+        virBufferAddChar(buf, hextable[c & 15]);                        \
+    } while (0)
+
+#define VALID_CHARS                             \
+        "0123456789"                            \
+        "abcdefghijklmnopqrstuvwxyz"            \
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
+        ":-_.\\"
+
+    if (*name == '.') {
+        ESCAPE(*name);
+        name++;
+    }
+
+    while (*name) {
+        if (*name == '/')
+            virBufferAddChar(buf, '-');
+        else if (*name == '-' ||
+                 *name == '\\' ||
+                 !strchr(VALID_CHARS, *name))
+            ESCAPE(*name);
+        else
+            virBufferAddChar(buf, *name);
+        name++;
+    }
+
+#undef ESCAPE
+#undef VALID_CHARS
+}
+
+
+char *virSystemdMakeScopeName(const char *name,
+                              const char *drivername,
+                              const char *partition)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (*partition == '/')
+        partition++;
+
+    virSystemdEscapeName(&buf, partition);
+    virBufferAddChar(&buf, '-');
+    virSystemdEscapeName(&buf, drivername);
+    virBufferAddLit(&buf, "\\x2d");
+    virSystemdEscapeName(&buf, name);
+    virBufferAddLit(&buf, ".scope");
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+char *virSystemdMakeSliceName(const char *partition)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (*partition == '/')
+        partition++;
+
+    virSystemdEscapeName(&buf, partition);
+    virBufferAddLit(&buf, ".slice");
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
 /**
  * virSystemdCreateMachine:
  * @name: driver unique name of the machine
@@ -75,8 +162,8 @@ int virSystemdCreateMachine(const char *name,
         goto cleanup;
 
     if (partition) {
-        if (virAsprintf(&slicename, "%s.slice", partition) < 0)
-            goto cleanup;
+        if (!(slicename = virSystemdMakeSliceName(partition)))
+             goto cleanup;
     } else {
         if (VIR_STRDUP(slicename, "") < 0)
             goto cleanup;
diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h
index 9ca4e0b..414ae5a 100644
--- a/src/util/virsystemd.h
+++ b/src/util/virsystemd.h
@@ -24,6 +24,11 @@
 
 # include "internal.h"
 
+char *virSystemdMakeScopeName(const char *name,
+                              const char *drivername,
+                              const char *slicename);
+char *virSystemdMakeSliceName(const char *partition);
+
 int virSystemdCreateMachine(const char *name,
                             const char *drivername,
                             bool privileged,
diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c
index bcf3ad3..a9c6d32 100644
--- a/tests/virsystemdtest.c
+++ b/tests/virsystemdtest.c
@@ -138,6 +138,38 @@ static int testCreateBadSystemd(const void *opaque ATTRIBUTE_UNUSED)
     return 0;
 }
 
+
+struct testScopeData {
+    const char *name;
+    const char *partition;
+    const char *expected;
+};
+
+static int
+testScopeName(const void *opaque)
+{
+    const struct testScopeData *data = opaque;
+    int ret = -1;
+    char *actual = NULL;
+
+    if (!(actual = virSystemdMakeScopeName(data->name,
+                                           "lxc",
+                                           data->partition)))
+        goto cleanup;
+
+    if (STRNEQ(actual, data->expected)) {
+        fprintf(stderr, "Expected '%s' but got '%s'\n",
+                data->expected, actual);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(actual);
+    return ret;
+}
+
 static int
 mymain(void)
 {
@@ -152,6 +184,23 @@ mymain(void)
     if (virtTestRun("Test create bad systemd ", 1, testCreateBadSystemd, NULL) < 0)
         ret = -1;
 
+#define TEST_SCOPE(name, partition, unitname)                           \
+    do {                                                                \
+        struct testScopeData data = {                                   \
+            name, partition, unitname                                   \
+        };                                                              \
+        if (virtTestRun("Test scopename", 1, testScopeName, &data) < 0) \
+            ret = -1;                                                   \
+    } while (0)
+
+    TEST_SCOPE("demo", "/machine", "machine-lxc\\x2ddemo.scope");
+    TEST_SCOPE("demo-name", "/machine", "machine-lxc\\x2ddemo\\x2dname.scope");
+    TEST_SCOPE("demo!name", "/machine", "machine-lxc\\x2ddemo\\x21name.scope");
+    TEST_SCOPE(".demo", "/machine", "machine-lxc\\x2d\\x2edemo.scope");
+    TEST_SCOPE("demo", "/machine/eng-dept", "machine-eng\\x2ddept-lxc\\x2ddemo.scope");
+    TEST_SCOPE("demo", "/machine/eng-dept/testing!stuff",
+               "machine-eng\\x2ddept-testing\\x21stuff-lxc\\x2ddemo.scope");
+
     return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-- 
1.8.3.2