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
Settings()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
SetSwapEnabled(bool enabled,bool revertable)56 Settings::SetSwapEnabled(bool enabled, bool revertable)
57 {
58 fCurrentSettings.enabled = enabled;
59 if (!revertable)
60 fInitialSettings.enabled = enabled;
61 }
62
63
64 void
SetSwapAutomatic(bool automatic,bool revertable)65 Settings::SetSwapAutomatic(bool automatic, bool revertable)
66 {
67 fCurrentSettings.automatic = automatic;
68 if (!revertable)
69 fInitialSettings.automatic = automatic;
70 }
71
72
73 void
SetSwapSize(off_t size,bool revertable)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
SetSwapVolume(dev_t volume,bool revertable)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
SetWindowPosition(BPoint position)93 Settings::SetWindowPosition(BPoint position)
94 {
95 fWindowPosition = position;
96 }
97
98
99 status_t
ReadWindowSettings()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
WriteWindowSettings()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
ReadSwapSettings()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
WriteSwapSettings()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
IsRevertable()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
RevertSwapSettings()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
IsDefaultable()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
DefaultSwapSettings(bool revertable)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