xref: /haiku/src/preferences/virtualmemory/Settings.cpp (revision 46b7da1f4f40f7157d74fc7fb26ff9ec7f2416f2)
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