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