]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/hibernate-resume/hibernate-resume-generator.c
f3b668ccdae266687fc254e01cc4b4db5de2950c
[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_root_options = NULL;
21 static bool arg_noresume = false;
22
23 STATIC_DESTRUCTOR_REGISTER(arg_resume_device, freep);
24 STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
25
26 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
27
28 if (streq(key, "resume")) {
29 char *s;
30
31 if (proc_cmdline_value_missing(key, value))
32 return 0;
33
34 s = fstab_node_to_udev_node(value);
35 if (!s)
36 return log_oom();
37
38 free_and_replace(arg_resume_device, s);
39
40 } else if (streq(key, "rootflags")) {
41
42 if (proc_cmdline_value_missing(key, value))
43 return 0;
44
45 if (!strextend_with_separator(&arg_root_options, ",", value, NULL))
46 return log_oom();
47
48 } else if (streq(key, "noresume")) {
49 if (value) {
50 log_warning("\"noresume\" kernel command line switch specified with an argument, ignoring.");
51 return 0;
52 }
53
54 arg_noresume = true;
55 }
56
57 return 0;
58 }
59
60 static int process_resume(void) {
61 _cleanup_free_ char *name = NULL, *lnk = NULL;
62 int r;
63
64 if (!arg_resume_device)
65 return 0;
66
67 r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service", &name);
68 if (r < 0)
69 return log_error_errno(r, "Failed to generate unit name: %m");
70
71 lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", name);
72 if (!lnk)
73 return log_oom();
74
75 mkdir_parents_label(lnk, 0755);
76 if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-hibernate-resume@.service", lnk) < 0)
77 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
78
79 r = generator_write_timeouts(arg_dest, arg_resume_device, arg_resume_device, arg_root_options, NULL);
80 if (r < 0)
81 return r;
82
83 return 0;
84 }
85
86 static int run(int argc, char *argv[]) {
87 int r = 0;
88
89 log_setup_generator();
90
91 if (argc > 1 && argc != 4)
92 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
93 "This program takes three or no arguments.");
94
95 if (argc > 1)
96 arg_dest = argv[1];
97
98 /* Don't even consider resuming outside of initramfs. */
99 if (!in_initrd()) {
100 log_debug("Not running in an initrd, quitting.");
101 return 0;
102 }
103
104 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
105 if (r < 0)
106 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
107
108 if (arg_noresume) {
109 log_notice("Found \"noresume\" on the kernel command line, quitting.");
110 return 0;
111 }
112
113 return process_resume();
114 }
115
116 DEFINE_MAIN_FUNCTION(run);