sysv-generator: do not join dependencies on one line, split them

If there is a lot of initscripts and dependencies between them we might
end generating After= (and similar) lines which are longer then LINE_MAX
and thus rejected by parser in systemd.

Fixes #2099
This commit is contained in:
Lukas Nykryn 2016-01-20 15:16:32 +01:00
parent 91c4b6db78
commit c584ffc0b7
2 changed files with 24 additions and 19 deletions

View File

@ -161,7 +161,6 @@ static int add_alias(const char *service, const char *alias) {
}
static int generate_unit_file(SysvStub *s) {
_cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *unit;
char **p;
@ -174,14 +173,6 @@ static int generate_unit_file(SysvStub *s) {
unit = strjoina(arg_dest, "/", s->name);
before = strv_join(s->before, " ");
after = strv_join(s->after, " ");
wants = strv_join(s->wants, " ");
conflicts = strv_join(s->conflicts, " ");
if (!before || !after || !wants || !conflicts)
return log_oom();
/* We might already have a symlink with the same name from a Provides:,
* or from backup files like /etc/init.d/foo.bak. Real scripts always win,
* so remove an existing link */
@ -204,14 +195,14 @@ static int generate_unit_file(SysvStub *s) {
if (s->description)
fprintf(f, "Description=%s\n", s->description);
if (!isempty(before))
fprintf(f, "Before=%s\n", before);
if (!isempty(after))
fprintf(f, "After=%s\n", after);
if (!isempty(wants))
fprintf(f, "Wants=%s\n", wants);
if (!isempty(conflicts))
fprintf(f, "Conflicts=%s\n", conflicts);
STRV_FOREACH(p, s->before)
fprintf(f, "Before=%s\n", *p);
STRV_FOREACH(p, s->after)
fprintf(f, "After=%s\n", *p);
STRV_FOREACH(p, s->wants)
fprintf(f, "Wants=%s\n", *p);
STRV_FOREACH(p, s->conflicts)
fprintf(f, "Conflicts=%s\n", *p);
fprintf(f,
"\n[Service]\n"

View File

@ -23,6 +23,7 @@ import subprocess
import tempfile
import shutil
from glob import glob
import collections
try:
from configparser import RawConfigParser
@ -32,6 +33,12 @@ except ImportError:
sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator')
class MultiDict(collections.OrderedDict):
def __setitem__(self, key, value):
if isinstance(value, list) and key in self:
self[key].extend(value)
else:
super(MultiDict, self).__setitem__(key, value)
class SysvGeneratorTest(unittest.TestCase):
def setUp(self):
@ -77,7 +84,14 @@ class SysvGeneratorTest(unittest.TestCase):
for service in glob(self.out_dir + '/*.service'):
if os.path.islink(service):
continue
cp = RawConfigParser()
try:
# for python3 we need here strict=False to parse multiple
# lines with the same key
cp = RawConfigParser(dict_type=MultiDict, strict=False)
except TypeError:
# RawConfigParser in python2 does not have the strict option
# but it allows multiple lines with the same key by default
cp = RawConfigParser(dict_type=MultiDict)
cp.optionxform = lambda o: o # don't lower-case option names
with open(service) as f:
cp.readfp(f)
@ -224,7 +238,7 @@ class SysvGeneratorTest(unittest.TestCase):
s = self.run_generator()[1]['foo.service']
self.assertEqual(set(s.options('Unit')),
set(['Documentation', 'SourcePath', 'Description', 'After']))
self.assertEqual(s.get('Unit', 'After'), 'nss-lookup.target rpcbind.target')
self.assertEqual(s.get('Unit', 'After').split(), ['nss-lookup.target', 'rpcbind.target'])
def test_lsb_deps(self):
'''LSB header dependencies to other services'''