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 DriverSettingsUnloader settings( 141 load_driver_settings(kVirtualMemorySettings)); 142 if (!settings.IsSet()) 143 return kErrorSettingsNotFound; 144 145 const char* enabled = get_driver_parameter(settings.Get(), 146 "vm", NULL, NULL); 147 const char* automatic = get_driver_parameter(settings.Get(), 148 "swap_auto", NULL, NULL); 149 const char* size = get_driver_parameter(settings.Get(), 150 "swap_size", NULL, NULL); 151 const char* volume = get_driver_parameter(settings.Get(), 152 "swap_volume_name", NULL, NULL); 153 const char* device = get_driver_parameter(settings.Get(), 154 "swap_volume_device", NULL, NULL); 155 const char* filesystem = get_driver_parameter(settings.Get(), 156 "swap_volume_filesystem", NULL, NULL); 157 const char* capacity = get_driver_parameter(settings.Get(), 158 "swap_volume_capacity", NULL, NULL); 159 160 if (enabled == NULL || automatic == NULL || size == NULL || device == NULL 161 || volume == NULL || capacity == NULL || filesystem == NULL) 162 return kErrorSettingsInvalid; 163 164 off_t volCapacity = atoll(capacity); 165 166 SetSwapEnabled(get_driver_boolean_parameter(settings.Get(), 167 "vm", true, false)); 168 SetSwapAutomatic(get_driver_boolean_parameter(settings.Get(), 169 "swap_auto", true, false)); 170 SetSwapSize(atoll(size)); 171 172 int32 bestScore = -1; 173 dev_t bestVol = -1; 174 175 BVolume vol; 176 fs_info volStat; 177 BVolumeRoster roster; 178 while (roster.GetNextVolume(&vol) == B_OK) { 179 if (!vol.IsPersistent() || vol.IsReadOnly() || vol.IsRemovable() 180 || vol.IsShared()) 181 continue; 182 if (fs_stat_dev(vol.Device(), &volStat) == 0) { 183 int32 score = 0; 184 if (strcmp(volume, volStat.volume_name) == 0) 185 score += 4; 186 if (strcmp(device, volStat.device_name) == 0) 187 score += 3; 188 if (volCapacity == volStat.total_blocks * volStat.block_size) 189 score += 2; 190 if (strcmp(filesystem, volStat.fsh_name) == 0) 191 score += 1; 192 if (score >= 4 && score > bestScore) { 193 bestVol = vol.Device(); 194 bestScore = score; 195 } 196 } 197 } 198 199 SetSwapVolume(bestVol); 200 fInitialSettings = fCurrentSettings; 201 202 if (bestVol < 0) 203 return kErrorVolumeNotFound; 204 205 return B_OK; 206 } 207 208 209 status_t 210 Settings::WriteSwapSettings() 211 { 212 BPath path; 213 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 214 return B_ERROR; 215 216 path.Append("kernel/drivers"); 217 path.Append(kVirtualMemorySettings); 218 219 BFile file; 220 if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) 221 != B_OK) 222 return B_ERROR; 223 224 fs_info info; 225 if (fs_stat_dev(SwapVolume(), &info) != 0) 226 return B_ERROR; 227 228 char buffer[1024]; 229 snprintf(buffer, sizeof(buffer), "vm %s\nswap_auto %s\nswap_size %" 230 B_PRIdOFF "\nswap_volume_name %s\nswap_volume_device %s\n" 231 "swap_volume_filesystem %s\nswap_volume_capacity %" B_PRIdOFF "\n", 232 SwapEnabled() ? "on" : "off", SwapAutomatic() ? "yes" : "no", 233 SwapSize(), info.volume_name, info.device_name, info.fsh_name, 234 info.total_blocks * info.block_size); 235 236 file.Write(buffer, strlen(buffer)); 237 return B_OK; 238 } 239 240 241 bool 242 Settings::IsRevertable() 243 { 244 return SwapEnabled() != fInitialSettings.enabled 245 || SwapAutomatic() != fInitialSettings.automatic 246 || SwapSize() != fInitialSettings.size 247 || SwapVolume() != fInitialSettings.volume; 248 } 249 250 251 void 252 Settings::RevertSwapSettings() 253 { 254 SetSwapEnabled(fInitialSettings.enabled); 255 SetSwapAutomatic(fInitialSettings.automatic); 256 SetSwapSize(fInitialSettings.size); 257 SetSwapVolume(fInitialSettings.volume); 258 } 259 260 261 bool 262 Settings::IsDefaultable() 263 { 264 return SwapEnabled() != fDefaultSettings.enabled 265 || SwapAutomatic() != fDefaultSettings.automatic 266 || SwapSize() != fDefaultSettings.size 267 || SwapVolume() != fDefaultSettings.volume; 268 } 269 270 271 void 272 Settings::DefaultSwapSettings(bool revertable) 273 { 274 SetSwapEnabled(fDefaultSettings.enabled); 275 SetSwapAutomatic(fDefaultSettings.automatic); 276 SetSwapSize(fDefaultSettings.size); 277 SetSwapVolume(fDefaultSettings.volume); 278 if (!revertable) 279 fInitialSettings = fDefaultSettings; 280 } 281