]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/hibernate-resume/hibernate-resume-generator.c
Merge pull request #12753 from jrouleau/fix/hibernate-resume-timeout
[thirdparty/systemd.git] / src / hibernate-resume / hibernate-resume-generator.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <stdio.h>
5 #include <unistd.h>
6
7 #include "alloc-util.h"
8 #include "fstab-util.h"
9 #include "generator.h"
10 #include "log.h"
11 #include "main-func.h"
12 #include "mkdir.h"
13 #include "proc-cmdline.h"
14 #include "special.h"
15 #include "string-util.h"
16 #include "unit-name.h"
17
18 static const char *arg_dest = "/tmp";
19 static char *arg_resume_device = NULL;
20 static char *arg_resume_options = NULL;
21 static char *arg_root_options = NULL;
22 static bool arg_noresume = false;
23
24 STATIC_DESTRUCTOR_REGISTER(arg_resume_device, freep);
25 STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep);
26 STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
27
28 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
29
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)
38 return log_oom();
39
40 free_and_replace(arg_resume_device, s);
41
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
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
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;
65 }
66
67 return 0;
68 }
69
70 static int process_resume(void) {
71 _cleanup_free_ char *name = NULL, *lnk = NULL;
72 const char *opts;
73 int r;
74
75 if (!arg_resume_device)
76 return 0;
77
78 r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service", &name);
79 if (r < 0)
80 return log_error_errno(r, "Failed to generate unit name: %m");
81
82 lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", name);
83 if (!lnk)
84 return log_oom();
85
86 mkdir_parents_label(lnk, 0755);
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);
89
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);
96 if (r < 0)
97 return r;
98
99 return 0;
100 }
101
102 static int run(int argc, char *argv[]) {
103 int r = 0;
104
105 log_setup_generator();
106
107 if (argc > 1 && argc != 4)
108 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
109 "This program takes three or no arguments.");
110
111 if (argc > 1)
112 arg_dest = argv[1];
113
114 /* Don't even consider resuming outside of initramfs. */
115 if (!in_initrd()) {
116 log_debug("Not running in an initrd, quitting.");
117 return 0;
118 }
119
120 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
121 if (r < 0)
122 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
123
124 if (arg_noresume) {
125 log_notice("Found \"noresume\" on the kernel command line, quitting.");
126 return 0;
127 }
128
129 return process_resume();
130 }
131
132 DEFINE_MAIN_FUNCTION(run);