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