1 /* 2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de 3 * All rights reserved. Distributed under the terms of the MIT License. 4 * 5 * Copyright 2010-2012 Haiku, Inc. All rights reserved. 6 * Distributed under the terms of the MIT License. 7 * 8 * Authors: 9 * Hamish Morrison, hamish@lavabit.com 10 * Alexander von Gluck, kallisti5@unixzen.com 11 */ 12 13 14 #include "Settings.h" 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 #include <AutoDeleter.h> 21 #include <AutoDeleterDrivers.h> 22 #include <File.h> 23 #include <FindDirectory.h> 24 #include <Path.h> 25 #include <VolumeRoster.h> 26 27 #include <driver_settings.h> 28 29 30 static const char* const kWindowSettingsFile = "virtualmemory_preferences"; 31 static const char* const kVirtualMemorySettings = "virtual_memory"; 32 static const off_t kMegaByte = 1024 * 1024; 33 static const off_t kGigaByte = kMegaByte * 1024; 34 35 36 Settings::Settings() 37 { 38 fDefaultSettings.enabled = true; 39 fDefaultSettings.automatic = true; 40 41 system_info sysInfo; 42 get_system_info(&sysInfo); 43 44 fDefaultSettings.size = (off_t)sysInfo.max_pages * B_PAGE_SIZE; 45 if (fDefaultSettings.size <= kGigaByte) { 46 // Memory under 1GB? double the swap 47 // This matches the behaviour of the kernel 48 fDefaultSettings.size *= 2; 49 } 50 51 fDefaultSettings.volume = dev_for_path("/boot"); 52 } 53 54 55 void 56 Settings::SetSwapEnabled(bool enabled, bool revertable) 57 { 58 fCurrentSettings.enabled = enabled; 59 if (!revertable) 60 fInitialSettings.enabled = enabled; 61 } 62 63 64 void 65 Settings::SetSwapAutomatic(bool automatic, bool revertable) 66 { 67 fCurrentSettings.automatic = automatic; 68 if (!revertable) 69 fInitialSettings.automatic = automatic; 70 } 71 72 73 void 74 Settings::SetSwapSize(off_t size, bool revertable) 75 { 76 fCurrentSettings.size = size; 77 if (!revertable) 78 fInitialSettings.size = size; 79 } 80 81 82 void 83 Settings::SetSwapVolume(dev_t volume, bool revertable) 84 { 85 fCurrentSettings.volume = volume; 86 if (!revertable) 87 fInitialSettings.volume = volume; 88 89 } 90 91 92 void 93 Settings::SetWindowPosition(BPoint position) 94 { 95 fWindowPosition = position; 96 } 97 98 99 status_t 100 Settings::ReadWindowSettings() 101 { 102 BPath path; 103 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 104 return B_ERROR; 105 106 path.Append(kWindowSettingsFile); 107 BFile file; 108 if (file.SetTo(path.Path(), B_READ_ONLY) != B_OK) 109 return B_ERROR; 110 111 if (file.Read(&fWindowPosition, sizeof(BPoint)) == sizeof(BPoint)) 112 return B_OK; 113 114 return B_ERROR; 115 } 116 117 118 status_t 119 Settings::WriteWindowSettings() 120 { 121 BPath path; 122 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK) 123 return B_ERROR; 124 125 path.Append(kWindowSettingsFile); 126 127 BFile file; 128 if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) 129 != B_OK) 130 return B_ERROR; 131 132 file.Write(&fWindowPosition, sizeof(BPoint)); 133 return B_OK; 134 } 135 136 137 status_t 138 Settings::ReadSwapSettings() 139 { 140 void* settings = load_driver_settings(kVirtualMemorySettings); 141 if (settings == NULL) 142 return kErrorSettingsNotFound; 143 DriverSettingsUnloader settingDeleter(settings); 144 145 const char* enabled = get_driver_parameter(settings, "vm", NULL, NULL); 146 const char* automatic = get_driver_parameter(settings, "swap_auto", 147 NULL, NULL); 148 const char* size = get_driver_parameter(settings, "swap_size", NULL, NULL); 149 const char* volume = get_driver_parameter(settings, "swap_volume_name", 150 NULL, NULL); 151 const char* device = get_driver_parameter(settings, 152 "swap_volume_device", NULL, NULL); 153 const char* filesystem = get_driver_parameter(settings, 154 "swap_volume_filesystem", NULL, NULL); 155 const char* capacity = get_driver_parameter(settings, 156 "swap_volume_capacity", NULL, NULL); 157 158 if (enabled == NULL || automatic == NULL || size == NULL || device == NULL 159 || volume == NULL || capacity == NULL || filesystem == NULL) 160 return kErrorSettingsInvalid; 161 162 off_t volCapacity = atoll(capacity); 163 164 SetSwapEnabled(get_driver_boolean_parameter(settings, 165 "vm", true, false)); 166 SetSwapAutomatic(get_driver_boolean_parameter(settings, 167 "swap_auto", true, false)); 168 SetSwapSize(atoll(size)); 169 170 int32 bestScore = -1; 171 dev_t bestVol = -1; 172 173 BVolume vol; 174 fs_info volStat; 175 BVolumeRoster roster; 176 while (roster.GetNextVolume(&vol) == B_OK) { 177 if (!vol.IsPersistent() || vol.IsReadOnly() || vol.IsRemovable() 178 || vol.IsShared()) 179 continue; 180 if (fs_stat_dev(vol.Device(), &volStat) == 0) { 181 int32 score = 0; 182 if (strcmp(volume, volStat.volume_name) == 0) 183 score += 4; 184 if (strcmp(device, volStat.device_name) == 0) 185 score += 3; 186 if (volCapacity == volStat.total_blocks * volStat.block_size) 187 score += 2; 188 if (strcmp(filesystem, volStat.fsh_name) == 0) 189 score += 1; 190 if (score >= 4 && score > bestScore) { 191 bestVol = vol.Device(); 192 bestScore = score; 193 } 194 } 195 } 196 197 SetSwapVolume(bestVol); 198 fInitialSettings = fCurrentSettings; 199 200 if (bestVol < 0) 201 return kErrorVolumeNotFound; 202 203 return B_OK; 204 } 205 206 207 status_t 208 Settings::WriteSwapSettings() 209 { 210 BPath path; 211 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 212 return B_ERROR; 213 214 path.Append("kernel/drivers"); 215 path.Append(kVirtualMemorySettings); 216 217 BFile file; 218 if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) 219 != B_OK) 220 return B_ERROR; 221 222 fs_info info; 223 if (fs_stat_dev(SwapVolume(), &info) != 0) 224 return B_ERROR; 225 226 char buffer[1024]; 227 snprintf(buffer, sizeof(buffer), "vm %s\nswap_auto %s\nswap_size %" 228 B_PRIdOFF "\nswap_volume_name %s\nswap_volume_device %s\n" 229 "swap_volume_filesystem %s\nswap_volume_capacity %" B_PRIdOFF "\n", 230 SwapEnabled() ? "on" : "off", SwapAutomatic() ? "yes" : "no", 231 SwapSize(), info.volume_name, info.device_name, info.fsh_name, 232 info.total_blocks * info.block_size); 233 234 file.Write(buffer, strlen(buffer)); 235 return B_OK; 236 } 237 238 239 bool 240 Settings::IsRevertable() 241 { 242 return SwapEnabled() != fInitialSettings.enabled 243 || SwapAutomatic() != fInitialSettings.automatic 244 || SwapSize() != fInitialSettings.size 245 || SwapVolume() != fInitialSettings.volume; 246 } 247 248 249 void 250 Settings::RevertSwapSettings() 251 { 252 SetSwapEnabled(fInitialSettings.enabled); 253 SetSwapAutomatic(fInitialSettings.automatic); 254 SetSwapSize(fInitialSettings.size); 255 SetSwapVolume(fInitialSettings.volume); 256 } 257 258 259 bool 260 Settings::IsDefaultable() 261 { 262 return SwapEnabled() != fDefaultSettings.enabled 263 || SwapAutomatic() != fDefaultSettings.automatic 264 || SwapSize() != fDefaultSettings.size 265 || SwapVolume() != fDefaultSettings.volume; 266 } 267 268 269 void 270 Settings::DefaultSwapSettings(bool revertable) 271 { 272 SetSwapEnabled(fDefaultSettings.enabled); 273 SetSwapAutomatic(fDefaultSettings.automatic); 274 SetSwapSize(fDefaultSettings.size); 275 SetSwapVolume(fDefaultSettings.volume); 276 if (!revertable) 277 fInitialSettings = fDefaultSettings; 278 } 279