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 113a7e0b00SIngo Weinhold #include <AutoDeleter.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 19c04f3a62SIngo Weinhold static const char* const kEntryBlacklistParameterName = "EntryBlacklist"; 20c04f3a62SIngo Weinhold 21c04f3a62SIngo Weinhold 223a7e0b00SIngo Weinhold // #pragma mark - PackageSettingsItem 233a7e0b00SIngo Weinhold 243a7e0b00SIngo Weinhold 253a7e0b00SIngo Weinhold PackageSettingsItem::PackageSettingsItem() 263a7e0b00SIngo Weinhold : 273a7e0b00SIngo Weinhold fName(), 283a7e0b00SIngo Weinhold fEntries() 293a7e0b00SIngo Weinhold { 303a7e0b00SIngo Weinhold } 313a7e0b00SIngo Weinhold 323a7e0b00SIngo Weinhold 333a7e0b00SIngo Weinhold PackageSettingsItem::~PackageSettingsItem() 343a7e0b00SIngo Weinhold { 353a7e0b00SIngo Weinhold Entry* entry = fEntries.Clear(true); 363a7e0b00SIngo Weinhold while (entry != NULL) { 373a7e0b00SIngo Weinhold Entry* next = entry->HashNext(); 383a7e0b00SIngo Weinhold delete entry; 393a7e0b00SIngo Weinhold entry = next; 403a7e0b00SIngo Weinhold } 413a7e0b00SIngo Weinhold } 423a7e0b00SIngo Weinhold 433a7e0b00SIngo Weinhold 443a7e0b00SIngo Weinhold status_t 45c04f3a62SIngo Weinhold PackageSettingsItem::Init(const char* name) 463a7e0b00SIngo Weinhold { 47c04f3a62SIngo Weinhold if (!fName.SetTo(name) || fEntries.Init() != B_OK) 483a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY); 49c04f3a62SIngo Weinhold return B_OK; 50c04f3a62SIngo Weinhold } 513a7e0b00SIngo Weinhold 52c04f3a62SIngo Weinhold 53c04f3a62SIngo Weinhold status_t 54c04f3a62SIngo Weinhold PackageSettingsItem::ApplySettings(const driver_parameter* parameters, 55c04f3a62SIngo Weinhold int parameterCount) 56c04f3a62SIngo Weinhold { 57c04f3a62SIngo Weinhold for (int i = 0; i < parameterCount; i++) { 58c04f3a62SIngo Weinhold const driver_parameter& subParameter = parameters[i]; 59c04f3a62SIngo Weinhold if (strcmp(subParameter.name, kEntryBlacklistParameterName) != 0) 603a7e0b00SIngo Weinhold continue; 613a7e0b00SIngo Weinhold 623a7e0b00SIngo Weinhold status_t error = _AddBlackListedEntries(subParameter); 633a7e0b00SIngo Weinhold // abort only in case of serious issues (memory shortage) 643a7e0b00SIngo Weinhold if (error == B_NO_MEMORY) 653a7e0b00SIngo Weinhold return error; 663a7e0b00SIngo Weinhold } 673a7e0b00SIngo Weinhold 683a7e0b00SIngo Weinhold return B_OK; 693a7e0b00SIngo Weinhold } 703a7e0b00SIngo Weinhold 713a7e0b00SIngo Weinhold 723a7e0b00SIngo Weinhold void 733a7e0b00SIngo Weinhold PackageSettingsItem::AddEntry(Entry* entry) 743a7e0b00SIngo Weinhold { 753a7e0b00SIngo Weinhold fEntries.Insert(entry); 763a7e0b00SIngo Weinhold } 773a7e0b00SIngo Weinhold 783a7e0b00SIngo Weinhold 793a7e0b00SIngo Weinhold status_t 803a7e0b00SIngo Weinhold PackageSettingsItem::AddEntry(const char* path, Entry*& _entry) 813a7e0b00SIngo Weinhold { 823a7e0b00SIngo Weinhold Entry* parent = NULL; 833a7e0b00SIngo Weinhold 843a7e0b00SIngo Weinhold while (*path != '\0') { 853a7e0b00SIngo Weinhold while (*path == '/') { 863a7e0b00SIngo Weinhold path++; 873a7e0b00SIngo Weinhold continue; 883a7e0b00SIngo Weinhold } 893a7e0b00SIngo Weinhold 903a7e0b00SIngo Weinhold const char* componentEnd = strchr(path, '/'); 913a7e0b00SIngo Weinhold if (componentEnd == NULL) 923a7e0b00SIngo Weinhold componentEnd = path + strlen(path); 933a7e0b00SIngo Weinhold 943a7e0b00SIngo Weinhold String name; 953a7e0b00SIngo Weinhold if (!name.SetTo(path, componentEnd - path)) 963a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY); 973a7e0b00SIngo Weinhold 983a7e0b00SIngo Weinhold Entry* entry = FindEntry(parent, name); 993a7e0b00SIngo Weinhold if (entry == NULL) { 1003a7e0b00SIngo Weinhold entry = new(std::nothrow) Entry(parent, name); 1013a7e0b00SIngo Weinhold if (entry == NULL) 1023a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY); 1033a7e0b00SIngo Weinhold AddEntry(entry); 1043a7e0b00SIngo Weinhold } 1053a7e0b00SIngo Weinhold 1063a7e0b00SIngo Weinhold path = componentEnd; 1073a7e0b00SIngo Weinhold parent = entry; 1083a7e0b00SIngo Weinhold } 1093a7e0b00SIngo Weinhold 1103a7e0b00SIngo Weinhold if (parent == NULL) 1113a7e0b00SIngo Weinhold return B_BAD_VALUE; 1123a7e0b00SIngo Weinhold 1133a7e0b00SIngo Weinhold _entry = parent; 1143a7e0b00SIngo Weinhold return B_OK; 1153a7e0b00SIngo Weinhold } 1163a7e0b00SIngo Weinhold 1173a7e0b00SIngo Weinhold 1183a7e0b00SIngo Weinhold PackageSettingsItem::Entry* 1193a7e0b00SIngo Weinhold PackageSettingsItem::FindEntry(Entry* parent, const String& name) const 1203a7e0b00SIngo Weinhold { 1213a7e0b00SIngo Weinhold return fEntries.Lookup(EntryKey(parent, name)); 1223a7e0b00SIngo Weinhold } 1233a7e0b00SIngo Weinhold 1243a7e0b00SIngo Weinhold 1253a7e0b00SIngo Weinhold PackageSettingsItem::Entry* 1263a7e0b00SIngo Weinhold PackageSettingsItem::FindEntry(Entry* parent, const char* name) const 1273a7e0b00SIngo Weinhold { 1283a7e0b00SIngo Weinhold return fEntries.Lookup(EntryKey(parent, name)); 1293a7e0b00SIngo Weinhold } 1303a7e0b00SIngo Weinhold 1313a7e0b00SIngo Weinhold 1323a7e0b00SIngo Weinhold status_t 1333a7e0b00SIngo Weinhold PackageSettingsItem::_AddBlackListedEntries(const driver_parameter& parameter) 1343a7e0b00SIngo Weinhold { 1353a7e0b00SIngo Weinhold for (int i = 0; i < parameter.parameter_count; i++) { 1363a7e0b00SIngo Weinhold Entry* entry; 1373a7e0b00SIngo Weinhold status_t error = AddEntry(parameter.parameters[i].name, entry); 1383a7e0b00SIngo Weinhold // abort only in case of serious issues (memory shortage) 1393a7e0b00SIngo Weinhold if (error == B_NO_MEMORY) 1403a7e0b00SIngo Weinhold return error; 1413a7e0b00SIngo Weinhold 1423a7e0b00SIngo Weinhold entry->SetBlackListed(true); 1433a7e0b00SIngo Weinhold } 1443a7e0b00SIngo Weinhold 1453a7e0b00SIngo Weinhold return B_OK; 1463a7e0b00SIngo Weinhold } 1473a7e0b00SIngo Weinhold 1483a7e0b00SIngo Weinhold 1493a7e0b00SIngo Weinhold // #pragma mark - PackageSettings 1503a7e0b00SIngo Weinhold 1513a7e0b00SIngo Weinhold 1523a7e0b00SIngo Weinhold PackageSettings::PackageSettings() 1533a7e0b00SIngo Weinhold : 1543a7e0b00SIngo Weinhold fPackageItems() 1553a7e0b00SIngo Weinhold { 1563a7e0b00SIngo Weinhold } 1573a7e0b00SIngo Weinhold 1583a7e0b00SIngo Weinhold 1593a7e0b00SIngo Weinhold PackageSettings::~PackageSettings() 1603a7e0b00SIngo Weinhold { 1613a7e0b00SIngo Weinhold PackageSettingsItem* item = fPackageItems.Clear(true); 1623a7e0b00SIngo Weinhold while (item != NULL) { 1633a7e0b00SIngo Weinhold PackageSettingsItem* next = item->HashNext(); 1643a7e0b00SIngo Weinhold delete item; 1653a7e0b00SIngo Weinhold item = next; 1663a7e0b00SIngo Weinhold } 1673a7e0b00SIngo Weinhold } 1683a7e0b00SIngo Weinhold 1693a7e0b00SIngo Weinhold 1703a7e0b00SIngo Weinhold status_t 1713a7e0b00SIngo Weinhold PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID, 1723a7e0b00SIngo Weinhold PackageFSMountType mountType) 1733a7e0b00SIngo Weinhold { 1743a7e0b00SIngo Weinhold status_t error = fPackageItems.Init(); 1753a7e0b00SIngo Weinhold if (error != B_OK) 1763a7e0b00SIngo Weinhold RETURN_ERROR(error); 1773a7e0b00SIngo Weinhold 178c04f3a62SIngo Weinhold // First get the safe mode options. Those apply to the system package. 179c04f3a62SIngo Weinhold if (mountType == PACKAGE_FS_MOUNT_TYPE_SYSTEM) { 180c04f3a62SIngo Weinhold void* settingsHandle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); 181c04f3a62SIngo Weinhold if (settingsHandle != NULL) { 182c04f3a62SIngo Weinhold if (const driver_settings* settings 183c04f3a62SIngo Weinhold = get_driver_settings(settingsHandle)) { 184c04f3a62SIngo Weinhold error = _AddPackageSettingsItem("haiku", settings->parameters, 185c04f3a62SIngo Weinhold settings->parameter_count); 186c04f3a62SIngo Weinhold // abort only in case of serious issues (memory shortage) 187c04f3a62SIngo Weinhold if (error == B_NO_MEMORY) 188c04f3a62SIngo Weinhold return error; 189c04f3a62SIngo Weinhold } 190c04f3a62SIngo Weinhold unload_driver_settings(settingsHandle); 191c04f3a62SIngo Weinhold } 192c04f3a62SIngo Weinhold } 193c04f3a62SIngo Weinhold 1943a7e0b00SIngo Weinhold // get the mount point relative settings file path 1953a7e0b00SIngo Weinhold const char* settingsFilePath = mountType == PACKAGE_FS_MOUNT_TYPE_HOME 196*39be4f89SX512 ? &(kUserSettingsGlobalDirectory "/packages") 197*39be4f89SX512 [strlen(kUserConfigDirectory) + 1] 198*39be4f89SX512 : &(kSystemSettingsDirectory "/packages")[strlen(kSystemDirectory) + 1]; 1993a7e0b00SIngo Weinhold 2003a7e0b00SIngo Weinhold // get an absolute path 2013a7e0b00SIngo Weinhold KPath path; 2023a7e0b00SIngo Weinhold if (path.InitCheck() != B_OK) 2033a7e0b00SIngo Weinhold RETURN_ERROR(path.InitCheck()); 2043a7e0b00SIngo Weinhold 2053a7e0b00SIngo Weinhold error = vfs_entry_ref_to_path(mountPointDeviceID, mountPointNodeID, 2063a7e0b00SIngo Weinhold NULL, true, path.LockBuffer(), path.BufferSize()); 2073a7e0b00SIngo Weinhold if (error != B_OK) 2083a7e0b00SIngo Weinhold return error; 2093a7e0b00SIngo Weinhold path.UnlockBuffer(); 2103a7e0b00SIngo Weinhold 2113a7e0b00SIngo Weinhold error = path.Append(settingsFilePath); 2123a7e0b00SIngo Weinhold if (error != B_OK) 2133a7e0b00SIngo Weinhold return error; 2143a7e0b00SIngo Weinhold 2153a7e0b00SIngo Weinhold // load the driver settings 2163a7e0b00SIngo Weinhold void* settingsHandle = load_driver_settings(path.Path()); 2173a7e0b00SIngo Weinhold if (settingsHandle == NULL) 2183a7e0b00SIngo Weinhold return B_ENTRY_NOT_FOUND; 2193a7e0b00SIngo Weinhold CObjectDeleter<void, status_t> settingsDeleter(settingsHandle, 2203a7e0b00SIngo Weinhold &unload_driver_settings); 2213a7e0b00SIngo Weinhold 2223a7e0b00SIngo Weinhold const driver_settings* settings = get_driver_settings(settingsHandle); 2233a7e0b00SIngo Weinhold for (int i = 0; i < settings->parameter_count; i++) { 2243a7e0b00SIngo Weinhold const driver_parameter& parameter = settings->parameters[i]; 2253a7e0b00SIngo Weinhold if (strcmp(parameter.name, "Package") != 0 2263a7e0b00SIngo Weinhold || parameter.value_count < 1) { 2273a7e0b00SIngo Weinhold continue; 2283a7e0b00SIngo Weinhold } 2293a7e0b00SIngo Weinhold 230c04f3a62SIngo Weinhold error = _AddPackageSettingsItem(parameter.values[0], 231c04f3a62SIngo Weinhold parameter.parameters, parameter.parameter_count); 2323a7e0b00SIngo Weinhold // abort only in case of serious issues (memory shortage) 2333a7e0b00SIngo Weinhold if (error == B_NO_MEMORY) 2343a7e0b00SIngo Weinhold return error; 2353a7e0b00SIngo Weinhold } 2363a7e0b00SIngo Weinhold 2373a7e0b00SIngo Weinhold return B_OK; 2383a7e0b00SIngo Weinhold } 2393a7e0b00SIngo Weinhold 2403a7e0b00SIngo Weinhold 2413a7e0b00SIngo Weinhold const PackageSettingsItem* 2423a7e0b00SIngo Weinhold PackageSettings::PackageItemFor(const String& name) const 2433a7e0b00SIngo Weinhold { 2443a7e0b00SIngo Weinhold return fPackageItems.Lookup(name); 2453a7e0b00SIngo Weinhold } 2463a7e0b00SIngo Weinhold 2473a7e0b00SIngo Weinhold 2483a7e0b00SIngo Weinhold status_t 249c04f3a62SIngo Weinhold PackageSettings::_AddPackageSettingsItem(const char* name, 250c04f3a62SIngo Weinhold const driver_parameter* parameters, int parameterCount) 2513a7e0b00SIngo Weinhold { 252c04f3a62SIngo Weinhold // get/create the package item 253c04f3a62SIngo Weinhold PackageSettingsItem* packageItem = fPackageItems.Lookup(StringKey(name)); 254c04f3a62SIngo Weinhold if (packageItem == NULL) { 255c04f3a62SIngo Weinhold packageItem = new(std::nothrow) PackageSettingsItem; 256c04f3a62SIngo Weinhold if (packageItem == NULL || packageItem->Init(name) != B_OK) { 2573a7e0b00SIngo Weinhold delete packageItem; 2583a7e0b00SIngo Weinhold RETURN_ERROR(B_NO_MEMORY); 2593a7e0b00SIngo Weinhold } 2603a7e0b00SIngo Weinhold 2613a7e0b00SIngo Weinhold fPackageItems.Insert(packageItem); 262c04f3a62SIngo Weinhold } 263c04f3a62SIngo Weinhold 264c04f3a62SIngo Weinhold // apply the settings 265c04f3a62SIngo Weinhold return packageItem->ApplySettings(parameters, parameterCount); 2663a7e0b00SIngo Weinhold } 267