| 1 | /* |
| 2 | * Copyright 2011, Haiku, Inc. All rights reserved. |
| 3 | * Distributed under the terms of the MIT License. |
| 4 | * |
| 5 | * Authors: |
| 6 | * Hamish Morrison <hamish@lavabit.com> |
| 7 | */ |
| 8 | |
| 9 | #include <stdio.h> |
| 10 | |
| 11 | #include <Alert.h> |
| 12 | #include <Application.h> |
| 13 | #include <Catalog.h> |
| 14 | #include <File.h> |
| 15 | #include <FindDirectory.h> |
| 16 | #include <kernel/fs_info.h> |
| 17 | #include <Path.h> |
| 18 | #include <Roster.h> |
| 19 | |
| 20 | #include <driver_settings.h> |
| 21 | |
| 22 | #undef B_TRANSLATE_CONTEXT |
| 23 | #define B_TRANSLATE_CONTEXT "swapcheck" |
| 24 | |
| 25 | |
| 26 | static const char* const kSwapErrorFilePath = "swaperr"; |
| 27 | static const char* const kVirtualMemorySettings = "virtual_memory"; |
| 28 | |
| 29 | |
| 30 | int main() |
| 31 | { |
| 32 | // Ensure that the swap error file is not old |
| 33 | time_t currentTime = time(NULL); |
| 34 | bigtime_t bootTime = (system_time() / 1000000) + 1; |
| 35 | |
| 36 | BPath path; |
| 37 | if (find_directory(B_COMMON_SETTINGS_DIRECTORY, &path) != B_OK) |
| 38 | return 1; |
| 39 | path.Append(kSwapErrorFilePath); |
| 40 | |
| 41 | const char* pathString = path.Path(); |
| 42 | struct stat errFile; |
| 43 | if (stat(pathString, &errFile) < 0) |
| 44 | return 0; |
| 45 | |
| 46 | time_t modTime = currentTime - errFile.st_mtime; |
| 47 | if (modTime >= bootTime) { |
| 48 | unlink(pathString); |
| 49 | return 0; |
| 50 | } |
| 51 | |
| 52 | // Currently all swap errors result in the swap file |
| 53 | // being created on the boot device, so update the swap |
| 54 | // settings to reflect that. |
| 55 | void* settings = load_driver_settings(kVirtualMemorySettings); |
| 56 | if (settings != NULL) { |
| 57 | const char* enabled = get_driver_parameter(settings, |
| 58 | "vm", NULL, NULL); |
| 59 | const char* size = get_driver_parameter(settings, |
| 60 | "swap_size", NULL, NULL); |
| 61 | |
| 62 | if (enabled != NULL && size != NULL) { |
| 63 | BPath path; |
| 64 | if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { |
| 65 | path.Append("kernel/drivers"); |
| 66 | path.Append(kVirtualMemorySettings); |
| 67 | |
| 68 | BFile file; |
| 69 | if (file.SetTo(path.Path(), |
| 70 | B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) == B_OK) { |
| 71 | fs_info info; |
| 72 | fs_stat_dev(dev_for_path("/boot"), &info); |
| 73 | |
| 74 | char buffer[1024]; |
| 75 | snprintf(buffer, sizeof(buffer), "vm %s\nswap_size %s\n" |
| 76 | "swap_volume_name %s\nswap_volume_device %s\n" |
| 77 | "swap_volume_filesystem %s\n" |
| 78 | "swap_volume_capacity %lld\n", enabled, size, |
| 79 | info.volume_name, info.device_name, info.fsh_name, |
| 80 | info.total_blocks * info.block_size); |
| 81 | file.Write(buffer, strlen(buffer)); |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | unload_driver_settings(settings); |
| 86 | } |
| 87 | |
| 88 | int fd = open(pathString, O_RDONLY); |
| 89 | if (fd >= 0) { |
| 90 | char buf[8] = { 0 }; |
| 91 | if (read(fd, &buf, sizeof(buf)) > 0) { |
| 92 | BApplication app("application/x-vnd.Haiku-cmd-swapcheck"); |
| 93 | const char* prompt = NULL; |
| 94 | if (strcmp(buf, "nfnd") == 0) |
| 95 | prompt = B_TRANSLATE("The system could not locate the " |
| 96 | "specified swap volume at boot time. The boot " |
| 97 | "device has been used instead"); |
| 98 | else if (strcmp(buf, "nmnt") == 0) |
| 99 | prompt = B_TRANSLATE("The system could not mount the " |
| 100 | "specified swap volume at boot time. The boot " |
| 101 | "device has been used instead"); |
| 102 | |
| 103 | if (prompt != NULL) { |
| 104 | int32 choice = 0; |
| 105 | choice = (new BAlert("swapcheck", prompt, |
| 106 | B_TRANSLATE("OK"), B_TRANSLATE("Adjust swap " |
| 107 | "settings" B_UTF8_ELLIPSIS)))->Go(); |
| 108 | if (choice == 1) |
| 109 | be_roster->Launch("application/x-vnd." |
| 110 | "Haiku-VirtualMemory"); |
| 111 | } |
| 112 | |
| 113 | } |
| 114 | unlink(pathString); |
| 115 | close(fd); |
| 116 | } |
| 117 | |
| 118 | return 0; |
| 119 | } |