]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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" |
6550203e | 8 | #include "fstab-util.h" |
afe44c8f | 9 | #include "generator.h" |
d2c68822 | 10 | #include "log.h" |
77182cc6 | 11 | #include "main-func.h" |
d2c68822 | 12 | #include "mkdir.h" |
4e731273 | 13 | #include "proc-cmdline.h" |
07630cea LP |
14 | #include "special.h" |
15 | #include "string-util.h" | |
d2c68822 IS |
16 | #include "unit-name.h" |
17 | ||
18 | static const char *arg_dest = "/tmp"; | |
1d84ad94 | 19 | static char *arg_resume_device = NULL; |
8b6805a2 | 20 | static char *arg_resume_options = NULL; |
70e843fe | 21 | static char *arg_root_options = NULL; |
e83419d0 | 22 | static bool arg_noresume = false; |
d2c68822 | 23 | |
77182cc6 | 24 | STATIC_DESTRUCTOR_REGISTER(arg_resume_device, freep); |
8b6805a2 | 25 | STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep); |
70e843fe | 26 | STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep); |
77182cc6 | 27 | |
96287a49 | 28 | static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { |
7410616c | 29 | |
1d84ad94 LP |
30 | if (streq(key, "resume")) { |
31 | char *s; | |
32 | ||
33 | if (proc_cmdline_value_missing(key, value)) | |
34 | return 0; | |
35 | ||
36 | s = fstab_node_to_udev_node(value); | |
37 | if (!s) | |
d2c68822 | 38 | return log_oom(); |
1d84ad94 | 39 | |
e83419d0 ZJS |
40 | free_and_replace(arg_resume_device, s); |
41 | ||
8b6805a2 JR |
42 | } else if (streq(key, "resumeflags")) { |
43 | ||
44 | if (proc_cmdline_value_missing(key, value)) | |
45 | return 0; | |
46 | ||
47 | if (!strextend_with_separator(&arg_resume_options, ",", value, NULL)) | |
48 | return log_oom(); | |
49 | ||
70e843fe JR |
50 | } else if (streq(key, "rootflags")) { |
51 | ||
52 | if (proc_cmdline_value_missing(key, value)) | |
53 | return 0; | |
54 | ||
55 | if (!strextend_with_separator(&arg_root_options, ",", value, NULL)) | |
56 | return log_oom(); | |
57 | ||
e83419d0 ZJS |
58 | } else if (streq(key, "noresume")) { |
59 | if (value) { | |
60 | log_warning("\"noresume\" kernel command line switch specified with an argument, ignoring."); | |
61 | return 0; | |
62 | } | |
63 | ||
64 | arg_noresume = true; | |
d2c68822 IS |
65 | } |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
70 | static int process_resume(void) { | |
71 | _cleanup_free_ char *name = NULL, *lnk = NULL; | |
8b6805a2 | 72 | const char *opts; |
7410616c | 73 | int r; |
d2c68822 | 74 | |
1d84ad94 | 75 | if (!arg_resume_device) |
b5884878 LP |
76 | return 0; |
77 | ||
1d84ad94 | 78 | r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service", &name); |
7410616c LP |
79 | if (r < 0) |
80 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
d2c68822 | 81 | |
605405c6 | 82 | lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", name); |
d2c68822 IS |
83 | if (!lnk) |
84 | return log_oom(); | |
85 | ||
86 | mkdir_parents_label(lnk, 0755); | |
4a62c710 MS |
87 | if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-hibernate-resume@.service", lnk) < 0) |
88 | return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); | |
d2c68822 | 89 | |
8b6805a2 JR |
90 | if (arg_resume_options) |
91 | opts = arg_resume_options; | |
92 | else | |
93 | opts = arg_root_options; | |
94 | ||
95 | r = generator_write_timeouts(arg_dest, arg_resume_device, arg_resume_device, opts, NULL); | |
70e843fe JR |
96 | if (r < 0) |
97 | return r; | |
98 | ||
d2c68822 IS |
99 | return 0; |
100 | } | |
101 | ||
77182cc6 | 102 | static int run(int argc, char *argv[]) { |
d2c68822 IS |
103 | int r = 0; |
104 | ||
afe44c8f | 105 | log_setup_generator(); |
a79858bf | 106 | |
baaa35ad ZJS |
107 | if (argc > 1 && argc != 4) |
108 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
109 | "This program takes three or no arguments."); | |
d2c68822 IS |
110 | |
111 | if (argc > 1) | |
112 | arg_dest = argv[1]; | |
113 | ||
d2c68822 | 114 | /* Don't even consider resuming outside of initramfs. */ |
a79858bf ZJS |
115 | if (!in_initrd()) { |
116 | log_debug("Not running in an initrd, quitting."); | |
77182cc6 | 117 | return 0; |
a79858bf | 118 | } |
d2c68822 | 119 | |
1d84ad94 | 120 | r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0); |
b5884878 | 121 | if (r < 0) |
da927ba9 | 122 | log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); |
d2c68822 | 123 | |
e83419d0 ZJS |
124 | if (arg_noresume) { |
125 | log_notice("Found \"noresume\" on the kernel command line, quitting."); | |
77182cc6 | 126 | return 0; |
e83419d0 ZJS |
127 | } |
128 | ||
77182cc6 | 129 | return process_resume(); |
d2c68822 | 130 | } |
77182cc6 YW |
131 | |
132 | DEFINE_MAIN_FUNCTION(run); |