summaryrefslogtreecommitdiffstats
path: root/scripts/lvm2_activation_generator_systemd_red_hat.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lvm2_activation_generator_systemd_red_hat.c')
-rw-r--r--scripts/lvm2_activation_generator_systemd_red_hat.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/scripts/lvm2_activation_generator_systemd_red_hat.c b/scripts/lvm2_activation_generator_systemd_red_hat.c
new file mode 100644
index 00000000..99210049
--- /dev/null
+++ b/scripts/lvm2_activation_generator_systemd_red_hat.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "lvm2app.h"
+
+#define KMSG_DEV_PATH "/dev/kmsg"
+#define LVM_CONF_USE_LVMETAD "global/use_lvmetad"
+
+#define DEFAULT_UNIT_DIR "/tmp"
+#define UNIT_NAME_EARLY "lvm2-activation-early.service"
+#define UNIT_NAME "lvm2-activation.service"
+#define UNIT_TARGET "local-fs.target"
+
+static char unit_path[PATH_MAX];
+static char target_path[PATH_MAX];
+static char message[PATH_MAX];
+static int kmsg_fd = -1;
+
+static void kmsg(const char *format, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, format);
+ n = vsnprintf(message, sizeof(message), format, ap);
+ va_end(ap);
+
+ if (kmsg_fd < 0 || (n < 0 || ((unsigned) n + 1 > sizeof(message))))
+ return;
+
+ write(kmsg_fd, message, n + 1);
+}
+
+static int lvm_uses_lvmetad(void)
+{
+ lvm_t lvm;
+ int r;
+
+ if (!(lvm = lvm_init(NULL))) {
+ kmsg("LVM: Failed to initialize library context for activation generator.\n");
+ return 0;
+ }
+ r = lvm_config_find_bool(lvm, LVM_CONF_USE_LVMETAD, 0);
+ lvm_quit(lvm);
+
+ return r;
+}
+
+static int register_unit_with_target(const char *dir, const char *unit, const char *target)
+{
+ int r = 1;
+
+ if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants", dir, target) < 0) {
+ r = 0; goto out;
+ }
+ (void) dm_prepare_selinux_context(target_path, S_IFDIR);
+ if (mkdir(target_path, 0755) < 0 && errno != EEXIST) {
+ kmsg("LVM: Failed to create target directory %s: %m.\n", target_path);
+ r = 0; goto out;
+ }
+
+ if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants/%s", dir, target, unit) < 0) {
+ r = 0; goto out;
+ }
+ (void) dm_prepare_selinux_context(target_path, S_IFLNK);
+ if (symlink(unit_path, target_path) < 0) {
+ kmsg("LVM: Failed to create symlink for unit %s: %m.\n", unit);
+ r = 0;
+ }
+out:
+ dm_prepare_selinux_context(NULL, 0);
+ return r;
+}
+
+static int generate_unit(const char *dir, int early)
+{
+ FILE *f;
+ const char *unit = early ? UNIT_NAME_EARLY : UNIT_NAME;
+
+ if (dm_snprintf(unit_path, PATH_MAX, "%s/%s", dir, unit) < 0)
+ return 0;
+
+ if (!(f = fopen(unit_path, "wxe"))) {
+ kmsg("LVM: Failed to create unit file %s: %m.\n", unit);
+ return 0;
+ }
+
+ fputs("# Automatically generated by lvm2-activation-generator.\n"
+ "#\n"
+ "# This unit is responsible for direct activation of LVM2 logical volumes\n"
+ "# if lvmetad daemon is not used (global/use_lvmetad=0 lvm.conf setting),\n"
+ "# hence volume autoactivation is not applicable.\n"
+ "# Direct LVM2 activation requires udev to be settled!\n\n"
+ "[Unit]\n"
+ "Description=Activation of LVM2 logical volumes\n"
+ "Documentation=man:lvm(8) man:vgchange(8)\n"
+ "SourcePath=/etc/lvm/lvm.conf\n"
+ "DefaultDependencies=no\n", f);
+
+ if (early)
+ fputs("After=fedora-wait-storage.service\n", f);
+ else
+ fputs("After=lvm2-activation-early.service cryptsetup.target\n", f);
+
+ fputs("Before=local-fs.target shutdown.target\n"
+ "Wants=fedora-wait-storage.service\n\n"
+ "[Service]\n"
+ "ExecStart=/usr/sbin/lvm vgchange -aay --sysinit\n"
+ "Type=oneshot\n", f);
+
+ if (fclose(f) < 0) {
+ kmsg("LVM: Failed to write unit file %s: %m.\n", unit);
+ return 0;
+ }
+
+ if (!register_unit_with_target(dir, unit, UNIT_TARGET)) {
+ kmsg("LVM: Failed to register unit %s with target %s.\n", unit, UNIT_TARGET);
+ return 0;
+ }
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *dir;
+ int r = EXIT_SUCCESS;
+
+ kmsg_fd = open(KMSG_DEV_PATH, O_WRONLY|O_NOCTTY|O_CLOEXEC);
+
+ if (argc > 1 && argc != 4) {
+ kmsg("LVM: Activation generator takes three or no arguments.\n");
+ r = EXIT_FAILURE; goto out;
+ }
+
+ /* If lvmetad used, rely on autoactivation instead of direct activation. */
+ if (lvm_uses_lvmetad()) {
+ kmsg("LVM: Logical Volume autoactivation enabled.\n");
+ goto out;
+ }
+
+ dir = argc > 1 ? argv[1] : DEFAULT_UNIT_DIR;
+
+ if (!generate_unit(dir, 1) || !generate_unit(dir, 0))
+ r = EXIT_FAILURE;
+out:
+ kmsg("LVM: Activation generator %s.\n", r ? "failed" : "successfully completed");
+ if (kmsg_fd != -1)
+ close(kmsg_fd);
+ return r;
+}