]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
d2c68822 | 2 | |
b5efdb8a | 3 | #include "alloc-util.h" |
ff757c9d | 4 | #include "dropin.h" |
afe44c8f | 5 | #include "generator.h" |
a628d933 | 6 | #include "hibernate-resume-config.h" |
baa6a42d | 7 | #include "initrd-util.h" |
d2c68822 | 8 | #include "log.h" |
77182cc6 | 9 | #include "main-func.h" |
760e99bb | 10 | #include "parse-util.h" |
4e731273 | 11 | #include "proc-cmdline.h" |
07630cea | 12 | #include "special.h" |
a628d933 | 13 | #include "static-destruct.h" |
07630cea | 14 | #include "string-util.h" |
d2c68822 IS |
15 | #include "unit-name.h" |
16 | ||
b8110a3e | 17 | static const char *arg_dest = NULL; |
8b6805a2 | 18 | static char *arg_resume_options = NULL; |
70e843fe | 19 | static char *arg_root_options = NULL; |
e83419d0 | 20 | static bool arg_noresume = false; |
d2c68822 | 21 | |
8b6805a2 | 22 | STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep); |
70e843fe | 23 | STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep); |
77182cc6 | 24 | |
96287a49 | 25 | static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { |
a8d3315b YW |
26 | assert(key); |
27 | ||
a628d933 | 28 | if (streq(key, "resumeflags")) { |
8b6805a2 JR |
29 | |
30 | if (proc_cmdline_value_missing(key, value)) | |
31 | return 0; | |
32 | ||
c2bc710b | 33 | if (!strextend_with_separator(&arg_resume_options, ",", value)) |
8b6805a2 JR |
34 | return log_oom(); |
35 | ||
a8d3315b | 36 | } else if (streq(key, "rootflags")) { |
70e843fe JR |
37 | |
38 | if (proc_cmdline_value_missing(key, value)) | |
39 | return 0; | |
40 | ||
c2bc710b | 41 | if (!strextend_with_separator(&arg_root_options, ",", value)) |
70e843fe JR |
42 | return log_oom(); |
43 | ||
a8d3315b YW |
44 | } else if (streq(key, "noresume")) { |
45 | ||
e83419d0 | 46 | if (value) { |
a628d933 | 47 | log_warning("'noresume' kernel command line option specified with an argument, ignoring."); |
e83419d0 ZJS |
48 | return 0; |
49 | } | |
50 | ||
51 | arg_noresume = true; | |
d2c68822 IS |
52 | } |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
6cfce71b | 57 | static int process_resume(const HibernateInfo *info) { |
a628d933 | 58 | _cleanup_free_ char *device_unit = NULL; |
7410616c | 59 | int r; |
d2c68822 | 60 | |
6cfce71b | 61 | assert(info); |
b5884878 | 62 | |
6cfce71b | 63 | r = unit_name_from_path(info->device, ".device", &device_unit); |
ff757c9d | 64 | if (r < 0) |
6cfce71b | 65 | return log_error_errno(r, "Failed to generate device unit name from path '%s': %m", info->device); |
ff757c9d | 66 | |
6cfce71b MY |
67 | /* If hibernate info is acquired from EFI variable, don't wait forever by default. Otherwise, if |
68 | * swap device is not present and HibernateLocation was not correctly cleared, we end up blocking | |
69 | * the boot process infinitely. */ | |
70 | r = write_drop_in_format(arg_dest, device_unit, 40, "device-timeout", | |
71 | "# Automatically generated by systemd-hibernate-resume-generator\n\n" | |
72 | "[Unit]\n" | |
73 | "JobTimeoutSec=%s\n", | |
74 | info->cmdline ? "infinity" : "2min"); | |
ff757c9d | 75 | if (r < 0) |
760e99bb MY |
76 | log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m"); |
77 | ||
ff757c9d | 78 | r = generator_write_timeouts(arg_dest, |
6cfce71b MY |
79 | info->device, |
80 | info->device, | |
ff757c9d ZJS |
81 | arg_resume_options ?: arg_root_options, |
82 | NULL); | |
70e843fe | 83 | if (r < 0) |
a628d933 | 84 | log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m"); |
70e843fe | 85 | |
a628d933 MY |
86 | r = write_drop_in_format(arg_dest, SPECIAL_HIBERNATE_RESUME_SERVICE, 90, "device-dependency", |
87 | "# Automatically generated by systemd-hibernate-resume-generator\n\n" | |
88 | "[Unit]\n" | |
89 | "BindsTo=%1$s\n" | |
90 | "After=%1$s\n", | |
91 | device_unit); | |
92 | if (r < 0) | |
93 | return log_error_errno(r, "Failed to write device dependency drop-in: %m"); | |
94 | ||
95 | return generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SPECIAL_HIBERNATE_RESUME_SERVICE); | |
d2c68822 IS |
96 | } |
97 | ||
b8110a3e | 98 | static int run(const char *dest, const char *dest_early, const char *dest_late) { |
a628d933 | 99 | _cleanup_(hibernate_info_done) HibernateInfo info = {}; |
760e99bb | 100 | int r; |
d2c68822 | 101 | |
b8110a3e | 102 | arg_dest = ASSERT_PTR(dest); |
d2c68822 | 103 | |
32e27670 | 104 | /* Don't even consider resuming outside of initrd. */ |
a79858bf | 105 | if (!in_initrd()) { |
a628d933 | 106 | log_debug("Not running in initrd, exiting."); |
77182cc6 | 107 | return 0; |
a79858bf | 108 | } |
d2c68822 | 109 | |
1d84ad94 | 110 | r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0); |
b5884878 | 111 | if (r < 0) |
da927ba9 | 112 | log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); |
d2c68822 | 113 | |
e83419d0 | 114 | if (arg_noresume) { |
a628d933 | 115 | log_info("Found 'noresume' on the kernel command line, exiting."); |
77182cc6 | 116 | return 0; |
e83419d0 ZJS |
117 | } |
118 | ||
a628d933 MY |
119 | r = acquire_hibernate_info(&info); |
120 | if (r == -ENODEV) { | |
121 | log_debug_errno(r, "No resume device found, exiting."); | |
122 | return 0; | |
123 | } | |
124 | if (r < 0) | |
9deeca12 MY |
125 | return r; |
126 | ||
6cfce71b | 127 | return process_resume(&info); |
d2c68822 | 128 | } |
77182cc6 | 129 | |
b8110a3e | 130 | DEFINE_MAIN_GENERATOR_FUNCTION(run); |