]> sourceware.org Git - lvm2.git/blob - scripts/lvm2_activation_generator_systemd_red_hat.c
thin: tighten discard string conversions
[lvm2.git] / scripts / lvm2_activation_generator_systemd_red_hat.c
1 /*
2 * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
3 *
4 * This file is part of the device-mapper userspace tools.
5 *
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU General Public License v.2.
9 *
10 * You should have received a copy of the GNU General Public License
11 * along with this program; if not, write to the Free Software Foundation,
12 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
13 */
14
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <stdarg.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include "lvm2app.h"
23
24 #define KMSG_DEV_PATH "/dev/kmsg"
25 #define LVM_CONF_USE_LVMETAD "global/use_lvmetad"
26
27 #define DEFAULT_UNIT_DIR "/tmp"
28 #define UNIT_NAME_EARLY "lvm2-activation-early.service"
29 #define UNIT_NAME "lvm2-activation.service"
30 #define UNIT_TARGET "local-fs.target"
31
32 static char unit_path[PATH_MAX];
33 static char target_path[PATH_MAX];
34 static char message[PATH_MAX];
35 static int kmsg_fd = -1;
36
37 static void kmsg(const char *format, ...)
38 {
39 va_list ap;
40 int n;
41
42 va_start(ap, format);
43 n = vsnprintf(message, sizeof(message), format, ap);
44 va_end(ap);
45
46 if (kmsg_fd < 0 || (n < 0 || ((unsigned) n + 1 > sizeof(message))))
47 return;
48
49 write(kmsg_fd, message, n + 1);
50 }
51
52 static int lvm_uses_lvmetad(void)
53 {
54 lvm_t lvm;
55 int r;
56
57 if (!(lvm = lvm_init(NULL))) {
58 kmsg("LVM: Failed to initialize library context for activation generator.\n");
59 return 0;
60 }
61 r = lvm_config_find_bool(lvm, LVM_CONF_USE_LVMETAD, 0);
62 lvm_quit(lvm);
63
64 return r;
65 }
66
67 static int register_unit_with_target(const char *dir, const char *unit, const char *target)
68 {
69 int r = 1;
70
71 if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants", dir, target) < 0) {
72 r = 0; goto out;
73 }
74 (void) dm_prepare_selinux_context(target_path, S_IFDIR);
75 if (mkdir(target_path, 0755) < 0 && errno != EEXIST) {
76 kmsg("LVM: Failed to create target directory %s: %m.\n", target_path);
77 r = 0; goto out;
78 }
79
80 if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants/%s", dir, target, unit) < 0) {
81 r = 0; goto out;
82 }
83 (void) dm_prepare_selinux_context(target_path, S_IFLNK);
84 if (symlink(unit_path, target_path) < 0) {
85 kmsg("LVM: Failed to create symlink for unit %s: %m.\n", unit);
86 r = 0;
87 }
88 out:
89 dm_prepare_selinux_context(NULL, 0);
90 return r;
91 }
92
93 static int generate_unit(const char *dir, int early)
94 {
95 FILE *f;
96 const char *unit = early ? UNIT_NAME_EARLY : UNIT_NAME;
97
98 if (dm_snprintf(unit_path, PATH_MAX, "%s/%s", dir, unit) < 0)
99 return 0;
100
101 if (!(f = fopen(unit_path, "wxe"))) {
102 kmsg("LVM: Failed to create unit file %s: %m.\n", unit);
103 return 0;
104 }
105
106 fputs("# Automatically generated by lvm2-activation-generator.\n"
107 "#\n"
108 "# This unit is responsible for direct activation of LVM2 logical volumes\n"
109 "# if lvmetad daemon is not used (global/use_lvmetad=0 lvm.conf setting),\n"
110 "# hence volume autoactivation is not applicable.\n"
111 "# Direct LVM2 activation requires udev to be settled!\n\n"
112 "[Unit]\n"
113 "Description=Activation of LVM2 logical volumes\n"
114 "Documentation=man:lvm(8) man:vgchange(8)\n"
115 "SourcePath=/etc/lvm/lvm.conf\n"
116 "DefaultDependencies=no\n", f);
117
118 if (early)
119 fputs("After=fedora-wait-storage.service\n", f);
120 else
121 fputs("After=lvm2-activation-early.service cryptsetup.target\n", f);
122
123 fputs("Before=local-fs.target shutdown.target\n"
124 "Wants=fedora-wait-storage.service\n\n"
125 "[Service]\n"
126 "ExecStart=/usr/sbin/lvm vgchange -aay --sysinit\n"
127 "Type=oneshot\n", f);
128
129 if (fclose(f) < 0) {
130 kmsg("LVM: Failed to write unit file %s: %m.\n", unit);
131 return 0;
132 }
133
134 if (!register_unit_with_target(dir, unit, UNIT_TARGET)) {
135 kmsg("LVM: Failed to register unit %s with target %s.\n", unit, UNIT_TARGET);
136 return 0;
137 }
138
139 return 1;
140 }
141
142 int main(int argc, char *argv[])
143 {
144 const char *dir;
145 int r = EXIT_SUCCESS;
146
147 kmsg_fd = open(KMSG_DEV_PATH, O_WRONLY|O_NOCTTY);
148
149 if (argc > 1 && argc != 4) {
150 kmsg("LVM: Activation generator takes three or no arguments.\n");
151 r = EXIT_FAILURE; goto out;
152 }
153
154 /* If lvmetad used, rely on autoactivation instead of direct activation. */
155 if (lvm_uses_lvmetad()) {
156 kmsg("LVM: Logical Volume autoactivation enabled.\n");
157 goto out;
158 }
159
160 dir = argc > 1 ? argv[1] : DEFAULT_UNIT_DIR;
161
162 if (!generate_unit(dir, 1) || !generate_unit(dir, 0))
163 r = EXIT_FAILURE;
164 out:
165 kmsg("LVM: Activation generator %s.\n", r ? "failed" : "successfully completed");
166 if (kmsg_fd != -1)
167 close(kmsg_fd);
168 return r;
169 }
This page took 1.789633 seconds and 5 git commands to generate.