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 <File.h> 22 #include <FindDirectory.h> 23 #include <Path.h> 24 #include <VolumeRoster.h> 25 26 #include <driver_settings.h> 27 28 29 static const char* const kWindowSettingsFile = "virtualmemory_preferences"; 30 static const char* const kVirtualMemorySettings = "virtual_memory"; 31 static const off_t kMegaByte = 1024 * 1024; 32 static const off_t kGigaByte = kMegaByte * 1024; 33 34 35 Settings::Settings() 36 { 37 fDefaultSettings.enabled = true; 38 fDefaultSettings.automatic = true; 39 40 system_info sysInfo; 41 get_system_info(&sysInfo); 42 43 fDefaultSettings.size = (off_t)sysInfo.max_pages * B_PAGE_SIZE; 44 if (fDefaultSettings.size <= kGigaByte) { 45 // Memory under 1GB? double the swap 46 // This matches the behaviour of the kernel 47 fDefaultSettings.size *= 2; 48 } 49 50 fDefaultSettings.volume = dev_for_path("/boot"); 51 } 52 53 54 void 55 Settings::SetSwapEnabled(bool enabled, bool revertable) 56 { 57 fCurrentSettings.enabled = enabled; 58 if (!revertable) 59 fInitialSettings.enabled = enabled; 60 } 61 62 63 void 64 Settings::SetSwapAutomatic(bool automatic, bool revertable) 65 { 66 fCurrentSettings.automatic = automatic; 67 if (!revertable) 68 fInitialSettings.automatic = automatic; 69 } 70 71 72 void 73 Settings::SetSwapSize(off_t size, bool revertable) 74 { 75 fCurrentSettings.size = size; 76 if (!revertable) 77 fInitialSettings.size = size; 78 } 79 80 81 void 82 Settings::SetSwapVolume(dev_t volume, bool revertable) 83 { 84 fCurrentSettings.volume = volume; 85 if (!revertable) 86 fInitialSettings.volume = volume; 87 88 } 89 90 91 void 92 Settings::SetWindowPosition(BPoint position) 93 { 94 fWindowPosition = position; 95 } 96 97 98 status_t 99 Settings::ReadWindowSettings() 100 { 101 BPath path; 102 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 103 return B_ERROR; 104 105 path.Append(kWindowSettingsFile); 106 BFile file; 107 if (file.SetTo(path.Path(), B_READ_ONLY) != B_OK) 108 return B_ERROR; 109 110 if (file.Read(&fWindowPosition, sizeof(BPoint)) == sizeof(BPoint)) 111 return B_OK; 112 113 return B_ERROR; 114 } 115 116 117 status_t 118 Settings::WriteWindowSettings() 119 { 120 BPath path; 121 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK) 122 return B_ERROR; 123 124 path.Append(kWindowSettingsFile); 125 126 BFile file; 127 if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) 128 != B_OK) 129 return B_ERROR; 130 131 file.Write(&fWindowPosition, sizeof(BPoint)); 132 return B_OK; 133 } 134 135 136 status_t 137 Settings::ReadSwapSettings() 138 { 139 void* settings = load_driver_settings(kVirtualMemorySettings); 140 if (settings == NULL) 141 return kErrorSettingsNotFound; 142 CObjectDeleter<void, status_t> settingDeleter(settings, 143 &unload_driver_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