]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
d2c68822 | 2 | |
d2c68822 | 3 | #include <errno.h> |
07630cea | 4 | #include <stdio.h> |
ca78ad1d | 5 | #include <unistd.h> |
d2c68822 | 6 | |
b5efdb8a | 7 | #include "alloc-util.h" |
ff757c9d | 8 | #include "dropin.h" |
6550203e | 9 | #include "fstab-util.h" |
afe44c8f | 10 | #include "generator.h" |
baa6a42d | 11 | #include "initrd-util.h" |
d2c68822 | 12 | #include "log.h" |
77182cc6 | 13 | #include "main-func.h" |
35cd0ba5 | 14 | #include "mkdir-label.h" |
4e731273 | 15 | #include "proc-cmdline.h" |
07630cea LP |
16 | #include "special.h" |
17 | #include "string-util.h" | |
d2c68822 IS |
18 | #include "unit-name.h" |
19 | ||
b8110a3e | 20 | static const char *arg_dest = NULL; |
1d84ad94 | 21 | static char *arg_resume_device = NULL; |
8b6805a2 | 22 | static char *arg_resume_options = NULL; |
70e843fe | 23 | static char *arg_root_options = NULL; |
e83419d0 | 24 | static bool arg_noresume = false; |
d2c68822 | 25 | |
77182cc6 | 26 | STATIC_DESTRUCTOR_REGISTER(arg_resume_device, freep); |
8b6805a2 | 27 | STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep); |
70e843fe | 28 | STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep); |
77182cc6 | 29 | |
96287a49 | 30 | static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { |
7410616c | 31 | |
1d84ad94 LP |
32 | if (streq(key, "resume")) { |
33 | char *s; | |
34 | ||
35 | if (proc_cmdline_value_missing(key, value)) | |
36 | return 0; | |
37 | ||
38 | s = fstab_node_to_udev_node(value); | |
39 | if (!s) | |
d2c68822 | 40 | return log_oom(); |
1d84ad94 | 41 | |
e83419d0 ZJS |
42 | free_and_replace(arg_resume_device, s); |
43 | ||
8b6805a2 JR |
44 | } else if (streq(key, "resumeflags")) { |
45 | ||
46 | if (proc_cmdline_value_missing(key, value)) | |
47 | return 0; | |
48 | ||
c2bc710b | 49 | if (!strextend_with_separator(&arg_resume_options, ",", value)) |
8b6805a2 JR |
50 | return log_oom(); |
51 | ||
70e843fe JR |
52 | } else if (streq(key, "rootflags")) { |
53 | ||
54 | if (proc_cmdline_value_missing(key, value)) | |
55 | return 0; | |
56 | ||
c2bc710b | 57 | if (!strextend_with_separator(&arg_root_options, ",", value)) |
70e843fe JR |
58 | return log_oom(); |
59 | ||
e83419d0 ZJS |
60 | } else if (streq(key, "noresume")) { |
61 | if (value) { | |
62 | log_warning("\"noresume\" kernel command line switch specified with an argument, ignoring."); | |
63 | return 0; | |
64 | } | |
65 | ||
66 | arg_noresume = true; | |
d2c68822 IS |
67 | } |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | static int process_resume(void) { | |
ff757c9d | 73 | _cleanup_free_ char *service_unit = NULL, *device_unit = NULL, *lnk = NULL; |
7410616c | 74 | int r; |
d2c68822 | 75 | |
1d84ad94 | 76 | if (!arg_resume_device) |
b5884878 LP |
77 | return 0; |
78 | ||
ff757c9d ZJS |
79 | r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service", |
80 | &service_unit); | |
7410616c LP |
81 | if (r < 0) |
82 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
d2c68822 | 83 | |
ff757c9d | 84 | lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", service_unit); |
d2c68822 IS |
85 | if (!lnk) |
86 | return log_oom(); | |
87 | ||
35cd0ba5 | 88 | (void) mkdir_parents_label(lnk, 0755); |
835cf75a | 89 | if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-hibernate-resume@.service", lnk) < 0) |
4a62c710 | 90 | return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); |
d2c68822 | 91 | |
ff757c9d ZJS |
92 | r = unit_name_from_path(arg_resume_device, ".device", &device_unit); |
93 | if (r < 0) | |
94 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
95 | ||
96 | r = write_drop_in(arg_dest, device_unit, 40, "device-timeout", | |
90198bcb | 97 | "# Automatically generated by systemd-hibernate-resume-generator\n\n" |
ff757c9d ZJS |
98 | "[Unit]\nJobTimeoutSec=0"); |
99 | if (r < 0) | |
100 | log_warning_errno(r, "Failed to write device timeout drop-in: %m"); | |
8b6805a2 | 101 | |
ff757c9d ZJS |
102 | r = generator_write_timeouts(arg_dest, |
103 | arg_resume_device, | |
104 | arg_resume_device, | |
105 | arg_resume_options ?: arg_root_options, | |
106 | NULL); | |
70e843fe JR |
107 | if (r < 0) |
108 | return r; | |
109 | ||
d2c68822 IS |
110 | return 0; |
111 | } | |
112 | ||
b8110a3e | 113 | static int run(const char *dest, const char *dest_early, const char *dest_late) { |
d2c68822 IS |
114 | int r = 0; |
115 | ||
b8110a3e | 116 | arg_dest = ASSERT_PTR(dest); |
d2c68822 | 117 | |
32e27670 | 118 | /* Don't even consider resuming outside of initrd. */ |
a79858bf ZJS |
119 | if (!in_initrd()) { |
120 | log_debug("Not running in an initrd, quitting."); | |
77182cc6 | 121 | return 0; |
a79858bf | 122 | } |
d2c68822 | 123 | |
1d84ad94 | 124 | r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0); |
b5884878 | 125 | if (r < 0) |
da927ba9 | 126 | log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); |
d2c68822 | 127 | |
e83419d0 ZJS |
128 | if (arg_noresume) { |
129 | log_notice("Found \"noresume\" on the kernel command line, quitting."); | |
77182cc6 | 130 | return 0; |
e83419d0 ZJS |
131 | } |
132 | ||
77182cc6 | 133 | return process_resume(); |
d2c68822 | 134 | } |
77182cc6 | 135 | |
b8110a3e | 136 | DEFINE_MAIN_GENERATOR_FUNCTION(run); |