* Copyright 2005, Axel DΓΆrfler, axeld@pinc-software.de
* All rights reserved. Distributed under the terms of the MIT License.
*
* Copyright 2010-2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hamish Morrison, hamish@lavabit.com
* Alexander von Gluck, kallisti5@unixzen.com
*/
#include "Settings.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <AutoDeleter.h>
#include <AutoDeleterDrivers.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <VolumeRoster.h>
#include <driver_settings.h>
static const char* const kWindowSettingsFile = "virtualmemory_preferences";
static const char* const kVirtualMemorySettings = "virtual_memory";
static const off_t kMegaByte = 1024 * 1024;
static const off_t kGigaByte = kMegaByte * 1024;
Settings::Settings()
{
fDefaultSettings.enabled = true;
fDefaultSettings.automatic = true;
system_info sysInfo;
get_system_info(&sysInfo);
fDefaultSettings.size = (off_t)sysInfo.max_pages * B_PAGE_SIZE;
if (fDefaultSettings.size <= kGigaByte) {
fDefaultSettings.size *= 2;
}
fDefaultSettings.volume = dev_for_path("/boot");
}
void
Settings::SetSwapEnabled(bool enabled, bool revertable)
{
fCurrentSettings.enabled = enabled;
if (!revertable)
fInitialSettings.enabled = enabled;
}
void
Settings::SetSwapAutomatic(bool automatic, bool revertable)
{
fCurrentSettings.automatic = automatic;
if (!revertable)
fInitialSettings.automatic = automatic;
}
void
Settings::SetSwapSize(off_t size, bool revertable)
{
fCurrentSettings.size = size;
if (!revertable)
fInitialSettings.size = size;
}
void
Settings::SetSwapVolume(dev_t volume, bool revertable)
{
fCurrentSettings.volume = volume;
if (!revertable)
fInitialSettings.volume = volume;
}
void
Settings::SetWindowPosition(BPoint position)
{
fWindowPosition = position;
}
status_t
Settings::ReadWindowSettings()
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return B_ERROR;
path.Append(kWindowSettingsFile);
BFile file;
if (file.SetTo(path.Path(), B_READ_ONLY) != B_OK)
return B_ERROR;
if (file.Read(&fWindowPosition, sizeof(BPoint)) == sizeof(BPoint))
return B_OK;
return B_ERROR;
}
status_t
Settings::WriteWindowSettings()
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK)
return B_ERROR;
path.Append(kWindowSettingsFile);
BFile file;
if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE)
!= B_OK)
return B_ERROR;
file.Write(&fWindowPosition, sizeof(BPoint));
return B_OK;
}
status_t
Settings::ReadSwapSettings()
{
DriverSettingsUnloader settings(
load_driver_settings(kVirtualMemorySettings));
if (!settings.IsSet())
return kErrorSettingsNotFound;
const char* enabled = get_driver_parameter(settings.Get(),
"vm", NULL, NULL);
const char* automatic = get_driver_parameter(settings.Get(),
"swap_auto", NULL, NULL);
const char* size = get_driver_parameter(settings.Get(),
"swap_size", NULL, NULL);
const char* volume = get_driver_parameter(settings.Get(),
"swap_volume_name", NULL, NULL);
const char* device = get_driver_parameter(settings.Get(),
"swap_volume_device", NULL, NULL);
const char* filesystem = get_driver_parameter(settings.Get(),
"swap_volume_filesystem", NULL, NULL);
const char* capacity = get_driver_parameter(settings.Get(),
"swap_volume_capacity", NULL, NULL);
if (enabled == NULL || automatic == NULL || size == NULL || device == NULL
|| volume == NULL || capacity == NULL || filesystem == NULL)
return kErrorSettingsInvalid;
off_t volCapacity = atoll(capacity);
SetSwapEnabled(get_driver_boolean_parameter(settings.Get(),
"vm", true, false));
SetSwapAutomatic(get_driver_boolean_parameter(settings.Get(),
"swap_auto", true, false));
SetSwapSize(atoll(size));
int32 bestScore = -1;
dev_t bestVol = -1;
BVolume vol;
fs_info volStat;
BVolumeRoster roster;
while (roster.GetNextVolume(&vol) == B_OK) {
if (!vol.IsPersistent() || vol.IsReadOnly() || vol.IsRemovable()
|| vol.IsShared())
continue;
if (fs_stat_dev(vol.Device(), &volStat) == 0) {
int32 score = 0;
if (strcmp(volume, volStat.volume_name) == 0)
score += 4;
if (strcmp(device, volStat.device_name) == 0)
score += 3;
if (volCapacity == volStat.total_blocks * volStat.block_size)
score += 2;
if (strcmp(filesystem, volStat.fsh_name) == 0)
score += 1;
if (score >= 4 && score > bestScore) {
bestVol = vol.Device();
bestScore = score;
}
}
}
SetSwapVolume(bestVol);
fInitialSettings = fCurrentSettings;
if (bestVol < 0)
return kErrorVolumeNotFound;
return B_OK;
}
status_t
Settings::WriteSwapSettings()
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return B_ERROR;
path.Append("kernel/drivers");
path.Append(kVirtualMemorySettings);
BFile file;
if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE)
!= B_OK)
return B_ERROR;
fs_info info;
if (fs_stat_dev(SwapVolume(), &info) != 0)
return B_ERROR;
char buffer[1024];
snprintf(buffer, sizeof(buffer), "vm %s\nswap_auto %s\nswap_size %"
B_PRIdOFF "\nswap_volume_name %s\nswap_volume_device %s\n"
"swap_volume_filesystem %s\nswap_volume_capacity %" B_PRIdOFF "\n",
SwapEnabled() ? "on" : "off", SwapAutomatic() ? "yes" : "no",
SwapSize(), info.volume_name, info.device_name, info.fsh_name,
info.total_blocks * info.block_size);
file.Write(buffer, strlen(buffer));
return B_OK;
}
bool
Settings::IsRevertable()
{
return SwapEnabled() != fInitialSettings.enabled
|| SwapAutomatic() != fInitialSettings.automatic
|| SwapSize() != fInitialSettings.size
|| SwapVolume() != fInitialSettings.volume;
}
void
Settings::RevertSwapSettings()
{
SetSwapEnabled(fInitialSettings.enabled);
SetSwapAutomatic(fInitialSettings.automatic);
SetSwapSize(fInitialSettings.size);
SetSwapVolume(fInitialSettings.volume);
}
bool
Settings::IsDefaultable()
{
return SwapEnabled() != fDefaultSettings.enabled
|| SwapAutomatic() != fDefaultSettings.automatic
|| SwapSize() != fDefaultSettings.size
|| SwapVolume() != fDefaultSettings.volume;
}
void
Settings::DefaultSwapSettings(bool revertable)
{
SetSwapEnabled(fDefaultSettings.enabled);
SetSwapAutomatic(fDefaultSettings.automatic);
SetSwapSize(fDefaultSettings.size);
SetSwapVolume(fDefaultSettings.volume);
if (!revertable)
fInitialSettings = fDefaultSettings;
}