diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/fileio.c | 34 | ||||
-rw-r--r-- | src/shared/fileio.h | 2 | ||||
-rw-r--r-- | src/shared/logs-show.c | 2 | ||||
-rw-r--r-- | src/shared/sleep-config.c | 45 | ||||
-rw-r--r-- | src/shared/util.c | 23 |
5 files changed, 82 insertions, 24 deletions
diff --git a/src/shared/fileio.c b/src/shared/fileio.c index 77fd05955a..4e2b4442db 100644 --- a/src/shared/fileio.c +++ b/src/shared/fileio.c @@ -648,3 +648,37 @@ int executable_is_script(const char *path, char **interpreter) { *interpreter = ans; return 1; } + +/** + * Retrieve one field from a file like /proc/self/status. + * pattern should start with '\n' and end with ':'. Whitespace + * after ':' will be skipped. field must be freed afterwards. + */ +int get_status_field(const char *filename, const char *pattern, char **field) { + _cleanup_free_ char *status = NULL; + char *t; + size_t len; + int r; + + assert(filename); + assert(field); + + r = read_full_file(filename, &status, NULL); + if (r < 0) + return r; + + t = strstr(status, pattern); + if (!t) + return -ENOENT; + + t += strlen(pattern); + t += strspn(t, WHITESPACE); + + len = strcspn(t, WHITESPACE); + + *field = strndup(t, len); + if (!*field) + return -ENOMEM; + + return 0; +} diff --git a/src/shared/fileio.h b/src/shared/fileio.h index a0aae28bae..59e41502b1 100644 --- a/src/shared/fileio.h +++ b/src/shared/fileio.h @@ -37,3 +37,5 @@ int load_env_file(const char *fname, const char *separator, char ***l); int write_env_file(const char *fname, char **l); int executable_is_script(const char *path, char **interpreter); + +int get_status_field(const char *filename, const char *pattern, char **field); diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 87633e7816..f50777c58d 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -201,7 +201,7 @@ static int output_short( assert(j); /* Set the threshold to one bigger than the actual print - * treshold, so that if the line is actually longer than what + * threshold, so that if the line is actually longer than what * we're willing to print, ellipsization will occur. This way * we won't output a misleading line without any indication of * truncation. diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index cd3238b405..5ec7cce458 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -163,6 +163,46 @@ int can_sleep_disk(char **types) { return false; } +#define HIBERNATION_SWAP_THRESHOLD 0.98 + +static bool enough_memory_for_hibernation(void) { + _cleanup_free_ char *active = NULL, *swapfree = NULL; + unsigned long long act, swap; + int r; + + r = get_status_field("/proc/meminfo", "\nSwapFree:", &swapfree); + if (r < 0) { + log_error("Failed to retrieve SwapFree from /proc/meminfo: %s", strerror(-r)); + return false; + } + + r = safe_atollu(swapfree, &swap); + if (r < 0) { + log_error("Failed to parse SwapFree from /proc/meminfo: %s: %s", + swapfree, strerror(-r)); + return false; + } + + r = get_status_field("/proc/meminfo", "\nActive(anon):", &active); + if (r < 0) { + log_error("Failed to retrieve Active(anon) from /proc/meminfo: %s", strerror(-r)); + return false; + } + + r = safe_atollu(active, &act); + if (r < 0) { + log_error("Failed to parse Active(anon) from /proc/meminfo: %s: %s", + active, strerror(-r)); + return false; + } + + r = act <= swap * HIBERNATION_SWAP_THRESHOLD; + log_debug("Hibernation is %spossible, Active(anon)=%llu kB, SwapFree=%llu kB, threshold=%.2g%%", + r ? "" : "im", act, swap, 100*HIBERNATION_SWAP_THRESHOLD); + + return r; +} + int can_sleep(const char *verb) { _cleanup_strv_free_ char **modes = NULL, **states = NULL; int r; @@ -175,5 +215,8 @@ int can_sleep(const char *verb) { if (r < 0) return false; - return can_sleep_state(states) && can_sleep_disk(modes); + if (!can_sleep_state(states) || !can_sleep_disk(modes)) + return false; + + return streq(verb, "suspend") || enough_memory_for_hibernation(); } diff --git a/src/shared/util.c b/src/shared/util.c index 9a075fa163..f6f3b18bfc 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -694,9 +694,6 @@ int is_kernel_thread(pid_t pid) { int get_process_capeff(pid_t pid, char **capeff) { const char *p; - _cleanup_free_ char *status = NULL; - char *t = NULL; - int r; assert(capeff); assert(pid >= 0); @@ -706,25 +703,7 @@ int get_process_capeff(pid_t pid, char **capeff) { else p = procfs_file_alloca(pid, "status"); - r = read_full_file(p, &status, NULL); - if (r < 0) - return r; - - t = strstr(status, "\nCapEff:\t"); - if (!t) - return -ENOENT; - - for (t += strlen("\nCapEff:\t"); t[0] == '0'; t++) - continue; - - if (t[0] == '\n') - t--; - - *capeff = strndup(t, strchr(t, '\n') - t); - if (!*capeff) - return -ENOMEM; - - return 0; + return get_status_field(p, "\nCapEff:", capeff); } int get_process_exe(pid_t pid, char **name) { |