systemctl: do not segfault when we cannot find template unit (#4915)
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 20 Dec 2016 10:09:59 +0000 (05:09 -0500)
committerLennart Poettering <lennart@poettering.net>
Tue, 20 Dec 2016 10:09:59 +0000 (11:09 +0100)
Core was generated by `systemctl cat test@.target test@.service'.
Program terminated with signal SIGSEGV, Segmentation fault.
32              movdqu  (%rdi), %xmm0
(gdb) bt
-0  strrchr () at ../sysdeps/x86_64/strrchr.S:32
-1  0x00007f57fdf837fe in __GI___basename (filename=0x0) at basename.c:24
-2  0x000055b8a77d0d91 in unit_find_paths (bus=0x55b8a9242f90, unit_name=0x55b8a92428f0 "test@.service", lp=0x7ffdc9070400, fragment_path=0x7ffdc90703e0, dropin_paths=0x7ffdc90703e8) at src/systemctl/systemctl.c:2584
-3  0x000055b8a77dbae5 in cat (argc=3, argv=0x7ffdc9070678, userdata=0x0) at src/systemctl/systemctl.c:5324
-4  0x00007f57fe55fc6b in dispatch_verb (argc=5, argv=0x7ffdc9070668, verbs=0x55b8a77f1c60 <verbs>, userdata=0x0) at src/basic/verbs.c:92
-5  0x000055b8a77e477f in systemctl_main (argc=5, argv=0x7ffdc9070668) at src/systemctl/systemctl.c:8141
-6  0x000055b8a77e5572 in main (argc=5, argv=0x7ffdc9070668) at src/systemctl/systemctl.c:8412

The right behaviour is not easy in this case. Implement some "sensible" logic.

Fixes #4912.

src/systemctl/systemctl.c

index 67516cf..f7e85c1 100644 (file)
@@ -2559,6 +2559,7 @@ static int unit_find_paths(
                 }
         } else {
                 _cleanup_set_free_ Set *names;
+                _cleanup_free_ char *template = NULL;
 
                 names = set_new(NULL);
                 if (!names)
@@ -2569,8 +2570,6 @@ static int unit_find_paths(
                         return r;
 
                 if (r == 0) {
-                        _cleanup_free_ char *template = NULL;
-
                         r = unit_name_template(unit_name, &template);
                         if (r < 0 && r != -EINVAL)
                                 return log_error_errno(r, "Failed to determine template name: %m");
@@ -2581,7 +2580,22 @@ static int unit_find_paths(
                         }
                 }
 
-                r = set_put(names, basename(path));
+                if (path)
+                        /* We found the unit file. If we followed symlinks, this name might be
+                         * different then the unit_name with started with. Look for dropins matching
+                         * that "final" name. */
+                        r = set_put(names, basename(path));
+                else if (!template)
+                        /* No unit file, let's look for dropins matching the original name.
+                         * systemd has fairly complicated rules (based on unit type and provenience),
+                         * which units are allowed not to have the main unit file. We err on the
+                         * side of including too many files, and always try to load dropins. */
+                        r = set_put(names, unit_name);
+                else
+                        /* The cases where we allow a unit to exist without the main file are
+                         * never valid for templates. Don't try to load dropins in this case. */
+                        goto not_found;
+
                 if (r < 0)
                         return log_error_errno(r, "Failed to add unit name: %m");
 
@@ -2605,7 +2619,7 @@ static int unit_find_paths(
                 dropins = NULL;
                 r = 1;
         }
-
+ not_found:
         if (r == 0 && !arg_force)
                 log_error("No files found for %s.", unit_name);