From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> 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@xxxxxxxxxx> --- src/libvirt_private.syms | 2 ++ src/util/virsystemd.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++-- src/util/virsystemd.h | 5 +++ tests/virsystemdtest.c | 48 +++++++++++++++++++++++++ 4 files changed, 144 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..784c45c 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,22 @@ 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.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list