summaryrefslogtreecommitdiffstats
path: root/src/hibernate-resume/hibernate-resume.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hibernate-resume/hibernate-resume.c')
-rw-r--r--src/hibernate-resume/hibernate-resume.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
new file mode 100644
index 0000000..175a0bd
--- /dev/null
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "devnum-util.h"
+#include "hibernate-resume-config.h"
+#include "hibernate-util.h"
+#include "initrd-util.h"
+#include "log.h"
+#include "main-func.h"
+#include "parse-util.h"
+#include "static-destruct.h"
+
+static HibernateInfo arg_info = {};
+
+STATIC_DESTRUCTOR_REGISTER(arg_info, hibernate_info_done);
+
+static int setup_hibernate_info_and_warn(void) {
+ int r;
+
+ r = acquire_hibernate_info(&arg_info);
+ if (r == -ENODEV) {
+ log_info_errno(r, "No resume device found, exiting.");
+ return 0;
+ }
+ if (r < 0)
+ return r;
+
+ compare_hibernate_location_and_warn(&arg_info);
+
+ return 1;
+}
+
+static int run(int argc, char *argv[]) {
+ struct stat st;
+ int r;
+
+ log_setup();
+
+ if (argc < 1 || argc > 3)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects zero, one, or two arguments.");
+
+ umask(0022);
+
+ if (!in_initrd())
+ return 0;
+
+ if (argc > 1) {
+ arg_info.device = argv[1];
+
+ if (argc == 3) {
+ r = safe_atou64(argv[2], &arg_info.offset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[2]);
+ }
+ } else {
+ r = setup_hibernate_info_and_warn();
+ if (r <= 0)
+ return r;
+
+ if (arg_info.efi)
+ clear_efi_hibernate_location();
+ }
+
+ if (stat(arg_info.device, &st) < 0)
+ return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_info.device);
+
+ if (!S_ISBLK(st.st_mode))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Resume device '%s' is not a block device.", arg_info.device);
+
+ /* The write shall not return if a resume takes place. */
+ r = write_resume_config(st.st_rdev, arg_info.offset, arg_info.device);
+ log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG,
+ r < 0 ? r : SYNTHETIC_ERRNO(ENOENT),
+ "Unable to resume from device '%s' (" DEVNUM_FORMAT_STR ") offset %" PRIu64 ", continuing boot process.",
+ arg_info.device, DEVNUM_FORMAT_VAL(st.st_rdev), arg_info.offset);
+
+ return r;
+}
+
+DEFINE_MAIN_FUNCTION(run);