Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling hibernation-setup-tool, hibernate and resume services #7

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Changes from 6 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d799ef4
Enabled service
ishaansehgal99 Jul 6, 2022
4551a79
Ensure directories created and files linked for service to run
ishaansehgal99 Jul 6, 2022
630be4f
Added optional arugments and permissions for tool and service file
ishaansehgal99 Jul 6, 2022
b70ad46
Delete
ishaansehgal99 Jul 6, 2022
8042081
Corrected link error. Named file
ishaansehgal99 Jul 7, 2022
361cc48
Ensured file was created not directory
ishaansehgal99 Jul 12, 2022
7938c45
Detect hibernate/resume using hooks. Ensure services files enabled an…
ishaansehgal99 Jul 25, 2022
9b15002
Cleaned up comments. Simplified check for is cold booted.
ishaansehgal99 Jul 26, 2022
7fd4005
Clean
ishaansehgal99 Jul 26, 2022
5f41ec3
Merge branch 'main' of https://github.com/microsoft/hibernation-setup…
ishaansehgal99 Jul 26, 2022
c1c6676
remove comment
ishaansehgal99 Jul 26, 2022
b2f191a
Removed additional conditional
ishaansehgal99 Jul 26, 2022
9f31117
Added comment
ishaansehgal99 Jul 27, 2022
4816cc8
Added tool and hook prefixes for better logging
ishaansehgal99 Jul 27, 2022
88dc86b
Minor logging addition
ishaansehgal99 Jul 28, 2022
583269d
Added log_notice log ability
ishaansehgal99 Aug 2, 2022
c365ce9
Merge branch 'main' of https://github.com/microsoft/hibernation-setup…
ishaansehgal99 Aug 2, 2022
77a73fd
Explicit check nftw succeeds
ishaansehgal99 Aug 2, 2022
3100c41
Formatting
ishaansehgal99 Aug 2, 2022
f58f229
Added failed hibernation state
ishaansehgal99 Aug 6, 2022
3e247ea
Merge branch 'main' of https://github.com/microsoft/hibernation-setup…
ishaansehgal99 Aug 8, 2022
ab98b8e
Resolve merge condflicts
ishaansehgal99 Aug 8, 2022
c33297f
Renamed enable_systemd_service function
ishaansehgal99 Aug 8, 2022
3f29064
Merge branch 'main' of https://github.com/microsoft/hibernation-setup…
ishaansehgal99 Aug 8, 2022
9c9a703
Fixed minor formatting
ishaansehgal99 Aug 8, 2022
9fe83d8
Added check to prevent re-enabling services if they have been enabled…
ishaansehgal99 Aug 10, 2022
d8df3c6
Disabling pre/post hibernate hooks if either fails to enable
ishaansehgal99 Aug 15, 2022
42100c1
Ensure prehook is always enabled
ishaansehgal99 Aug 18, 2022
6f2c0b1
Code for enabling/disabling post hooks in pre hooks
ishaansehgal99 Aug 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 113 additions & 9 deletions hibernation-setup-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1644,15 +1644,105 @@ static int handle_systemd_suspend_notification(const char *argv0, const char *wh
return 1;
}

static void link_hook(const char *src, const char *dest)
static bool link_hook(const char *src, const char *dest)
{
if (link(src, dest) < 0) {
if (errno != EEXIST)
return log_fatal("Couldn't link %s to %s: %s", src, dest, strerror(errno));
return false;
}

log_info("Notifying systemd of new hooks");
spawn_and_wait("systemctl", 1, "daemon-reload");
return true;
}

static void optional_params(int argc, char **argv, char **action, char **when, char **dest_dir) {
if (argc > 2) {
int opt;
while ((opt = getopt(argc, argv, "adw:")) != -1)
{
switch (opt)
{
case 'a':
*action = optarg;
break;

case 'w':
*when = optarg;
break;

case 'd':
*dest_dir = optarg;
break;
}
}
}
}

static bool ensure_systemd_service_enabled(char *dest_dir){
const char *execfn = (const char *)getauxval(AT_EXECFN);
const char *usr_sbin_default = "/usr/sbin", *systemd_dir_default = "/lib/systemd/system";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also usr/lib/systemd/system based on the distro?

Copy link
Contributor Author

@ishaansehgal99 ishaansehgal99 Aug 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Ubuntu /usr/lib and /lib and different directories. On Ubuntu, /usr/lib is a user-based directory to store things that require access to libraries. The /lib folder is the actual place for essential standard libraries. We need to put our services in this directory in order to access the targets we need (hibernate.target) and for systemd to recognize us as a legitimate service.

After testing on Debian, Rhel and CentOS, the /usr/lib and /lib directories are identical for each of them. On each of them lib is a symbolic link pointing to /usr/lib. In other words, /lib and /usr/lib go to the same place.

/lib is preferred because it includes ubuntu and so works on all distros.

Additional testing: On Debian tool executes without any issues.

However, Rhel has the additional challenges of not having enough space on root "/" partition no matter how much space it's created with. This causes the free space check to prevent tool from running, and if that check is removed, it causes insufficient space error upon allocating hibfile.


const char *hibernation_tool_name = "hibernation-setup-tool";
const char *hibernation_service_name = "hibernation-setup-tool.service";

char usr_sbin_dir[PATH_MAX], systemd_dir[PATH_MAX];
char usr_sbin_path[PATH_MAX], systemd_path[PATH_MAX];

if (dest_dir) {
snprintf(usr_sbin_dir, sizeof(usr_sbin_dir), "%s%s", dest_dir, usr_sbin_default);
snprintf(systemd_dir, sizeof(systemd_dir), "%s%s", dest_dir, systemd_dir_default);
} else {
snprintf(usr_sbin_dir, sizeof(usr_sbin_dir), "%s", usr_sbin_default);
snprintf(systemd_dir, sizeof(systemd_dir), "%s", systemd_dir_default);
}

snprintf(usr_sbin_path, sizeof(usr_sbin_path), "%s%s%s", usr_sbin_dir, "/", hibernation_tool_name);
snprintf(systemd_path, sizeof(systemd_path), "%s%s%s", systemd_dir, "/", hibernation_service_name);

char *tool_mode_str = "0755", *service_mode_str = "0644";
int tool_mode = strtol(tool_mode_str, 0, 8), service_mode = strtol(service_mode_str, 0, 8);

if (!mkdir(usr_sbin_dir, 0755) && errno != EEXIST) {
log_info("Couldn't create location to store hibernation setup tool executable: %s", strerror(errno));
return false;
}

if (chmod(execfn, tool_mode) < 0){
log_info("Couldn't set permissions of %s to %s: %s", execfn, tool_mode_str, strerror(errno));
return false;
}

if (link(execfn, usr_sbin_path) < 0 && errno != EEXIST) {
log_info("Couldn't link %s to %s: %s", execfn, usr_sbin_path, strerror(errno));
return false;
}

if(!mkdir(systemd_dir, 0755) && errno != EEXIST) {
log_info("Couldn't create location to store hibernation setup tool service: %s", strerror(errno));
return false;
}

char* last_slash = strrchr(execfn, '/');
if(last_slash == NULL)
return false;
*last_slash = '\0';

char service_path[PATH_MAX];
snprintf(service_path, sizeof(service_path), "%s%s%s", execfn, "/", hibernation_service_name);

if(chmod(service_path, service_mode) < 0){
log_info("Couldn't set permissions of %s to %s: %s", service_path, service_mode_str, strerror(errno));
return false;
}

if(!link_hook(service_path, systemd_path)){
log_info("Couldn't link %s to %s: %s", service_path, systemd_path, strerror(errno));
return false;
}

spawn_and_wait("systemctl", 2, "enable", hibernation_service_name);
ishaansehgal99 marked this conversation as resolved.
Show resolved Hide resolved
return true;
}

static void ensure_systemd_hooks_are_set_up(void)
Expand Down Expand Up @@ -1688,13 +1778,19 @@ static void ensure_systemd_hooks_are_set_up(void)
return;
}

if (execfn)
return link_hook(execfn, location_to_link);
if (execfn) {
if(!link_hook(execfn, location_to_link))
log_fatal("Couldn't link %s to %s: %s", execfn, location_to_link, strerror(errno));
return;
}

char self_path_buf[PATH_MAX];
const char *self_path = readlink0("/proc/self/exe", self_path_buf);
if (self_path)
return link_hook(self_path, location_to_link);
if (self_path) {
if(!link_hook(self_path, location_to_link))
log_fatal("Couldn't link %s to %s: %s", self_path, location_to_link, strerror(errno));
return;
}

return log_fatal("Both getauxval() and readlink(/proc/self/exe) failed. "
"Couldn't determine location of this executable to install "
Expand All @@ -1703,6 +1799,12 @@ static void ensure_systemd_hooks_are_set_up(void)

int main(int argc, char *argv[])
{
char *dest_dir = NULL;
char *when = NULL;
char *action = NULL;

optional_params(argc, argv, &dest_dir, &when, &action);

if (geteuid() != 0) {
log_fatal("This program has to be executed with superuser privileges.");
return 1;
Expand All @@ -1721,8 +1823,8 @@ int main(int argc, char *argv[])
if (is_hyperv()) {
/* We only handle these things here on Hyper-V VMs because it's the only
* hypervisor we know that might need these kinds of notifications. */
if (argc == 3)
return handle_systemd_suspend_notification(argv[0], argv[1], argv[2]);
if (when && action)
return handle_systemd_suspend_notification(argv[0], when, action);
if (is_cold_boot())
notify_vm_host(HOST_VM_NOTIFY_COLD_BOOT);
}
Expand All @@ -1743,7 +1845,7 @@ int main(int argc, char *argv[])
log_info("Swap file not found");
}

if (swap && swap->capacity < needed_swap) {
if (swap && swap->capacity != needed_swap) {
log_info("Swap file %s has capacity of %zu MB but needs %zu MB. Recreating. "
"System will run without a swap file while this is being set up.",
swap->path, swap->capacity / MEGA_BYTES, needed_swap / MEGA_BYTES);
Expand Down Expand Up @@ -1788,6 +1890,8 @@ int main(int argc, char *argv[])

if (is_hyperv()) {
ensure_udev_rules_are_installed();
if(!ensure_systemd_service_enabled(dest_dir))
log_info("Could not enable hibernation-setup-tool service");
ensure_systemd_hooks_are_set_up();
}

Expand Down