]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/generator.c
shared/generator: voidify mkdir_parents() call
[thirdparty/systemd.git] / src / shared / generator.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e48fdd84 2
a8fbdf54 3#include <errno.h>
e48fdd84
LP
4#include <unistd.h>
5
b5efdb8a 6#include "alloc-util.h"
4f5dd394
LP
7#include "dropin.h"
8#include "escape.h"
3ffd4af2 9#include "fd-util.h"
4f5dd394
LP
10#include "fileio.h"
11#include "fstab-util.h"
3ffd4af2 12#include "generator.h"
a8fbdf54
TA
13#include "log.h"
14#include "macro.h"
e48fdd84 15#include "mkdir.h"
4f5dd394
LP
16#include "path-util.h"
17#include "special.h"
98bad05e 18#include "specifier.h"
07630cea 19#include "string-util.h"
a8fbdf54 20#include "time-util.h"
e48fdd84 21#include "unit-name.h"
4f5dd394 22#include "util.h"
e48fdd84 23
fb883e75
ZJS
24int generator_open_unit_file(
25 const char *dest,
26 const char *source,
27 const char *name,
28 FILE **file) {
29
30 const char *unit;
31 FILE *f;
41f6e627 32 int r;
fb883e75
ZJS
33
34 unit = strjoina(dest, "/", name);
35
41f6e627
ZJS
36 r = fopen_unlocked(unit, "wxe", &f);
37 if (r < 0) {
38 if (source && r == -EEXIST)
39 return log_error_errno(r,
fb883e75
ZJS
40 "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
41 unit, source);
42 else
41f6e627 43 return log_error_errno(r,
fb883e75
ZJS
44 "Failed to create unit file %s: %m",
45 unit);
46 }
47
fb883e75
ZJS
48 fprintf(f,
49 "# Automatically generated by %s\n\n",
50 program_invocation_short_name);
51
52 *file = f;
53 return 0;
54}
55
5c176eb4
ZJS
56int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src) {
57 /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
58 * or ../<src> (otherwise). */
b559616f
ZJS
59
60 const char *from, *to;
61
5c176eb4
ZJS
62 from = path_is_absolute(src) ? src : strjoina("../", src);
63 to = strjoina(dir, "/", dst, ".", dep_type, "/", basename(src));
b559616f
ZJS
64
65 mkdir_parents_label(to, 0755);
66 if (symlink(from, to) < 0)
7f0cc637
ZJS
67 if (errno != EEXIST)
68 return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
b559616f
ZJS
69
70 return 0;
71}
72
4dda4e63 73static int write_fsck_sysroot_service(const char *dir, const char *what) {
98bad05e 74 _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
4dda4e63 75 _cleanup_fclose_ FILE *f = NULL;
85eca92e 76 const char *unit;
4dda4e63
ZJS
77 int r;
78
98bad05e 79 escaped = specifier_escape(what);
fa05e972
AB
80 if (!escaped)
81 return log_oom();
82
98bad05e
LP
83 escaped2 = cescape(escaped);
84 if (!escaped2)
85 return log_oom();
86
5ff8da10 87 unit = strjoina(dir, "/"SPECIAL_FSCK_ROOT_SERVICE);
4dda4e63
ZJS
88 log_debug("Creating %s", unit);
89
90 r = unit_name_from_path(what, ".device", &device);
91 if (r < 0)
92 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
93
94 f = fopen(unit, "wxe");
95 if (!f)
96 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
97
98 fprintf(f,
99 "# Automatically generated by %1$s\n\n"
100 "[Unit]\n"
4dda4e63 101 "Description=File System Check on %2$s\n"
da495a03 102 "Documentation=man:systemd-fsck-root.service(8)\n"
4dda4e63
ZJS
103 "DefaultDependencies=no\n"
104 "BindsTo=%3$s\n"
ff9bf8d0 105 "Conflicts=shutdown.target\n"
0900593e 106 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
4dda4e63
ZJS
107 "Before=shutdown.target\n"
108 "\n"
109 "[Service]\n"
110 "Type=oneshot\n"
111 "RemainAfterExit=yes\n"
fa05e972 112 "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
4dda4e63
ZJS
113 "TimeoutSec=0\n",
114 program_invocation_short_name,
98bad05e 115 escaped,
fa05e972 116 device,
98bad05e 117 escaped2);
4dda4e63 118
2929b4a6
LP
119 r = fflush_and_check(f);
120 if (r < 0)
121 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
4dda4e63
ZJS
122
123 return 0;
124}
125
e48fdd84
LP
126int generator_write_fsck_deps(
127 FILE *f,
2e852276 128 const char *dir,
e48fdd84
LP
129 const char *what,
130 const char *where,
6db615c1 131 const char *fstype) {
e48fdd84 132
7410616c
LP
133 int r;
134
e48fdd84 135 assert(f);
2e852276 136 assert(dir);
6db615c1
LP
137 assert(what);
138 assert(where);
e48fdd84
LP
139
140 if (!is_device_path(what)) {
141 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
142 return 0;
143 }
144
6db615c1 145 if (!isempty(fstype) && !streq(fstype, "auto")) {
eb66db55 146 r = fsck_exists(fstype);
85eca92e
LP
147 if (r < 0)
148 log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
149 else if (r == 0) {
e48fdd84 150 /* treat missing check as essentially OK */
85eca92e 151 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
571d0134 152 return 0;
85eca92e 153 }
e48fdd84
LP
154 }
155
2e852276 156 if (path_equal(where, "/")) {
85eca92e 157 const char *lnk;
e48fdd84 158
5ff8da10 159 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/"SPECIAL_FSCK_ROOT_SERVICE);
e48fdd84 160
37dc34f7 161 (void) mkdir_parents(lnk, 0755);
5ff8da10 162 if (symlink(SYSTEM_DATA_UNIT_PATH "/"SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0)
4a62c710 163 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
e48fdd84
LP
164
165 } else {
4dda4e63
ZJS
166 _cleanup_free_ char *_fsck = NULL;
167 const char *fsck;
168
169 if (in_initrd() && path_equal(where, "/sysroot")) {
170 r = write_fsck_sysroot_service(dir, what);
171 if (r < 0)
172 return r;
173
5ff8da10 174 fsck = SPECIAL_FSCK_ROOT_SERVICE;
4dda4e63
ZJS
175 } else {
176 r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
177 if (r < 0)
178 return log_error_errno(r, "Failed to create fsck service name: %m");
179
180 fsck = _fsck;
181 }
e48fdd84
LP
182
183 fprintf(f,
f32b43bd 184 "Requires=%1$s\n"
2e852276 185 "After=%1$s\n",
e48fdd84
LP
186 fsck);
187 }
188
189 return 0;
190}
29686440 191
2e852276
ZJS
192int generator_write_timeouts(
193 const char *dir,
194 const char *what,
195 const char *where,
196 const char *opts,
197 char **filtered) {
29686440 198
c2f4bcfc
ZJS
199 /* Configure how long we wait for a device that backs a mount point or a
200 * swap partition to show up. This is useful to support endless device timeouts
201 * for devices that show up only after user input, like crypto devices. */
29686440 202
d15d0333 203 _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
29686440
ZJS
204 usec_t u;
205 int r;
29686440 206
0004f698
ZJS
207 r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
208 "x-systemd.device-timeout\0",
d15d0333
ZJS
209 NULL, &timeout, filtered);
210 if (r <= 0)
211 return r;
b3208b66 212
0004f698 213 r = parse_sec_fix_0(timeout, &u);
29686440 214 if (r < 0) {
7410616c 215 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
29686440
ZJS
216 return 0;
217 }
218
219 node = fstab_node_to_udev_node(what);
220 if (!node)
221 return log_oom();
c67bd1f7
N
222 if (!is_device_path(node)) {
223 log_warning("x-systemd.device-timeout ignored for %s", what);
224 return 0;
225 }
29686440 226
7410616c
LP
227 r = unit_name_from_path(node, ".device", &unit);
228 if (r < 0)
229 return log_error_errno(r, "Failed to make unit name from path: %m");
29686440 230
8eea8687
ZJS
231 return write_drop_in_format(dir, unit, 50, "device-timeout",
232 "# Automatically generated by %s\n\n"
acd53eaa
LP
233 "[Unit]\n"
234 "JobRunningTimeoutSec=%s",
235 program_invocation_short_name,
236 timeout);
29686440 237}
7163e1ca 238
4195077a
MK
239int generator_write_device_deps(
240 const char *dir,
241 const char *what,
242 const char *where,
243 const char *opts) {
244
245 /* fstab records that specify _netdev option should apply the network
246 * ordering on the actual device depending on network connection. If we
247 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
248 * on the mount unit itself. */
249
250 _cleanup_free_ char *node = NULL, *unit = NULL;
251 int r;
252
253 if (!fstab_test_option(opts, "_netdev\0"))
254 return 0;
255
256 node = fstab_node_to_udev_node(what);
257 if (!node)
258 return log_oom();
259
260 /* Nothing to apply dependencies to. */
261 if (!is_device_path(node))
262 return 0;
263
264 r = unit_name_from_path(node, ".device", &unit);
265 if (r < 0)
da495a03
ZJS
266 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
267 node);
4195077a
MK
268
269 /* See mount_add_default_dependencies for explanation why we create such
270 * dependencies. */
271 return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
272 "# Automatically generated by %s\n\n"
273 "[Unit]\n"
274 "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
275 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
276 program_invocation_short_name);
277}
278
7163e1ca
DD
279int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
280 _cleanup_free_ char *unit = NULL;
281 int r;
282
283 r = unit_name_from_path(what, ".device", &unit);
284 if (r < 0)
da495a03
ZJS
285 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
286 what);
7163e1ca
DD
287
288 return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
289 "# Automatically generated by %s\n\n"
acd53eaa
LP
290 "[Unit]\n"
291 "Requires=%s\n"
292 "After=%s",
293 program_invocation_short_name,
294 unit,
295 unit);
7163e1ca 296}
da495a03
ZJS
297
298int generator_hook_up_mkswap(
299 const char *dir,
300 const char *what) {
301
302 _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
303 _cleanup_fclose_ FILE *f = NULL;
304 const char *unit_file;
305 int r;
306
307 node = fstab_node_to_udev_node(what);
308 if (!node)
309 return log_oom();
310
311 /* Nothing to work on. */
baaa35ad
ZJS
312 if (!is_device_path(node))
313 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
314 "Cannot format something that is not a device node: %s",
315 node);
da495a03
ZJS
316
317 r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
318 if (r < 0)
319 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
320 node);
321
322 unit_file = strjoina(dir, "/", unit);
323 log_debug("Creating %s", unit_file);
324
325 escaped = cescape(node);
326 if (!escaped)
327 return log_oom();
328
329 r = unit_name_from_path(what, ".swap", &where_unit);
330 if (r < 0)
331 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
332 what);
333
334 f = fopen(unit_file, "wxe");
335 if (!f)
336 return log_error_errno(errno, "Failed to create unit file %s: %m",
337 unit_file);
338
339 fprintf(f,
340 "# Automatically generated by %s\n\n"
341 "[Unit]\n"
342 "Description=Make Swap on %%f\n"
343 "Documentation=man:systemd-mkswap@.service(8)\n"
344 "DefaultDependencies=no\n"
345 "BindsTo=%%i.device\n"
ff9bf8d0 346 "Conflicts=shutdown.target\n"
da495a03 347 "After=%%i.device\n"
ff9bf8d0 348 "Before=shutdown.target %s\n"
da495a03
ZJS
349 "\n"
350 "[Service]\n"
351 "Type=oneshot\n"
352 "RemainAfterExit=yes\n"
353 "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
354 "TimeoutSec=0\n",
355 program_invocation_short_name,
356 where_unit,
357 escaped);
358
359 r = fflush_and_check(f);
360 if (r < 0)
361 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
362
363 return generator_add_symlink(dir, where_unit, "requires", unit);
364}
365
366int generator_hook_up_mkfs(
367 const char *dir,
368 const char *what,
369 const char *where,
370 const char *type) {
371
372 _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
373 _cleanup_fclose_ FILE *f = NULL;
374 const char *unit_file;
375 int r;
376
377 node = fstab_node_to_udev_node(what);
378 if (!node)
379 return log_oom();
380
381 /* Nothing to work on. */
baaa35ad
ZJS
382 if (!is_device_path(node))
383 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
384 "Cannot format something that is not a device node: %s",
385 node);
da495a03 386
baaa35ad
ZJS
387 if (!type || streq(type, "auto"))
388 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
389 "Cannot format partition %s, filesystem type is not specified",
390 node);
da495a03 391
804f8e17 392 r = unit_name_from_path_instance("systemd-makefs", node, ".service", &unit);
da495a03
ZJS
393 if (r < 0)
394 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
395 node);
396
397 unit_file = strjoina(dir, "/", unit);
398 log_debug("Creating %s", unit_file);
399
400 escaped = cescape(node);
401 if (!escaped)
402 return log_oom();
403
404 r = unit_name_from_path(where, ".mount", &where_unit);
405 if (r < 0)
406 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
407 where);
408
409 f = fopen(unit_file, "wxe");
410 if (!f)
411 return log_error_errno(errno, "Failed to create unit file %s: %m",
412 unit_file);
413
414 fprintf(f,
415 "# Automatically generated by %s\n\n"
416 "[Unit]\n"
417 "Description=Make File System on %%f\n"
804f8e17 418 "Documentation=man:systemd-makefs@.service(8)\n"
da495a03
ZJS
419 "DefaultDependencies=no\n"
420 "BindsTo=%%i.device\n"
ff9bf8d0 421 "Conflicts=shutdown.target\n"
da495a03
ZJS
422 "After=%%i.device\n"
423 /* fsck might or might not be used, so let's be safe and order
424 * ourselves before both systemd-fsck@.service and the mount unit. */
ff9bf8d0 425 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
da495a03
ZJS
426 "\n"
427 "[Service]\n"
428 "Type=oneshot\n"
429 "RemainAfterExit=yes\n"
430 "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
431 "TimeoutSec=0\n",
432 program_invocation_short_name,
433 where_unit,
434 type,
435 escaped);
436 // XXX: what about local-fs-pre.target?
437
438 r = fflush_and_check(f);
439 if (r < 0)
440 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
441
442 return generator_add_symlink(dir, where_unit, "requires", unit);
443}
7f2806d5
ZJS
444
445int generator_hook_up_growfs(
446 const char *dir,
447 const char *where,
448 const char *target) {
449
450 _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
451 _cleanup_fclose_ FILE *f = NULL;
452 const char *unit_file;
453 int r;
454
455 escaped = cescape(where);
456 if (!escaped)
457 return log_oom();
458
459 r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
460 if (r < 0)
461 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
462 where);
463
464 r = unit_name_from_path(where, ".mount", &where_unit);
465 if (r < 0)
466 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
467 where);
468
469 unit_file = strjoina(dir, "/", unit);
470 log_debug("Creating %s", unit_file);
471
472 f = fopen(unit_file, "wxe");
473 if (!f)
474 return log_error_errno(errno, "Failed to create unit file %s: %m",
475 unit_file);
476
477 fprintf(f,
478 "# Automatically generated by %s\n\n"
479 "[Unit]\n"
480 "Description=Grow File System on %%f\n"
481 "Documentation=man:systemd-growfs@.service(8)\n"
482 "DefaultDependencies=no\n"
483 "BindsTo=%%i.mount\n"
ff9bf8d0 484 "Conflicts=shutdown.target\n"
7f2806d5 485 "After=%%i.mount\n"
ff9bf8d0 486 "Before=shutdown.target %s\n"
7f2806d5
ZJS
487 "\n"
488 "[Service]\n"
489 "Type=oneshot\n"
490 "RemainAfterExit=yes\n"
491 "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
492 "TimeoutSec=0\n",
493 program_invocation_short_name,
494 target,
495 escaped);
496
497 return generator_add_symlink(dir, where_unit, "wants", unit);
498}
afe44c8f 499
9b69569d
ZJS
500int generator_enable_remount_fs_service(const char *dir) {
501 /* Pull in systemd-remount-fs.service */
502 return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants",
503 SYSTEM_DATA_UNIT_PATH "/" SPECIAL_REMOUNT_FS_SERVICE);
504}
505
afe44c8f
LP
506void log_setup_generator(void) {
507 log_set_prohibit_ipc(true);
6bf3c61c 508 log_setup_service();
afe44c8f 509}