xref: /haiku/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.cpp (revision 39be4f89f500d489df5a6d8b2162f6e271e1b05e)
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