xref: /haiku/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.cpp (revision e304f35430187430902fcf5ed57be21f6e0cc301)
1 /*
2  * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "PackageSettings.h"
8 
9 #include <driver_settings.h>
10 
11 #include <AutoDeleter.h>
12 #include <directories.h>
13 #include <fs/KPath.h>
14 #include <vfs.h>
15 
16 #include "DebugSupport.h"
17 
18 
19 static const char* const kEntryBlacklistParameterName = "EntryBlacklist";
20 
21 
22 // #pragma mark - PackageSettingsItem
23 
24 
25 PackageSettingsItem::PackageSettingsItem()
26 	:
27 	fName(),
28 	fEntries()
29 {
30 }
31 
32 
33 PackageSettingsItem::~PackageSettingsItem()
34 {
35 	Entry* entry = fEntries.Clear(true);
36 	while (entry != NULL) {
37 		Entry* next = entry->HashNext();
38 		delete entry;
39 		entry = next;
40 	}
41 }
42 
43 
44 status_t
45 PackageSettingsItem::Init(const char* name)
46 {
47 	if (!fName.SetTo(name) || fEntries.Init() != B_OK)
48 		RETURN_ERROR(B_NO_MEMORY);
49 	return B_OK;
50 }
51 
52 
53 status_t
54 PackageSettingsItem::ApplySettings(const driver_parameter* parameters,
55 	int parameterCount)
56 {
57 	for (int i = 0; i < parameterCount; i++) {
58 		const driver_parameter& subParameter = parameters[i];
59 		if (strcmp(subParameter.name, kEntryBlacklistParameterName) != 0)
60 			continue;
61 
62 		status_t error = _AddBlackListedEntries(subParameter);
63 		// abort only in case of serious issues (memory shortage)
64 		if (error == B_NO_MEMORY)
65 			return error;
66 	}
67 
68 	return B_OK;
69 }
70 
71 
72 void
73 PackageSettingsItem::AddEntry(Entry* entry)
74 {
75 	fEntries.Insert(entry);
76 }
77 
78 
79 status_t
80 PackageSettingsItem::AddEntry(const char* path, Entry*& _entry)
81 {
82 	Entry* parent = NULL;
83 
84 	while (*path != '\0') {
85 		while (*path == '/') {
86 			path++;
87 			continue;
88 		}
89 
90 		const char* componentEnd = strchr(path, '/');
91 		if (componentEnd == NULL)
92 			componentEnd = path + strlen(path);
93 
94 		String name;
95 		if (!name.SetTo(path, componentEnd - path))
96 			RETURN_ERROR(B_NO_MEMORY);
97 
98 		Entry* entry = FindEntry(parent, name);
99 		if (entry == NULL) {
100 			entry = new(std::nothrow) Entry(parent, name);
101 			if (entry == NULL)
102 				RETURN_ERROR(B_NO_MEMORY);
103 			AddEntry(entry);
104 		}
105 
106 		path = componentEnd;
107 		parent = entry;
108 	}
109 
110 	if (parent == NULL)
111 		return B_BAD_VALUE;
112 
113 	_entry = parent;
114 	return B_OK;
115 }
116 
117 
118 PackageSettingsItem::Entry*
119 PackageSettingsItem::FindEntry(Entry* parent, const String& name) const
120 {
121 	return fEntries.Lookup(EntryKey(parent, name));
122 }
123 
124 
125 PackageSettingsItem::Entry*
126 PackageSettingsItem::FindEntry(Entry* parent, const char* name) const
127 {
128 	return fEntries.Lookup(EntryKey(parent, name));
129 }
130 
131 
132 status_t
133 PackageSettingsItem::_AddBlackListedEntries(const driver_parameter& parameter)
134 {
135 	for (int i = 0; i < parameter.parameter_count; i++) {
136 		Entry* entry;
137 		status_t error = AddEntry(parameter.parameters[i].name, entry);
138 		// abort only in case of serious issues (memory shortage)
139 		if (error == B_NO_MEMORY)
140 			return error;
141 
142 		entry->SetBlackListed(true);
143 	}
144 
145 	return B_OK;
146 }
147 
148 
149 // #pragma mark - PackageSettings
150 
151 
152 PackageSettings::PackageSettings()
153 	:
154 	fPackageItems()
155 {
156 }
157 
158 
159 PackageSettings::~PackageSettings()
160 {
161 	PackageSettingsItem* item = fPackageItems.Clear(true);
162 	while (item != NULL) {
163 		PackageSettingsItem* next = item->HashNext();
164 		delete item;
165 		item = next;
166 	}
167 }
168 
169 
170 status_t
171 PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID,
172 	PackageFSMountType mountType)
173 {
174 	status_t error = fPackageItems.Init();
175 	if (error != B_OK)
176 		RETURN_ERROR(error);
177 
178 	// First get the safe mode options. Those apply to the system package.
179 	if (mountType == PACKAGE_FS_MOUNT_TYPE_SYSTEM) {
180 		void* settingsHandle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
181 		if (settingsHandle != NULL) {
182 			if (const driver_settings* settings
183 					= get_driver_settings(settingsHandle)) {
184 				error = _AddPackageSettingsItem("haiku", settings->parameters,
185 					settings->parameter_count);
186 				// abort only in case of serious issues (memory shortage)
187 				if (error == B_NO_MEMORY)
188 					return error;
189 			}
190 			unload_driver_settings(settingsHandle);
191 		}
192 	}
193 
194 	// get the mount point relative settings file path
195 	const char* settingsFilePath = mountType == PACKAGE_FS_MOUNT_TYPE_HOME
196 		? &(kUserSettingsGlobalDirectory "/packages")
197 			[strlen(kUserConfigDirectory) + 1]
198 		: &(kSystemSettingsDirectory "/packages")[strlen(kSystemDirectory) + 1];
199 
200 	// get an absolute path
201 	KPath path;
202 	if (path.InitCheck() != B_OK)
203 		RETURN_ERROR(path.InitCheck());
204 
205 	error = vfs_entry_ref_to_path(mountPointDeviceID, mountPointNodeID,
206 		NULL, true, path.LockBuffer(), path.BufferSize());
207 	if (error != B_OK)
208 		return error;
209 	path.UnlockBuffer();
210 
211 	error = path.Append(settingsFilePath);
212 	if (error != B_OK)
213 		return error;
214 
215 	// load the driver settings
216 	void* settingsHandle = load_driver_settings(path.Path());
217 	if (settingsHandle == NULL)
218 		return B_ENTRY_NOT_FOUND;
219 	CObjectDeleter<void, status_t> settingsDeleter(settingsHandle,
220 		&unload_driver_settings);
221 
222 	const driver_settings* settings = get_driver_settings(settingsHandle);
223 	for (int i = 0; i < settings->parameter_count; i++) {
224 		const driver_parameter& parameter = settings->parameters[i];
225 		if (strcmp(parameter.name, "Package") != 0
226 			|| parameter.value_count < 1) {
227 			continue;
228 		}
229 
230 		error = _AddPackageSettingsItem(parameter.values[0],
231 			parameter.parameters, parameter.parameter_count);
232 		// abort only in case of serious issues (memory shortage)
233 		if (error == B_NO_MEMORY)
234 			return error;
235 	}
236 
237 	return B_OK;
238 }
239 
240 
241 const PackageSettingsItem*
242 PackageSettings::PackageItemFor(const String& name) const
243 {
244 	return fPackageItems.Lookup(name);
245 }
246 
247 
248 status_t
249 PackageSettings::_AddPackageSettingsItem(const char* name,
250 	const driver_parameter* parameters, int parameterCount)
251 {
252 	// get/create the package item
253 	PackageSettingsItem* packageItem = fPackageItems.Lookup(StringKey(name));
254 	if (packageItem == NULL) {
255 		packageItem = new(std::nothrow) PackageSettingsItem;
256 		if (packageItem == NULL || packageItem->Init(name) != B_OK) {
257 			delete packageItem;
258 			RETURN_ERROR(B_NO_MEMORY);
259 		}
260 
261 		fPackageItems.Insert(packageItem);
262 	}
263 
264 	// apply the settings
265 	return packageItem->ApplySettings(parameters, parameterCount);
266 }
267