]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/generator.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / shared / generator.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e48fdd84
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
a8fbdf54 21#include <errno.h>
e48fdd84
LP
22#include <unistd.h>
23
b5efdb8a 24#include "alloc-util.h"
4f5dd394
LP
25#include "dropin.h"
26#include "escape.h"
3ffd4af2 27#include "fd-util.h"
4f5dd394
LP
28#include "fileio.h"
29#include "fstab-util.h"
3ffd4af2 30#include "generator.h"
a8fbdf54
TA
31#include "log.h"
32#include "macro.h"
e48fdd84 33#include "mkdir.h"
4f5dd394
LP
34#include "path-util.h"
35#include "special.h"
07630cea 36#include "string-util.h"
a8fbdf54 37#include "time-util.h"
e48fdd84 38#include "unit-name.h"
4f5dd394 39#include "util.h"
e48fdd84 40
b559616f
ZJS
41int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src) {
42 /* Adds a symlink from <dst>.<dep_type>.d/ to ../<src> */
43
44 const char *from, *to;
45
46 from = strjoina("../", src);
47 to = strjoina(root, "/", dst, ".", dep_type, "/", src);
48
49 mkdir_parents_label(to, 0755);
50 if (symlink(from, to) < 0)
7f0cc637
ZJS
51 if (errno != EEXIST)
52 return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
b559616f
ZJS
53
54 return 0;
55}
56
4dda4e63 57static int write_fsck_sysroot_service(const char *dir, const char *what) {
85eca92e 58 _cleanup_free_ char *device = NULL, *escaped = NULL;
4dda4e63 59 _cleanup_fclose_ FILE *f = NULL;
85eca92e 60 const char *unit;
4dda4e63
ZJS
61 int r;
62
fa05e972
AB
63 escaped = cescape(what);
64 if (!escaped)
65 return log_oom();
66
4dda4e63
ZJS
67 unit = strjoina(dir, "/systemd-fsck-root.service");
68 log_debug("Creating %s", unit);
69
70 r = unit_name_from_path(what, ".device", &device);
71 if (r < 0)
72 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
73
74 f = fopen(unit, "wxe");
75 if (!f)
76 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
77
78 fprintf(f,
79 "# Automatically generated by %1$s\n\n"
80 "[Unit]\n"
81 "Documentation=man:systemd-fsck-root.service(8)\n"
82 "Description=File System Check on %2$s\n"
83 "DefaultDependencies=no\n"
84 "BindsTo=%3$s\n"
0900593e 85 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
4dda4e63
ZJS
86 "Before=shutdown.target\n"
87 "\n"
88 "[Service]\n"
89 "Type=oneshot\n"
90 "RemainAfterExit=yes\n"
fa05e972 91 "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
4dda4e63
ZJS
92 "TimeoutSec=0\n",
93 program_invocation_short_name,
94 what,
fa05e972
AB
95 device,
96 escaped);
4dda4e63 97
2929b4a6
LP
98 r = fflush_and_check(f);
99 if (r < 0)
100 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
4dda4e63
ZJS
101
102 return 0;
103}
104
e48fdd84
LP
105int generator_write_fsck_deps(
106 FILE *f,
2e852276 107 const char *dir,
e48fdd84
LP
108 const char *what,
109 const char *where,
6db615c1 110 const char *fstype) {
e48fdd84 111
7410616c
LP
112 int r;
113
e48fdd84 114 assert(f);
2e852276 115 assert(dir);
6db615c1
LP
116 assert(what);
117 assert(where);
e48fdd84
LP
118
119 if (!is_device_path(what)) {
120 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
121 return 0;
122 }
123
6db615c1 124 if (!isempty(fstype) && !streq(fstype, "auto")) {
eb66db55 125 r = fsck_exists(fstype);
85eca92e
LP
126 if (r < 0)
127 log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
128 else if (r == 0) {
e48fdd84 129 /* treat missing check as essentially OK */
85eca92e 130 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
571d0134 131 return 0;
85eca92e 132 }
e48fdd84
LP
133 }
134
2e852276 135 if (path_equal(where, "/")) {
85eca92e 136 const char *lnk;
e48fdd84 137
2e852276 138 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
e48fdd84
LP
139
140 mkdir_parents(lnk, 0755);
4a62c710
MS
141 if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
142 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
e48fdd84
LP
143
144 } else {
4dda4e63
ZJS
145 _cleanup_free_ char *_fsck = NULL;
146 const char *fsck;
147
148 if (in_initrd() && path_equal(where, "/sysroot")) {
149 r = write_fsck_sysroot_service(dir, what);
150 if (r < 0)
151 return r;
152
153 fsck = "systemd-fsck-root.service";
154 } else {
155 r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
156 if (r < 0)
157 return log_error_errno(r, "Failed to create fsck service name: %m");
158
159 fsck = _fsck;
160 }
e48fdd84
LP
161
162 fprintf(f,
f32b43bd 163 "Requires=%1$s\n"
2e852276 164 "After=%1$s\n",
e48fdd84
LP
165 fsck);
166 }
167
168 return 0;
169}
29686440 170
2e852276
ZJS
171int generator_write_timeouts(
172 const char *dir,
173 const char *what,
174 const char *where,
175 const char *opts,
176 char **filtered) {
29686440
ZJS
177
178 /* Allow configuration how long we wait for a device that
179 * backs a mount point to show up. This is useful to support
180 * endless device timeouts for devices that show up only after
181 * user input, like crypto devices. */
182
d15d0333 183 _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
29686440
ZJS
184 usec_t u;
185 int r;
29686440 186
0004f698
ZJS
187 r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
188 "x-systemd.device-timeout\0",
d15d0333
ZJS
189 NULL, &timeout, filtered);
190 if (r <= 0)
191 return r;
b3208b66 192
0004f698 193 r = parse_sec_fix_0(timeout, &u);
29686440 194 if (r < 0) {
7410616c 195 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
29686440
ZJS
196 return 0;
197 }
198
199 node = fstab_node_to_udev_node(what);
200 if (!node)
201 return log_oom();
c67bd1f7
N
202 if (!is_device_path(node)) {
203 log_warning("x-systemd.device-timeout ignored for %s", what);
204 return 0;
205 }
29686440 206
7410616c
LP
207 r = unit_name_from_path(node, ".device", &unit);
208 if (r < 0)
209 return log_error_errno(r, "Failed to make unit name from path: %m");
29686440 210
8eea8687
ZJS
211 return write_drop_in_format(dir, unit, 50, "device-timeout",
212 "# Automatically generated by %s\n\n"
acd53eaa
LP
213 "[Unit]\n"
214 "JobRunningTimeoutSec=%s",
215 program_invocation_short_name,
216 timeout);
29686440 217}
7163e1ca 218
4195077a
MK
219int generator_write_device_deps(
220 const char *dir,
221 const char *what,
222 const char *where,
223 const char *opts) {
224
225 /* fstab records that specify _netdev option should apply the network
226 * ordering on the actual device depending on network connection. If we
227 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
228 * on the mount unit itself. */
229
230 _cleanup_free_ char *node = NULL, *unit = NULL;
231 int r;
232
233 if (!fstab_test_option(opts, "_netdev\0"))
234 return 0;
235
236 node = fstab_node_to_udev_node(what);
237 if (!node)
238 return log_oom();
239
240 /* Nothing to apply dependencies to. */
241 if (!is_device_path(node))
242 return 0;
243
244 r = unit_name_from_path(node, ".device", &unit);
245 if (r < 0)
246 return log_error_errno(r, "Failed to make unit name from path: %m");
247
248 /* See mount_add_default_dependencies for explanation why we create such
249 * dependencies. */
250 return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
251 "# Automatically generated by %s\n\n"
252 "[Unit]\n"
253 "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
254 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
255 program_invocation_short_name);
256}
257
7163e1ca
DD
258int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
259 _cleanup_free_ char *unit = NULL;
260 int r;
261
262 r = unit_name_from_path(what, ".device", &unit);
263 if (r < 0)
264 return log_error_errno(r, "Failed to make unit name from path: %m");
265
266 return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
267 "# Automatically generated by %s\n\n"
acd53eaa
LP
268 "[Unit]\n"
269 "Requires=%s\n"
270 "After=%s",
271 program_invocation_short_name,
272 unit,
273 unit);
7163e1ca 274}