]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/generator.c
coccinelle: make use of SYNTHETIC_ERRNO
[thirdparty/systemd.git] / src / shared / generator.c
index 5f6b1de811ae40592fe34e69f32bc24809af81bc..e4a15f8b115c1c9f536d211960515744d50e508e 100644 (file)
@@ -1,23 +1,7 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <stdio_ext.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "special.h"
+#include "specifier.h"
 #include "string-util.h"
 #include "time-util.h"
 #include "unit-name.h"
 #include "util.h"
 
+int generator_open_unit_file(
+                const char *dest,
+                const char *source,
+                const char *name,
+                FILE **file) {
+
+        const char *unit;
+        FILE *f;
+
+        unit = strjoina(dest, "/", name);
+
+        f = fopen(unit, "wxe");
+        if (!f) {
+                if (source && errno == EEXIST)
+                        return log_error_errno(errno,
+                                               "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
+                                               unit, source);
+                else
+                        return log_error_errno(errno,
+                                               "Failed to create unit file %s: %m",
+                                               unit);
+        }
+
+        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+        fprintf(f,
+                "# Automatically generated by %s\n\n",
+                program_invocation_short_name);
+
+        *file = f;
+        return 0;
+}
+
+int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src) {
+        /* Adds a symlink from <dst>.<dep_type>.d/ to ../<src> */
+
+        const char *from, *to;
+
+        from = strjoina("../", src);
+        to = strjoina(root, "/", dst, ".", dep_type, "/", src);
+
+        mkdir_parents_label(to, 0755);
+        if (symlink(from, to) < 0)
+                if (errno != EEXIST)
+                        return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
+
+        return 0;
+}
+
 static int write_fsck_sysroot_service(const char *dir, const char *what) {
-        _cleanup_free_ char *device = NULL, *escaped = NULL;
+        _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         const char *unit;
         int r;
 
-        escaped = cescape(what);
+        escaped = specifier_escape(what);
         if (!escaped)
                 return log_oom();
 
+        escaped2 = cescape(escaped);
+        if (!escaped2)
+                return log_oom();
+
         unit = strjoina(dir, "/systemd-fsck-root.service");
         log_debug("Creating %s", unit);
 
@@ -61,8 +99,8 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
         fprintf(f,
                 "# Automatically generated by %1$s\n\n"
                 "[Unit]\n"
-                "Documentation=man:systemd-fsck-root.service(8)\n"
                 "Description=File System Check on %2$s\n"
+                "Documentation=man:systemd-fsck-root.service(8)\n"
                 "DefaultDependencies=no\n"
                 "BindsTo=%3$s\n"
                 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
@@ -74,9 +112,9 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
                 "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
                 "TimeoutSec=0\n",
                 program_invocation_short_name,
-                what,
+                escaped,
                 device,
-                escaped);
+                escaped2);
 
         r = fflush_and_check(f);
         if (r < 0)
@@ -167,12 +205,13 @@ int generator_write_timeouts(
         usec_t u;
         int r;
 
-        r = fstab_filter_options(opts, "comment=systemd.device-timeout\0" "x-systemd.device-timeout\0",
+        r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
+                                       "x-systemd.device-timeout\0",
                                  NULL, &timeout, filtered);
         if (r <= 0)
                 return r;
 
-        r = parse_sec(timeout, &u);
+        r = parse_sec_fix_0(timeout, &u);
         if (r < 0) {
                 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
                 return 0;
@@ -181,6 +220,10 @@ int generator_write_timeouts(
         node = fstab_node_to_udev_node(what);
         if (!node)
                 return log_oom();
+        if (!is_device_path(node)) {
+                log_warning("x-systemd.device-timeout ignored for %s", what);
+                return 0;
+        }
 
         r = unit_name_from_path(node, ".device", &unit);
         if (r < 0)
@@ -188,8 +231,10 @@ int generator_write_timeouts(
 
         return write_drop_in_format(dir, unit, 50, "device-timeout",
                                     "# Automatically generated by %s\n\n"
-                                    "[Unit]\nJobTimeoutSec=%s",
-                                    program_invocation_short_name, timeout);
+                                    "[Unit]\n"
+                                    "JobRunningTimeoutSec=%s",
+                                    program_invocation_short_name,
+                                    timeout);
 }
 
 int generator_write_device_deps(
@@ -219,7 +264,8 @@ int generator_write_device_deps(
 
         r = unit_name_from_path(node, ".device", &unit);
         if (r < 0)
-                return log_error_errno(r, "Failed to make unit name from path: %m");
+                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+                                       node);
 
         /* See mount_add_default_dependencies for explanation why we create such
          * dependencies. */
@@ -237,10 +283,223 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
 
         r = unit_name_from_path(what, ".device", &unit);
         if (r < 0)
-                return log_error_errno(r, "Failed to make unit name from path: %m");
+                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+                                       what);
 
         return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
                                     "# Automatically generated by %s\n\n"
-                                    "[Unit]\nRequires=%s\nAfter=%s",
-                                    program_invocation_short_name, unit, unit);
+                                    "[Unit]\n"
+                                    "Requires=%s\n"
+                                    "After=%s",
+                                    program_invocation_short_name,
+                                    unit,
+                                    unit);
+}
+
+int generator_hook_up_mkswap(
+                const char *dir,
+                const char *what) {
+
+        _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        const char *unit_file;
+        int r;
+
+        node = fstab_node_to_udev_node(what);
+        if (!node)
+                return log_oom();
+
+        /* Nothing to work on. */
+        if (!is_device_path(node))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Cannot format something that is not a device node: %s",
+                                       node);
+
+        r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+                                       node);
+
+        unit_file = strjoina(dir, "/", unit);
+        log_debug("Creating %s", unit_file);
+
+        escaped = cescape(node);
+        if (!escaped)
+                return log_oom();
+
+        r = unit_name_from_path(what, ".swap", &where_unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+                                       what);
+
+        f = fopen(unit_file, "wxe");
+        if (!f)
+                return log_error_errno(errno, "Failed to create unit file %s: %m",
+                                       unit_file);
+
+        fprintf(f,
+                "# Automatically generated by %s\n\n"
+                "[Unit]\n"
+                "Description=Make Swap on %%f\n"
+                "Documentation=man:systemd-mkswap@.service(8)\n"
+                "DefaultDependencies=no\n"
+                "BindsTo=%%i.device\n"
+                "After=%%i.device\n"
+                "Before=%s\n"
+                "Before=shutdown.target\n"
+                "\n"
+                "[Service]\n"
+                "Type=oneshot\n"
+                "RemainAfterExit=yes\n"
+                "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
+                "TimeoutSec=0\n",
+                program_invocation_short_name,
+                where_unit,
+                escaped);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
+
+        return generator_add_symlink(dir, where_unit, "requires", unit);
+}
+
+int generator_hook_up_mkfs(
+                const char *dir,
+                const char *what,
+                const char *where,
+                const char *type) {
+
+        _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        const char *unit_file;
+        int r;
+
+        node = fstab_node_to_udev_node(what);
+        if (!node)
+                return log_oom();
+
+        /* Nothing to work on. */
+        if (!is_device_path(node))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Cannot format something that is not a device node: %s",
+                                       node);
+
+        if (!type || streq(type, "auto"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Cannot format partition %s, filesystem type is not specified",
+                                       node);
+
+        r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+                                       node);
+
+        unit_file = strjoina(dir, "/", unit);
+        log_debug("Creating %s", unit_file);
+
+        escaped = cescape(node);
+        if (!escaped)
+                return log_oom();
+
+        r = unit_name_from_path(where, ".mount", &where_unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+                                       where);
+
+        f = fopen(unit_file, "wxe");
+        if (!f)
+                return log_error_errno(errno, "Failed to create unit file %s: %m",
+                                       unit_file);
+
+        fprintf(f,
+                "# Automatically generated by %s\n\n"
+                "[Unit]\n"
+                "Description=Make File System on %%f\n"
+                "Documentation=man:systemd-mkfs@.service(8)\n"
+                "DefaultDependencies=no\n"
+                "BindsTo=%%i.device\n"
+                "After=%%i.device\n"
+                /* fsck might or might not be used, so let's be safe and order
+                 * ourselves before both systemd-fsck@.service and the mount unit. */
+                "Before=systemd-fsck@%%i.service\n"
+                "Before=%s\n"
+                "Before=shutdown.target\n"
+                "\n"
+                "[Service]\n"
+                "Type=oneshot\n"
+                "RemainAfterExit=yes\n"
+                "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
+                "TimeoutSec=0\n",
+                program_invocation_short_name,
+                where_unit,
+                type,
+                escaped);
+        // XXX: what about local-fs-pre.target?
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
+
+        return generator_add_symlink(dir, where_unit, "requires", unit);
+}
+
+int generator_hook_up_growfs(
+                const char *dir,
+                const char *where,
+                const char *target) {
+
+        _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        const char *unit_file;
+        int r;
+
+        escaped = cescape(where);
+        if (!escaped)
+                return log_oom();
+
+        r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+                                       where);
+
+        r = unit_name_from_path(where, ".mount", &where_unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+                                       where);
+
+        unit_file = strjoina(dir, "/", unit);
+        log_debug("Creating %s", unit_file);
+
+        f = fopen(unit_file, "wxe");
+        if (!f)
+                return log_error_errno(errno, "Failed to create unit file %s: %m",
+                                       unit_file);
+
+        fprintf(f,
+                "# Automatically generated by %s\n\n"
+                "[Unit]\n"
+                "Description=Grow File System on %%f\n"
+                "Documentation=man:systemd-growfs@.service(8)\n"
+                "DefaultDependencies=no\n"
+                "BindsTo=%%i.mount\n"
+                "After=%%i.mount\n"
+                "Before=shutdown.target\n"
+                "Before=%s\n"
+                "\n"
+                "[Service]\n"
+                "Type=oneshot\n"
+                "RemainAfterExit=yes\n"
+                "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
+                "TimeoutSec=0\n",
+                program_invocation_short_name,
+                target,
+                escaped);
+
+        return generator_add_symlink(dir, where_unit, "wants", unit);
+}
+
+void log_setup_generator(void) {
+        log_set_prohibit_ipc(true);
+        log_setup_service();
 }