1185922Simp/*
2185922Simp * Copyright 2005, Axel D��rfler, axeld@pinc-software.de
3185922Simp * All rights reserved. Distributed under the terms of the MIT License.
4185922Simp *
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
29static const char* const kWindowSettingsFile = "virtualmemory_preferences";
30static const char* const kVirtualMemorySettings = "virtual_memory";
31static const off_t kMegaByte = 1024 * 1024;
32static const off_t kGigaByte = kMegaByte * 1024;
33
34
35Settings::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
54void
55Settings::SetSwapEnabled(bool enabled, bool revertable)
56{
57	fCurrentSettings.enabled = enabled;
58	if (!revertable)
59		fInitialSettings.enabled = enabled;
60}
61
62
63void
64Settings::SetSwapAutomatic(bool automatic, bool revertable)
65{
66	fCurrentSettings.automatic = automatic;
67	if (!revertable)
68		fInitialSettings.automatic = automatic;
69}
70
71
72void
73Settings::SetSwapSize(off_t size, bool revertable)
74{
75	fCurrentSettings.size = size;
76	if (!revertable)
77		fInitialSettings.size = size;
78}
79
80
81void
82Settings::SetSwapVolume(dev_t volume, bool revertable)
83{
84	fCurrentSettings.volume = volume;
85	if (!revertable)
86		fInitialSettings.volume = volume;
87
88}
89
90
91void
92Settings::SetWindowPosition(BPoint position)
93{
94	fWindowPosition = position;
95}
96
97
98status_t
99Settings::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
117status_t
118Settings::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
136status_t
137Settings::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
207status_t
208Settings::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
239bool
240Settings::IsRevertable()
241{
242	return SwapEnabled() != fInitialSettings.enabled
243		|| SwapAutomatic() != fInitialSettings.automatic
244		|| SwapSize() != fInitialSettings.size
245		|| SwapVolume() != fInitialSettings.volume;
246}
247
248
249void
250Settings::RevertSwapSettings()
251{
252	SetSwapEnabled(fInitialSettings.enabled);
253	SetSwapAutomatic(fInitialSettings.automatic);
254	SetSwapSize(fInitialSettings.size);
255	SetSwapVolume(fInitialSettings.volume);
256}
257
258
259bool
260Settings::IsDefaultable()
261{
262	return SwapEnabled() != fDefaultSettings.enabled
263		|| SwapAutomatic() != fDefaultSettings.automatic
264		|| SwapSize() != fDefaultSettings.size
265		|| SwapVolume() != fDefaultSettings.volume;
266}
267
268
269void
270Settings::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