1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <unistd.h>
5 
6 #include "alloc-util.h"
7 #include "cgroup-util.h"
8 #include "dropin.h"
9 #include "escape.h"
10 #include "fd-util.h"
11 #include "fileio.h"
12 #include "fstab-util.h"
13 #include "generator.h"
14 #include "log.h"
15 #include "macro.h"
16 #include "mkdir-label.h"
17 #include "path-util.h"
18 #include "special.h"
19 #include "specifier.h"
20 #include "string-util.h"
21 #include "time-util.h"
22 #include "unit-name.h"
23 #include "util.h"
24 
generator_open_unit_file(const char * dest,const char * source,const char * name,FILE ** file)25 int generator_open_unit_file(
26                 const char *dest,
27                 const char *source,
28                 const char *name,
29                 FILE **file) {
30 
31         const char *unit;
32         FILE *f;
33         int r;
34 
35         unit = prefix_roota(dest, name);
36 
37         r = fopen_unlocked(unit, "wxe", &f);
38         if (r < 0) {
39                 if (source && r == -EEXIST)
40                         return log_error_errno(r,
41                                                "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
42                                                unit, source);
43                 else
44                         return log_error_errno(r,
45                                                "Failed to create unit file %s: %m",
46                                                unit);
47         }
48 
49         fprintf(f,
50                 "# Automatically generated by %s\n\n",
51                 program_invocation_short_name);
52 
53         *file = f;
54         return 0;
55 }
56 
generator_add_symlink(const char * dir,const char * dst,const char * dep_type,const char * src)57 int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src) {
58         /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
59          * or ../<src> (otherwise). */
60 
61         const char *from, *to;
62 
63         from = path_is_absolute(src) ? src : strjoina("../", src);
64         to = strjoina(dir, "/", dst, ".", dep_type, "/", basename(src));
65 
66         (void) mkdir_parents_label(to, 0755);
67         if (symlink(from, to) < 0)
68                 if (errno != EEXIST)
69                         return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
70 
71         return 0;
72 }
73 
write_fsck_sysroot_service(const char * unit,const char * dir,const char * what,const char * extra_after)74 static int write_fsck_sysroot_service(
75                 const char *unit, /* Either SPECIAL_FSCK_ROOT_SERVICE or SPECIAL_FSCK_USR_SERVICE */
76                 const char *dir,
77                 const char *what,
78                 const char *extra_after) {
79 
80         _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
81         _cleanup_fclose_ FILE *f = NULL;
82         const char *fn;
83         int r;
84 
85         /* Writes out special versions of systemd-root-fsck.service and systemd-usr-fsck.service for use in
86          * the initrd. The regular statically shipped versions of these unit files use / and /usr for as
87          * paths, which doesn't match what we need for the initrd (where the dirs are /sysroot +
88          * /sysusr/usr), hence we overwrite those versions here. */
89 
90         escaped = specifier_escape(what);
91         if (!escaped)
92                 return log_oom();
93 
94         escaped2 = cescape(escaped);
95         if (!escaped2)
96                 return log_oom();
97 
98         fn = strjoina(dir, "/", unit);
99         log_debug("Creating %s", fn);
100 
101         r = unit_name_from_path(what, ".device", &device);
102         if (r < 0)
103                 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
104 
105         f = fopen(fn, "wxe");
106         if (!f)
107                 return log_error_errno(errno, "Failed to create unit file %s: %m", fn);
108 
109         fprintf(f,
110                 "# Automatically generated by %1$s\n\n"
111                 "[Unit]\n"
112                 "Description=File System Check on %2$s\n"
113                 "Documentation=man:%3$s(8)\n"
114                 "DefaultDependencies=no\n"
115                 "BindsTo=%4$s\n"
116                 "Conflicts=shutdown.target\n"
117                 "After=%5$s%6$slocal-fs-pre.target %4$s\n"
118                 "Before=shutdown.target\n"
119                 "\n"
120                 "[Service]\n"
121                 "Type=oneshot\n"
122                 "RemainAfterExit=yes\n"
123                 "ExecStart=" SYSTEMD_FSCK_PATH " %7$s\n"
124                 "TimeoutSec=0\n",
125                 program_invocation_short_name,
126                 escaped,
127                 unit,
128                 device,
129                 strempty(extra_after),
130                 isempty(extra_after) ? "" : " ",
131                 escaped2);
132 
133         r = fflush_and_check(f);
134         if (r < 0)
135                 return log_error_errno(r, "Failed to write unit file %s: %m", fn);
136 
137         return 0;
138 }
139 
generator_write_fsck_deps(FILE * f,const char * dir,const char * what,const char * where,const char * fstype)140 int generator_write_fsck_deps(
141                 FILE *f,
142                 const char *dir,
143                 const char *what,
144                 const char *where,
145                 const char *fstype) {
146 
147         int r;
148 
149         assert(f);
150         assert(dir);
151         assert(what);
152         assert(where);
153 
154         /* Let's do an early exit if we are invoked for the root and /usr/ trees in the initrd, to avoid
155          * generating confusing log messages */
156         if (in_initrd() && PATH_IN_SET(where, "/", "/usr")) {
157                 log_debug("Skipping fsck for %s in initrd.", where);
158                 return 0;
159         }
160 
161         if (!is_device_path(what)) {
162                 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
163                 return 0;
164         }
165 
166         if (!isempty(fstype) && !streq(fstype, "auto")) {
167                 r = fsck_exists(fstype);
168                 if (r < 0)
169                         log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
170                 else if (r == 0) {
171                         /* treat missing check as essentially OK */
172                         log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
173                         return 0;
174                 }
175         }
176 
177         if (path_equal(where, "/")) {
178                 const char *lnk;
179 
180                 /* We support running the fsck instance for the root fs while it is already mounted, for
181                  * compatibility with non-initrd boots. It's ugly, but it is how it is. Since – unlike for
182                  * regular file systems – this means the ordering is reversed (i.e. mount *before* fsck) we
183                  * have a separate fsck unit for this, independent of systemd-fsck@.service. */
184 
185                 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/" SPECIAL_FSCK_ROOT_SERVICE);
186 
187                 (void) mkdir_parents(lnk, 0755);
188                 if (symlink(SYSTEM_DATA_UNIT_DIR "/" SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0)
189                         return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
190 
191         } else {
192                 _cleanup_free_ char *_fsck = NULL;
193                 const char *fsck, *dep;
194 
195                 if (in_initrd() && path_equal(where, "/sysroot")) {
196                         r = write_fsck_sysroot_service(SPECIAL_FSCK_ROOT_SERVICE, dir, what, SPECIAL_INITRD_ROOT_DEVICE_TARGET);
197                         if (r < 0)
198                                 return r;
199 
200                         fsck = SPECIAL_FSCK_ROOT_SERVICE;
201                         dep = "Requires";
202 
203                 } else if (in_initrd() && path_equal(where, "/sysusr/usr")) {
204                         r = write_fsck_sysroot_service(SPECIAL_FSCK_USR_SERVICE, dir, what, NULL);
205                         if (r < 0)
206                                 return r;
207 
208                         fsck = SPECIAL_FSCK_USR_SERVICE;
209                         dep = "Requires";
210                 } else {
211                         /* When this is /usr, then let's add a Wants= dependency, otherwise a Requires=
212                          * dependency. Why? We can't possibly unmount /usr during shutdown, but if we have a
213                          * Requires= from /usr onto a fsck@.service unit and that unit is shut down, then
214                          * we'd have to unmount /usr too.  */
215 
216                         dep = path_equal(where, "/usr") ? "Wants" : "Requires";
217 
218                         r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
219                         if (r < 0)
220                                 return log_error_errno(r, "Failed to create fsck service name: %m");
221 
222                         fsck = _fsck;
223                 }
224 
225                 fprintf(f,
226                         "%1$s=%2$s\n"
227                         "After=%2$s\n",
228                         dep, fsck);
229         }
230 
231         return 0;
232 }
233 
generator_write_timeouts(const char * dir,const char * what,const char * where,const char * opts,char ** filtered)234 int generator_write_timeouts(
235                 const char *dir,
236                 const char *what,
237                 const char *where,
238                 const char *opts,
239                 char **filtered) {
240 
241         /* Configure how long we wait for a device that backs a mount point or a
242          * swap partition to show up. This is useful to support endless device timeouts
243          * for devices that show up only after user input, like crypto devices. */
244 
245         _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
246         usec_t u;
247         int r;
248 
249         r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
250                                        "x-systemd.device-timeout\0",
251                                  NULL, &timeout, NULL, filtered);
252         if (r < 0) {
253                 log_warning_errno(r, "Failed to parse fstab options, ignoring: %m");
254                 return 0;
255         }
256         if (r == 0)
257                 return 0;
258 
259         r = parse_sec_fix_0(timeout, &u);
260         if (r < 0) {
261                 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
262                 return 0;
263         }
264 
265         node = fstab_node_to_udev_node(what);
266         if (!node)
267                 return log_oom();
268         if (!is_device_path(node)) {
269                 log_warning("x-systemd.device-timeout ignored for %s", what);
270                 return 0;
271         }
272 
273         r = unit_name_from_path(node, ".device", &unit);
274         if (r < 0)
275                 return log_error_errno(r, "Failed to make unit name from path: %m");
276 
277         return write_drop_in_format(dir, unit, 50, "device-timeout",
278                                     "# Automatically generated by %s\n"
279                                     "# from supplied options \"%s\"\n\n"
280                                     "[Unit]\n"
281                                     "JobRunningTimeoutSec=%s",
282                                     program_invocation_short_name,
283                                     opts,
284                                     timeout);
285 }
286 
generator_write_device_deps(const char * dir,const char * what,const char * where,const char * opts)287 int generator_write_device_deps(
288                 const char *dir,
289                 const char *what,
290                 const char *where,
291                 const char *opts) {
292 
293         /* fstab records that specify _netdev option should apply the network
294          * ordering on the actual device depending on network connection. If we
295          * are not mounting real device (NFS, CIFS), we rely on _netdev effect
296          * on the mount unit itself. */
297 
298         _cleanup_free_ char *node = NULL, *unit = NULL;
299         int r;
300 
301         if (fstab_is_extrinsic(where, opts))
302                 return 0;
303 
304         if (!fstab_test_option(opts, "_netdev\0"))
305                 return 0;
306 
307         node = fstab_node_to_udev_node(what);
308         if (!node)
309                 return log_oom();
310 
311         /* Nothing to apply dependencies to. */
312         if (!is_device_path(node))
313                 return 0;
314 
315         r = unit_name_from_path(node, ".device", &unit);
316         if (r < 0)
317                 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
318                                        node);
319 
320         /* See mount_add_default_dependencies for explanation why we create such
321          * dependencies. */
322         return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
323                                     "# Automatically generated by %s\n\n"
324                                     "[Unit]\n"
325                                     "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
326                                     "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
327                                     program_invocation_short_name);
328 }
329 
generator_write_initrd_root_device_deps(const char * dir,const char * what)330 int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
331         _cleanup_free_ char *unit = NULL;
332         int r;
333 
334         r = unit_name_from_path(what, ".device", &unit);
335         if (r < 0)
336                 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
337                                        what);
338 
339         return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
340                                     "# Automatically generated by %s\n\n"
341                                     "[Unit]\n"
342                                     "Requires=%s\n"
343                                     "After=%s",
344                                     program_invocation_short_name,
345                                     unit,
346                                     unit);
347 }
348 
generator_hook_up_mkswap(const char * dir,const char * what)349 int generator_hook_up_mkswap(
350                 const char *dir,
351                 const char *what) {
352 
353         _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
354         _cleanup_fclose_ FILE *f = NULL;
355         const char *unit_file;
356         int r;
357 
358         node = fstab_node_to_udev_node(what);
359         if (!node)
360                 return log_oom();
361 
362         /* Nothing to work on. */
363         if (!is_device_path(node))
364                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
365                                        "Cannot format something that is not a device node: %s",
366                                        node);
367 
368         r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
369         if (r < 0)
370                 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
371                                        node);
372 
373         unit_file = prefix_roota(dir, unit);
374         log_debug("Creating %s", unit_file);
375 
376         escaped = cescape(node);
377         if (!escaped)
378                 return log_oom();
379 
380         r = unit_name_from_path(what, ".swap", &where_unit);
381         if (r < 0)
382                 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
383                                        what);
384 
385         f = fopen(unit_file, "wxe");
386         if (!f)
387                 return log_error_errno(errno, "Failed to create unit file %s: %m",
388                                        unit_file);
389 
390         fprintf(f,
391                 "# Automatically generated by %s\n\n"
392                 "[Unit]\n"
393                 "Description=Make Swap on %%f\n"
394                 "Documentation=man:systemd-mkswap@.service(8)\n"
395                 "DefaultDependencies=no\n"
396                 "BindsTo=%%i.device\n"
397                 "Conflicts=shutdown.target\n"
398                 "After=%%i.device\n"
399                 "Before=shutdown.target %s\n"
400                 "\n"
401                 "[Service]\n"
402                 "Type=oneshot\n"
403                 "RemainAfterExit=yes\n"
404                 "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
405                 "TimeoutSec=0\n",
406                 program_invocation_short_name,
407                 where_unit,
408                 escaped);
409 
410         r = fflush_and_check(f);
411         if (r < 0)
412                 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
413 
414         return generator_add_symlink(dir, where_unit, "requires", unit);
415 }
416 
generator_hook_up_mkfs(const char * dir,const char * what,const char * where,const char * type)417 int generator_hook_up_mkfs(
418                 const char *dir,
419                 const char *what,
420                 const char *where,
421                 const char *type) {
422 
423         _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
424         _cleanup_fclose_ FILE *f = NULL;
425         const char *unit_file;
426         int r;
427 
428         node = fstab_node_to_udev_node(what);
429         if (!node)
430                 return log_oom();
431 
432         /* Nothing to work on. */
433         if (!is_device_path(node))
434                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
435                                        "Cannot format something that is not a device node: %s",
436                                        node);
437 
438         if (!type || streq(type, "auto"))
439                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
440                                        "Cannot format partition %s, filesystem type is not specified",
441                                        node);
442 
443         r = unit_name_from_path_instance("systemd-makefs", node, ".service", &unit);
444         if (r < 0)
445                 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
446                                        node);
447 
448         unit_file = prefix_roota(dir, unit);
449         log_debug("Creating %s", unit_file);
450 
451         escaped = cescape(node);
452         if (!escaped)
453                 return log_oom();
454 
455         r = unit_name_from_path(where, ".mount", &where_unit);
456         if (r < 0)
457                 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
458                                        where);
459 
460         f = fopen(unit_file, "wxe");
461         if (!f)
462                 return log_error_errno(errno, "Failed to create unit file %s: %m",
463                                        unit_file);
464 
465         fprintf(f,
466                 "# Automatically generated by %s\n\n"
467                 "[Unit]\n"
468                 "Description=Make File System on %%f\n"
469                 "Documentation=man:systemd-makefs@.service(8)\n"
470                 "DefaultDependencies=no\n"
471                 "BindsTo=%%i.device\n"
472                 "Conflicts=shutdown.target\n"
473                 "After=%%i.device\n"
474                 /* fsck might or might not be used, so let's be safe and order
475                  * ourselves before both systemd-fsck@.service and the mount unit. */
476                 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
477                 "\n"
478                 "[Service]\n"
479                 "Type=oneshot\n"
480                 "RemainAfterExit=yes\n"
481                 "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
482                 "TimeoutSec=0\n",
483                 program_invocation_short_name,
484                 where_unit,
485                 type,
486                 escaped);
487         // XXX: what about local-fs-pre.target?
488 
489         r = fflush_and_check(f);
490         if (r < 0)
491                 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
492 
493         return generator_add_symlink(dir, where_unit, "requires", unit);
494 }
495 
generator_hook_up_growfs(const char * dir,const char * where,const char * target)496 int generator_hook_up_growfs(
497                 const char *dir,
498                 const char *where,
499                 const char *target) {
500 
501         _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
502         _cleanup_fclose_ FILE *f = NULL;
503         const char *unit_file;
504         int r;
505 
506         assert(dir);
507         assert(where);
508 
509         escaped = cescape(where);
510         if (!escaped)
511                 return log_oom();
512 
513         r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
514         if (r < 0)
515                 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
516                                        where);
517 
518         r = unit_name_from_path(where, ".mount", &where_unit);
519         if (r < 0)
520                 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
521                                        where);
522 
523         unit_file = prefix_roota(dir, unit);
524         log_debug("Creating %s", unit_file);
525 
526         f = fopen(unit_file, "wxe");
527         if (!f)
528                 return log_error_errno(errno, "Failed to create unit file %s: %m",
529                                        unit_file);
530 
531         fprintf(f,
532                 "# Automatically generated by %s\n\n"
533                 "[Unit]\n"
534                 "Description=Grow File System on %%f\n"
535                 "Documentation=man:systemd-growfs@.service(8)\n"
536                 "DefaultDependencies=no\n"
537                 "BindsTo=%%i.mount\n"
538                 "Conflicts=shutdown.target\n"
539                 "After=%%i.mount\n"
540                 "Before=shutdown.target%s%s\n",
541                 program_invocation_short_name,
542                 target ? " " : "",
543                 strempty(target));
544 
545         if (empty_or_root(where)) /* Make sure the root fs is actually writable before we resize it */
546                 fprintf(f,
547                         "After=systemd-remount-fs.service\n");
548 
549         fprintf(f,
550                 "\n"
551                 "[Service]\n"
552                 "Type=oneshot\n"
553                 "RemainAfterExit=yes\n"
554                 "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
555                 "TimeoutSec=0\n",
556                 escaped);
557 
558         return generator_add_symlink(dir, where_unit, "wants", unit);
559 }
560 
generator_enable_remount_fs_service(const char * dir)561 int generator_enable_remount_fs_service(const char *dir) {
562         /* Pull in systemd-remount-fs.service */
563         return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants",
564                                      SYSTEM_DATA_UNIT_DIR "/" SPECIAL_REMOUNT_FS_SERVICE);
565 }
566 
generator_write_blockdev_dependency(FILE * f,const char * what)567 int generator_write_blockdev_dependency(
568                 FILE *f,
569                 const char *what) {
570 
571         _cleanup_free_ char *escaped = NULL;
572         int r;
573 
574         assert(f);
575         assert(what);
576 
577         if (!path_startswith(what, "/dev/"))
578                 return 0;
579 
580         r = unit_name_path_escape(what, &escaped);
581         if (r < 0)
582                 return log_error_errno(r, "Failed to escape device node path %s: %m", what);
583 
584         fprintf(f,
585                 "After=blockdev@%s.target\n",
586                 escaped);
587 
588         return 0;
589 }
590 
generator_write_cryptsetup_unit_section(FILE * f,const char * source)591 int generator_write_cryptsetup_unit_section(
592                 FILE *f,
593                 const char *source) {
594 
595         assert(f);
596 
597         fprintf(f,
598                 "[Unit]\n"
599                 "Description=Cryptography Setup for %%I\n"
600                 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
601 
602         if (source)
603                 fprintf(f, "SourcePath=%s\n", source);
604 
605         fprintf(f,
606                 "DefaultDependencies=no\n"
607                 "IgnoreOnIsolate=true\n"
608                 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
609                 "Before=blockdev@dev-mapper-%%i.target\n"
610                 "Wants=blockdev@dev-mapper-%%i.target\n");
611 
612         return 0;
613 }
614 
generator_write_cryptsetup_service_section(FILE * f,const char * name,const char * what,const char * key_file,const char * options)615 int generator_write_cryptsetup_service_section(
616                 FILE *f,
617                 const char *name,
618                 const char *what,
619                 const char *key_file,
620                 const char *options) {
621 
622         _cleanup_free_ char *name_escaped = NULL, *what_escaped = NULL, *key_file_escaped = NULL, *options_escaped = NULL;
623 
624         assert(f);
625         assert(name);
626         assert(what);
627 
628         name_escaped = specifier_escape(name);
629         if (!name_escaped)
630                 return log_oom();
631 
632         what_escaped = specifier_escape(what);
633         if (!what_escaped)
634                 return log_oom();
635 
636         if (key_file) {
637                 key_file_escaped = specifier_escape(key_file);
638                 if (!key_file_escaped)
639                         return log_oom();
640         }
641 
642         if (options) {
643                 options_escaped = specifier_escape(options);
644                 if (!options_escaped)
645                         return log_oom();
646         }
647 
648         fprintf(f,
649                 "\n"
650                 "[Service]\n"
651                 "Type=oneshot\n"
652                 "RemainAfterExit=yes\n"
653                 "TimeoutSec=0\n"          /* The binary handles timeouts on its own */
654                 "KeyringMode=shared\n"    /* Make sure we can share cached keys among instances */
655                 "OOMScoreAdjust=500\n"    /* Unlocking can allocate a lot of memory if Argon2 is used */
656                 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
657                 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
658                 name_escaped, what_escaped, strempty(key_file_escaped), strempty(options_escaped),
659                 name_escaped);
660 
661         return 0;
662 }
663 
generator_write_veritysetup_unit_section(FILE * f,const char * source)664 int generator_write_veritysetup_unit_section(
665                 FILE *f,
666                 const char *source) {
667 
668         assert(f);
669 
670         fprintf(f,
671                 "[Unit]\n"
672                 "Description=Integrity Protection Setup for %%I\n"
673                 "Documentation=man:veritytab(5) man:systemd-veritysetup-generator(8) man:systemd-veritysetup@.service(8)\n");
674 
675         if (source)
676                 fprintf(f, "SourcePath=%s\n", source);
677 
678         fprintf(f,
679                 "DefaultDependencies=no\n"
680                 "IgnoreOnIsolate=true\n"
681                 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
682                 "Before=blockdev@dev-mapper-%%i.target\n"
683                 "Wants=blockdev@dev-mapper-%%i.target\n");
684 
685         return 0;
686 }
687 
generator_write_veritysetup_service_section(FILE * f,const char * name,const char * data_what,const char * hash_what,const char * roothash,const char * options)688 int generator_write_veritysetup_service_section(
689                 FILE *f,
690                 const char *name,
691                 const char *data_what,
692                 const char *hash_what,
693                 const char *roothash,
694                 const char *options) {
695 
696         _cleanup_free_ char *name_escaped = NULL, *data_what_escaped = NULL, *hash_what_escaped = NULL,
697                             *roothash_escaped = NULL, *options_escaped = NULL;
698 
699         assert(f);
700         assert(name);
701         assert(data_what);
702         assert(hash_what);
703 
704         name_escaped = specifier_escape(name);
705         if (!name_escaped)
706                 return log_oom();
707 
708         data_what_escaped = specifier_escape(data_what);
709         if (!data_what_escaped)
710                 return log_oom();
711 
712         hash_what_escaped = specifier_escape(hash_what);
713         if (!hash_what_escaped)
714                 return log_oom();
715 
716         roothash_escaped = specifier_escape(roothash);
717         if (!roothash_escaped)
718                 return log_oom();
719 
720         if (options) {
721                 options_escaped = specifier_escape(options);
722                 if (!options_escaped)
723                         return log_oom();
724         }
725 
726         fprintf(f,
727                 "\n"
728                 "[Service]\n"
729                 "Type=oneshot\n"
730                 "RemainAfterExit=yes\n"
731                 "ExecStart=" SYSTEMD_VERITYSETUP_PATH " attach '%s' '%s' '%s' '%s' '%s'\n"
732                 "ExecStop=" SYSTEMD_VERITYSETUP_PATH " detach '%s'\n",
733                 name_escaped, data_what_escaped, hash_what_escaped, roothash_escaped, strempty(options_escaped),
734                 name_escaped);
735 
736         return 0;
737 }
738 
log_setup_generator(void)739 void log_setup_generator(void) {
740         /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
741         if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */)
742                 log_set_prohibit_ipc(true);
743 
744         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); /* This effectively means: journal for per-user generators, kmsg otherwise */
745         log_parse_environment();
746         (void) log_open();
747 }
748