13a7e0b00SIngo Weinhold /*
23a7e0b00SIngo Weinhold * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
33a7e0b00SIngo Weinhold * Distributed under the terms of the MIT License.
43a7e0b00SIngo Weinhold */
53a7e0b00SIngo Weinhold
63a7e0b00SIngo Weinhold
73a7e0b00SIngo Weinhold #include "PackageSettings.h"
83a7e0b00SIngo Weinhold
93a7e0b00SIngo Weinhold #include <driver_settings.h>
103a7e0b00SIngo Weinhold
11cdccd323SX512 #include <AutoDeleterDrivers.h>
123a7e0b00SIngo Weinhold #include <directories.h>
133a7e0b00SIngo Weinhold #include <fs/KPath.h>
143a7e0b00SIngo Weinhold #include <vfs.h>
153a7e0b00SIngo Weinhold
163a7e0b00SIngo Weinhold #include "DebugSupport.h"
173a7e0b00SIngo Weinhold
183a7e0b00SIngo Weinhold
19560961eeSMurai Takashi static const char* const kBlockedEntriesParameterName = "BlockedEntries";
20560961eeSMurai Takashi static const char* const kLegacyBlockedEntriesParameterName = "EntryBlacklist";
21c04f3a62SIngo Weinhold
22c04f3a62SIngo Weinhold
233a7e0b00SIngo Weinhold // #pragma mark - PackageSettingsItem
243a7e0b00SIngo Weinhold
253a7e0b00SIngo Weinhold
PackageSettingsItem()263a7e0b00SIngo Weinhold PackageSettingsItem::PackageSettingsItem()
273a7e0b00SIngo Weinhold :
283a7e0b00SIngo Weinhold fName(),
293a7e0b00SIngo Weinhold fEntries()
303a7e0b00SIngo Weinhold {
313a7e0b00SIngo Weinhold }
323a7e0b00SIngo Weinhold
333a7e0b00SIngo Weinhold
~PackageSettingsItem()343a7e0b00SIngo Weinhold PackageSettingsItem::~PackageSettingsItem()
353a7e0b00SIngo Weinhold {
363a7e0b00SIngo Weinhold Entry* entry = fEntries.Clear(true);
373a7e0b00SIngo Weinhold while (entry != NULL) {
383a7e0b00SIngo Weinhold Entry* next = entry->HashNext();
393a7e0b00SIngo Weinhold delete entry;
403a7e0b00SIngo Weinhold entry = next;
413a7e0b00SIngo Weinhold }
423a7e0b00SIngo Weinhold }
433a7e0b00SIngo Weinhold
443a7e0b00SIngo Weinhold
453a7e0b00SIngo Weinhold status_t
Init(const char * name)46c04f3a62SIngo Weinhold PackageSettingsItem::Init(const char* name)
473a7e0b00SIngo Weinhold {
48c04f3a62SIngo Weinhold if (!fName.SetTo(name) || fEntries.Init() != B_OK)
493a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY);
50c04f3a62SIngo Weinhold return B_OK;
51c04f3a62SIngo Weinhold }
523a7e0b00SIngo Weinhold
53c04f3a62SIngo Weinhold
54c04f3a62SIngo Weinhold status_t
ApplySettings(const driver_parameter * parameters,int parameterCount)55c04f3a62SIngo Weinhold PackageSettingsItem::ApplySettings(const driver_parameter* parameters,
56c04f3a62SIngo Weinhold int parameterCount)
57c04f3a62SIngo Weinhold {
58c04f3a62SIngo Weinhold for (int i = 0; i < parameterCount; i++) {
59c04f3a62SIngo Weinhold const driver_parameter& subParameter = parameters[i];
60560961eeSMurai Takashi if (strcmp(subParameter.name, kBlockedEntriesParameterName) != 0
61560961eeSMurai Takashi && strcmp(subParameter.name, kLegacyBlockedEntriesParameterName)
62560961eeSMurai Takashi != 0)
633a7e0b00SIngo Weinhold continue;
643a7e0b00SIngo Weinhold
65560961eeSMurai Takashi status_t error = _AddBlockedEntries(subParameter);
663a7e0b00SIngo Weinhold // abort only in case of serious issues (memory shortage)
673a7e0b00SIngo Weinhold if (error == B_NO_MEMORY)
683a7e0b00SIngo Weinhold return error;
693a7e0b00SIngo Weinhold }
703a7e0b00SIngo Weinhold
713a7e0b00SIngo Weinhold return B_OK;
723a7e0b00SIngo Weinhold }
733a7e0b00SIngo Weinhold
743a7e0b00SIngo Weinhold
753a7e0b00SIngo Weinhold void
AddEntry(Entry * entry)763a7e0b00SIngo Weinhold PackageSettingsItem::AddEntry(Entry* entry)
773a7e0b00SIngo Weinhold {
783a7e0b00SIngo Weinhold fEntries.Insert(entry);
793a7e0b00SIngo Weinhold }
803a7e0b00SIngo Weinhold
813a7e0b00SIngo Weinhold
823a7e0b00SIngo Weinhold status_t
AddEntry(const char * path,Entry * & _entry)833a7e0b00SIngo Weinhold PackageSettingsItem::AddEntry(const char* path, Entry*& _entry)
843a7e0b00SIngo Weinhold {
853a7e0b00SIngo Weinhold Entry* parent = NULL;
863a7e0b00SIngo Weinhold
873a7e0b00SIngo Weinhold while (*path != '\0') {
883a7e0b00SIngo Weinhold while (*path == '/') {
893a7e0b00SIngo Weinhold path++;
903a7e0b00SIngo Weinhold continue;
913a7e0b00SIngo Weinhold }
923a7e0b00SIngo Weinhold
933a7e0b00SIngo Weinhold const char* componentEnd = strchr(path, '/');
943a7e0b00SIngo Weinhold if (componentEnd == NULL)
953a7e0b00SIngo Weinhold componentEnd = path + strlen(path);
963a7e0b00SIngo Weinhold
973a7e0b00SIngo Weinhold String name;
983a7e0b00SIngo Weinhold if (!name.SetTo(path, componentEnd - path))
993a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY);
1003a7e0b00SIngo Weinhold
1013a7e0b00SIngo Weinhold Entry* entry = FindEntry(parent, name);
1023a7e0b00SIngo Weinhold if (entry == NULL) {
1033a7e0b00SIngo Weinhold entry = new(std::nothrow) Entry(parent, name);
1043a7e0b00SIngo Weinhold if (entry == NULL)
1053a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY);
1063a7e0b00SIngo Weinhold AddEntry(entry);
1073a7e0b00SIngo Weinhold }
1083a7e0b00SIngo Weinhold
1093a7e0b00SIngo Weinhold path = componentEnd;
1103a7e0b00SIngo Weinhold parent = entry;
1113a7e0b00SIngo Weinhold }
1123a7e0b00SIngo Weinhold
1133a7e0b00SIngo Weinhold if (parent == NULL)
1143a7e0b00SIngo Weinhold return B_BAD_VALUE;
1153a7e0b00SIngo Weinhold
1163a7e0b00SIngo Weinhold _entry = parent;
1173a7e0b00SIngo Weinhold return B_OK;
1183a7e0b00SIngo Weinhold }
1193a7e0b00SIngo Weinhold
1203a7e0b00SIngo Weinhold
1213a7e0b00SIngo Weinhold PackageSettingsItem::Entry*
FindEntry(Entry * parent,const String & name) const1223a7e0b00SIngo Weinhold PackageSettingsItem::FindEntry(Entry* parent, const String& name) const
1233a7e0b00SIngo Weinhold {
1243a7e0b00SIngo Weinhold return fEntries.Lookup(EntryKey(parent, name));
1253a7e0b00SIngo Weinhold }
1263a7e0b00SIngo Weinhold
1273a7e0b00SIngo Weinhold
1283a7e0b00SIngo Weinhold PackageSettingsItem::Entry*
FindEntry(Entry * parent,const char * name) const1293a7e0b00SIngo Weinhold PackageSettingsItem::FindEntry(Entry* parent, const char* name) const
1303a7e0b00SIngo Weinhold {
1313a7e0b00SIngo Weinhold return fEntries.Lookup(EntryKey(parent, name));
1323a7e0b00SIngo Weinhold }
1333a7e0b00SIngo Weinhold
1343a7e0b00SIngo Weinhold
1353a7e0b00SIngo Weinhold status_t
_AddBlockedEntries(const driver_parameter & parameter)136560961eeSMurai Takashi PackageSettingsItem::_AddBlockedEntries(const driver_parameter& parameter)
1373a7e0b00SIngo Weinhold {
1383a7e0b00SIngo Weinhold for (int i = 0; i < parameter.parameter_count; i++) {
1393a7e0b00SIngo Weinhold Entry* entry;
1403a7e0b00SIngo Weinhold status_t error = AddEntry(parameter.parameters[i].name, entry);
1413a7e0b00SIngo Weinhold // abort only in case of serious issues (memory shortage)
1423a7e0b00SIngo Weinhold if (error == B_NO_MEMORY)
1433a7e0b00SIngo Weinhold return error;
1443a7e0b00SIngo Weinhold
145560961eeSMurai Takashi entry->SetBlocked(true);
1463a7e0b00SIngo Weinhold }
1473a7e0b00SIngo Weinhold
1483a7e0b00SIngo Weinhold return B_OK;
1493a7e0b00SIngo Weinhold }
1503a7e0b00SIngo Weinhold
1513a7e0b00SIngo Weinhold
1523a7e0b00SIngo Weinhold // #pragma mark - PackageSettings
1533a7e0b00SIngo Weinhold
1543a7e0b00SIngo Weinhold
PackageSettings()1553a7e0b00SIngo Weinhold PackageSettings::PackageSettings()
1563a7e0b00SIngo Weinhold :
1573a7e0b00SIngo Weinhold fPackageItems()
1583a7e0b00SIngo Weinhold {
1593a7e0b00SIngo Weinhold }
1603a7e0b00SIngo Weinhold
1613a7e0b00SIngo Weinhold
~PackageSettings()1623a7e0b00SIngo Weinhold PackageSettings::~PackageSettings()
1633a7e0b00SIngo Weinhold {
1643a7e0b00SIngo Weinhold PackageSettingsItem* item = fPackageItems.Clear(true);
1653a7e0b00SIngo Weinhold while (item != NULL) {
1663a7e0b00SIngo Weinhold PackageSettingsItem* next = item->HashNext();
1673a7e0b00SIngo Weinhold delete item;
1683a7e0b00SIngo Weinhold item = next;
1693a7e0b00SIngo Weinhold }
1703a7e0b00SIngo Weinhold }
1713a7e0b00SIngo Weinhold
1723a7e0b00SIngo Weinhold
1733a7e0b00SIngo Weinhold status_t
Load(dev_t mountPointDeviceID,ino_t mountPointNodeID,PackageFSMountType mountType)1743a7e0b00SIngo Weinhold PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID,
1753a7e0b00SIngo Weinhold PackageFSMountType mountType)
1763a7e0b00SIngo Weinhold {
1773a7e0b00SIngo Weinhold status_t error = fPackageItems.Init();
1783a7e0b00SIngo Weinhold if (error != B_OK)
1793a7e0b00SIngo Weinhold RETURN_ERROR(error);
1803a7e0b00SIngo Weinhold
181c04f3a62SIngo Weinhold // First get the safe mode options. Those apply to the system package.
182c04f3a62SIngo Weinhold if (mountType == PACKAGE_FS_MOUNT_TYPE_SYSTEM) {
183c04f3a62SIngo Weinhold void* settingsHandle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
184c04f3a62SIngo Weinhold if (settingsHandle != NULL) {
185c04f3a62SIngo Weinhold if (const driver_settings* settings
186c04f3a62SIngo Weinhold = get_driver_settings(settingsHandle)) {
187c04f3a62SIngo Weinhold error = _AddPackageSettingsItem("haiku", settings->parameters,
188c04f3a62SIngo Weinhold settings->parameter_count);
189c04f3a62SIngo Weinhold // abort only in case of serious issues (memory shortage)
190c04f3a62SIngo Weinhold if (error == B_NO_MEMORY)
191c04f3a62SIngo Weinhold return error;
192c04f3a62SIngo Weinhold }
193c04f3a62SIngo Weinhold unload_driver_settings(settingsHandle);
194c04f3a62SIngo Weinhold }
195c04f3a62SIngo Weinhold }
196c04f3a62SIngo Weinhold
1973a7e0b00SIngo Weinhold // get the mount point relative settings file path
1983a7e0b00SIngo Weinhold const char* settingsFilePath = mountType == PACKAGE_FS_MOUNT_TYPE_HOME
19939be4f89SX512 ? &(kUserSettingsGlobalDirectory "/packages")
20039be4f89SX512 [strlen(kUserConfigDirectory) + 1]
20139be4f89SX512 : &(kSystemSettingsDirectory "/packages")[strlen(kSystemDirectory) + 1];
2023a7e0b00SIngo Weinhold
2033a7e0b00SIngo Weinhold // get an absolute path
2043a7e0b00SIngo Weinhold KPath path;
2053a7e0b00SIngo Weinhold if (path.InitCheck() != B_OK)
2063a7e0b00SIngo Weinhold RETURN_ERROR(path.InitCheck());
2073a7e0b00SIngo Weinhold
2083a7e0b00SIngo Weinhold error = vfs_entry_ref_to_path(mountPointDeviceID, mountPointNodeID,
2093a7e0b00SIngo Weinhold NULL, true, path.LockBuffer(), path.BufferSize());
2103a7e0b00SIngo Weinhold if (error != B_OK)
2113a7e0b00SIngo Weinhold return error;
2123a7e0b00SIngo Weinhold path.UnlockBuffer();
2133a7e0b00SIngo Weinhold
2143a7e0b00SIngo Weinhold error = path.Append(settingsFilePath);
2153a7e0b00SIngo Weinhold if (error != B_OK)
2163a7e0b00SIngo Weinhold return error;
2173a7e0b00SIngo Weinhold
2183a7e0b00SIngo Weinhold // load the driver settings
219*fce7f3a7SX512 DriverSettingsUnloader settingsHandle(load_driver_settings(path.Path()));
220*fce7f3a7SX512 if (!settingsHandle.IsSet())
2213a7e0b00SIngo Weinhold return B_ENTRY_NOT_FOUND;
2223a7e0b00SIngo Weinhold
223*fce7f3a7SX512 const driver_settings* settings
224*fce7f3a7SX512 = get_driver_settings(settingsHandle.Get());
2253a7e0b00SIngo Weinhold for (int i = 0; i < settings->parameter_count; i++) {
2263a7e0b00SIngo Weinhold const driver_parameter& parameter = settings->parameters[i];
2273a7e0b00SIngo Weinhold if (strcmp(parameter.name, "Package") != 0
2283a7e0b00SIngo Weinhold || parameter.value_count < 1) {
2293a7e0b00SIngo Weinhold continue;
2303a7e0b00SIngo Weinhold }
2313a7e0b00SIngo Weinhold
232c04f3a62SIngo Weinhold error = _AddPackageSettingsItem(parameter.values[0],
233c04f3a62SIngo Weinhold parameter.parameters, parameter.parameter_count);
2343a7e0b00SIngo Weinhold // abort only in case of serious issues (memory shortage)
2353a7e0b00SIngo Weinhold if (error == B_NO_MEMORY)
2363a7e0b00SIngo Weinhold return error;
2373a7e0b00SIngo Weinhold }
2383a7e0b00SIngo Weinhold
2393a7e0b00SIngo Weinhold return B_OK;
2403a7e0b00SIngo Weinhold }
2413a7e0b00SIngo Weinhold
2423a7e0b00SIngo Weinhold
2433a7e0b00SIngo Weinhold const PackageSettingsItem*
PackageItemFor(const String & name) const2443a7e0b00SIngo Weinhold PackageSettings::PackageItemFor(const String& name) const
2453a7e0b00SIngo Weinhold {
2463a7e0b00SIngo Weinhold return fPackageItems.Lookup(name);
2473a7e0b00SIngo Weinhold }
2483a7e0b00SIngo Weinhold
2493a7e0b00SIngo Weinhold
2503a7e0b00SIngo Weinhold status_t
_AddPackageSettingsItem(const char * name,const driver_parameter * parameters,int parameterCount)251c04f3a62SIngo Weinhold PackageSettings::_AddPackageSettingsItem(const char* name,
252c04f3a62SIngo Weinhold const driver_parameter* parameters, int parameterCount)
2533a7e0b00SIngo Weinhold {
254c04f3a62SIngo Weinhold // get/create the package item
255c04f3a62SIngo Weinhold PackageSettingsItem* packageItem = fPackageItems.Lookup(StringKey(name));
256c04f3a62SIngo Weinhold if (packageItem == NULL) {
257c04f3a62SIngo Weinhold packageItem = new(std::nothrow) PackageSettingsItem;
258c04f3a62SIngo Weinhold if (packageItem == NULL || packageItem->Init(name) != B_OK) {
2593a7e0b00SIngo Weinhold delete packageItem;
2603a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY);
2613a7e0b00SIngo Weinhold }
2623a7e0b00SIngo Weinhold
2633a7e0b00SIngo Weinhold fPackageItems.Insert(packageItem);
264c04f3a62SIngo Weinhold }
265c04f3a62SIngo Weinhold
266c04f3a62SIngo Weinhold // apply the settings
267c04f3a62SIngo Weinhold return packageItem->ApplySettings(parameters, parameterCount);
2683a7e0b00SIngo Weinhold }
269