1abbee
From 72b3ff75e786efa2c9b2fdfb50e46597434c5420 Mon Sep 17 00:00:00 2001
1abbee
From: Lukas Nykryn <lnykryn@redhat.com>
1abbee
Date: Wed, 20 Jan 2016 15:16:32 +0100
1abbee
Subject: [PATCH] sysv-generator: do not join dependencies on one line, split
1abbee
 them
1abbee
1abbee
If there is a lot of initscripts and dependencies between them we might
1abbee
end generating After= (and similar) lines which are longer then LINE_MAX
1abbee
and thus rejected by parser in systemd.
1abbee
1abbee
Fixes #2099
1abbee
1abbee
Cherry-picked from: c584ffc0b75d4b9e9229bf1d8edb7d89562be3c1
1abbee
Resolves: #1288600
1abbee
---
23b3cf
 src/sysv-generator/sysv-generator.c | 44 ++++++++---------------------
23b3cf
 test/sysv-generator-test.py         | 18 ++++++++++--
1abbee
 2 files changed, 28 insertions(+), 34 deletions(-)
1abbee
1abbee
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
c62b8e
index 0a8a528bdc..d60e75a06b 100644
1abbee
--- a/src/sysv-generator/sysv-generator.c
1abbee
+++ b/src/sysv-generator/sysv-generator.c
1abbee
@@ -134,34 +134,14 @@ static int add_alias(const char *service, const char *alias) {
1abbee
 }
1abbee
 
1abbee
 static int generate_unit_file(SysvStub *s) {
1abbee
-        char **p;
1abbee
         _cleanup_fclose_ FILE *f = NULL;
1abbee
-        _cleanup_free_ char *unit = NULL;
1abbee
-        _cleanup_free_ char *before = NULL;
1abbee
-        _cleanup_free_ char *after = NULL;
1abbee
-        _cleanup_free_ char *wants = NULL;
1abbee
-        _cleanup_free_ char *conflicts = NULL;
1abbee
+        const char *unit;
1abbee
+        char **p;
1abbee
         int r;
1abbee
 
1abbee
-        before = strv_join(s->before, " ");
1abbee
-        if (!before)
1abbee
-                return log_oom();
1abbee
-
1abbee
-        after = strv_join(s->after, " ");
1abbee
-        if (!after)
1abbee
-                return log_oom();
1abbee
-
1abbee
-        wants = strv_join(s->wants, " ");
1abbee
-        if (!wants)
1abbee
-                return log_oom();
1abbee
-
1abbee
-        conflicts = strv_join(s->conflicts, " ");
1abbee
-        if (!conflicts)
1abbee
-                return log_oom();
1abbee
+        assert(s);
1abbee
 
1abbee
-        unit = strjoin(arg_dest, "/", s->name, NULL);
1abbee
-        if (!unit)
1abbee
-                return log_oom();
1abbee
+        unit = strjoina(arg_dest, "/", s->name);
1abbee
 
1abbee
         /* We might already have a symlink with the same name from a Provides:,
1abbee
          * or from backup files like /etc/init.d/foo.bak. Real scripts always win,
1abbee
@@ -183,14 +163,14 @@ static int generate_unit_file(SysvStub *s) {
1abbee
                 "Description=%s\n",
1abbee
                 s->path, s->description);
1abbee
 
1abbee
-        if (!isempty(before))
1abbee
-                fprintf(f, "Before=%s\n", before);
1abbee
-        if (!isempty(after))
1abbee
-                fprintf(f, "After=%s\n", after);
1abbee
-        if (!isempty(wants))
1abbee
-                fprintf(f, "Wants=%s\n", wants);
1abbee
-        if (!isempty(conflicts))
1abbee
-                fprintf(f, "Conflicts=%s\n", conflicts);
1abbee
+        STRV_FOREACH(p, s->before)
1abbee
+                fprintf(f, "Before=%s\n", *p);
1abbee
+        STRV_FOREACH(p, s->after)
1abbee
+                fprintf(f, "After=%s\n", *p);
1abbee
+        STRV_FOREACH(p, s->wants)
1abbee
+                fprintf(f, "Wants=%s\n", *p);
1abbee
+        STRV_FOREACH(p, s->conflicts)
1abbee
+                fprintf(f, "Conflicts=%s\n", *p);
1abbee
 
1abbee
         fprintf(f,
1abbee
                 "\n[Service]\n"
1abbee
diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
c62b8e
index 2060ad754e..25a35da47f 100644
1abbee
--- a/test/sysv-generator-test.py
1abbee
+++ b/test/sysv-generator-test.py
1abbee
@@ -23,6 +23,7 @@ import subprocess
1abbee
 import tempfile
1abbee
 import shutil
1abbee
 from glob import glob
1abbee
+import collections
1abbee
 
1abbee
 try:
1abbee
     from configparser import RawConfigParser
1abbee
@@ -32,6 +33,12 @@ except ImportError:
1abbee
 
1abbee
 sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator')
1abbee
 
1abbee
+class MultiDict(collections.OrderedDict):
1abbee
+    def __setitem__(self, key, value):
1abbee
+        if isinstance(value, list) and key in self:
1abbee
+            self[key].extend(value)
1abbee
+        else:
1abbee
+            super(MultiDict, self).__setitem__(key, value)
1abbee
 
1abbee
 class SysvGeneratorTest(unittest.TestCase):
1abbee
     def setUp(self):
1abbee
@@ -77,7 +84,14 @@ class SysvGeneratorTest(unittest.TestCase):
1abbee
         for service in glob(self.out_dir + '/*.service'):
1abbee
             if os.path.islink(service):
1abbee
                 continue
1abbee
-            cp = RawConfigParser()
1abbee
+            try:
1abbee
+                # for python3 we need here strict=False to parse multiple
1abbee
+                # lines with the same key
1abbee
+                cp = RawConfigParser(dict_type=MultiDict, strict=False)
1abbee
+            except TypeError:
1abbee
+                # RawConfigParser in python2 does not have the strict option
1abbee
+                # but it allows multiple lines with the same key by default
1abbee
+                cp = RawConfigParser(dict_type=MultiDict)
1abbee
             cp.optionxform = lambda o: o  # don't lower-case option names
1abbee
             with open(service) as f:
1abbee
                 cp.readfp(f)
1abbee
@@ -215,7 +229,7 @@ class SysvGeneratorTest(unittest.TestCase):
1abbee
         s = self.run_generator()[1]['foo.service']
1abbee
         self.assertEqual(set(s.options('Unit')),
1abbee
                          set(['Documentation', 'SourcePath', 'Description', 'After']))
1abbee
-        self.assertEqual(s.get('Unit', 'After'), 'nss-lookup.target rpcbind.target')
1abbee
+        self.assertEqual(s.get('Unit', 'After').split(), ['nss-lookup.target', 'rpcbind.target'])
1abbee
 
1abbee
     def test_lsb_deps(self):
1abbee
         '''LSB header dependencies to other services'''