1// Settings.cpp
2
3#include <new>
4
5#include <stdio.h>
6#include <stdlib.h>
7
8#include <driver_settings.h>
9#include <FindDirectory.h>
10
11#include "Debug.h"
12#include "HashMap.h"
13#include "IOCtlInfo.h"
14#include "Settings.h"
15
16using std::nothrow;
17
18static const directory_which kDirectories[] = {
19	B_USER_NONPACKAGED_DATA_DIRECTORY,
20	B_USER_DATA_DIRECTORY,
21	B_SYSTEM_NONPACKAGED_DATA_DIRECTORY,
22	B_SYSTEM_DATA_DIRECTORY
23};
24static const char *kFSSubpath = "/userlandfs/file_systems/";
25
26// IOCtlInfoMap
27struct Settings::IOCtlInfoMap : public HashMap<HashKey32<int>, IOCtlInfo*> {
28};
29
30
31// _FindNextParameter
32template<typename container_t>
33static
34const driver_parameter *
35_FindNextParameter(const container_t *container, const char *name,
36	int32 &cookie)
37{
38	const driver_parameter *parameter = NULL;
39	if (container) {
40		for (; !parameter && cookie < container->parameter_count; cookie++) {
41			const driver_parameter &param = container->parameters[cookie];
42			if (!strcmp(param.name, name))
43				parameter = &param;
44		}
45	}
46	return parameter;
47}
48
49// _GetParameterValue
50template<typename container_t>
51static
52const char *
53_GetParameterValue(const container_t *container, const char *name,
54	const char *unknownValue, const char *noArgValue)
55{
56	if (container) {
57		for (int32 i = container->parameter_count - 1; i >= 0; i--) {
58			const driver_parameter &param = container->parameters[i];
59			if (!strcmp(param.name, name)) {
60				if (param.value_count > 0)
61					return param.values[0];
62				return noArgValue;
63			}
64		}
65	}
66	return unknownValue;
67}
68
69// contains
70static inline
71bool
72contains(const char **array, size_t size, const char *value)
73{
74	for (int32 i = 0; i < (int32)size; i++) {
75		if (!strcmp(array[i], value))
76			return true;
77	}
78	return false;
79}
80
81// _GetParameterValue
82template<typename container_t>
83static
84bool
85_GetParameterValue(const container_t *container, const char *name,
86	bool unknownValue, bool noArgValue)
87{
88	// note: container may be NULL
89	const char unknown = 0;
90	const char noArg = 0;
91	const char *value = _GetParameterValue(container, name, &unknown, &noArg);
92	if (value == &unknown)
93		return unknownValue;
94	if (value == &noArg)
95		return noArgValue;
96	const char *trueStrings[]
97		= { "1", "true", "yes", "on", "enable", "enabled" };
98	const char *falseStrings[]
99		= { "0", "false", "no", "off", "disable", "disabled" };
100	if (contains(trueStrings, sizeof(trueStrings) / sizeof(const char*),
101				 value)) {
102		return true;
103	}
104	if (contains(falseStrings, sizeof(falseStrings) / sizeof(const char*),
105				 value)) {
106		return false;
107	}
108	return unknownValue;
109}
110
111// _GetParameterValue
112template<typename container_t>
113static
114int
115_GetParameterValue(const container_t *container, const char *name,
116	int unknownValue, int noArgValue)
117{
118	// note: container may be NULL
119	const char unknown = 0;
120	const char noArg = 0;
121	const char *value = _GetParameterValue(container, name, &unknown, &noArg);
122	if (value == &unknown)
123		return unknownValue;
124	if (value == &noArg)
125		return noArgValue;
126	return atoi(value);
127}
128
129// _FindFSParameter
130static
131const driver_parameter *
132_FindFSParameter(const driver_settings *settings, const char *name)
133{
134	if (settings) {
135		int32 cookie = 0;
136		while (const driver_parameter *parameter
137				= _FindNextParameter(settings, "file_system", cookie)) {
138PRINT(("  found file_system parameter\n"));
139if (parameter->value_count > 0)
140PRINT(("    value: `%s'\n", parameter->values[0]));
141			if (parameter->value_count == 1
142				&& !strcmp(parameter->values[0], name)) {
143				return parameter;
144			}
145		}
146	}
147	return NULL;
148}
149
150// constructor
151Settings::Settings()
152	: fIOCtlInfos(NULL)
153{
154}
155
156// destructor
157Settings::~Settings()
158{
159	Unset();
160}
161
162// SetTo
163status_t
164Settings::SetTo(const char* fsName)
165{
166	if (!fsName)
167		RETURN_ERROR(B_BAD_VALUE);
168	// unset
169	Unset();
170	// create the ioctl info map
171	fIOCtlInfos = new(nothrow) IOCtlInfoMap;
172	if (!fIOCtlInfos)
173		RETURN_ERROR(B_NO_MEMORY);
174
175	// load the driver settings for the FS
176	char path[B_PATH_NAME_LENGTH];
177	for (size_t i = 0; i < sizeof(kDirectories) / sizeof(kDirectories[0]);
178			i++) {
179		if (find_directory(kDirectories[i], -1, false, (char*)&path,
180				B_PATH_NAME_LENGTH) != B_OK) {
181			continue;
182		}
183
184		// construct the path within the directory
185		strlcat(path, kFSSubpath, B_PATH_NAME_LENGTH);
186		strlcat(path, fsName, B_PATH_NAME_LENGTH);
187
188		// load the file at the constructed path
189		void *settings = load_driver_settings((char*)&path);
190		if (!settings)
191			continue;
192
193		// get the settings from the loaded file
194		const driver_settings *ds = get_driver_settings(settings);
195		if (!ds) {
196			unload_driver_settings(settings);
197			continue;
198		}
199
200		// get the parameter from the settings
201		const driver_parameter *fsParameter = NULL;
202		fsParameter = _FindFSParameter(ds, fsName);
203
204		//  init the object and unload the settings
205		if (fsParameter)
206			_Init(ds, fsParameter);
207		unload_driver_settings(settings);
208
209		// if we found the parameter, we're done
210		if (fsParameter)
211			return B_OK;
212	}
213
214	// if we get here, we did not find the parameter
215	return B_ENTRY_NOT_FOUND;
216}
217
218// Unset
219void
220Settings::Unset()
221{
222	if (fIOCtlInfos) {
223		for (IOCtlInfoMap::Iterator it = fIOCtlInfos->GetIterator();
224			 it.HasNext();) {
225			IOCtlInfoMap::Entry entry = it.Next();
226			delete entry.value;
227		}
228		delete fIOCtlInfos;
229		fIOCtlInfos = NULL;
230	}
231}
232
233// GetIOCtlInfo
234const IOCtlInfo*
235Settings::GetIOCtlInfo(int command) const
236{
237	return (fIOCtlInfos ? fIOCtlInfos->Get(command) : NULL);
238}
239
240// Dump
241void
242Settings::Dump() const
243{
244	D(
245		PRINT(("Settings:\n"));
246		if (fIOCtlInfos) {
247			for (IOCtlInfoMap::Iterator it = fIOCtlInfos->GetIterator();
248				 it.HasNext();) {
249				IOCtlInfoMap::Entry entry = it.Next();
250				IOCtlInfo* info = entry.value;
251				PRINT(("  ioctl %d: buffer size: %" B_PRId32
252					", write buffer size: %" B_PRId32 "\n", info->command,
253					info->bufferSize, info->writeBufferSize));
254			}
255		}
256	)
257}
258
259// _Init
260status_t
261Settings::_Init(const driver_settings *settings,
262				const driver_parameter *fsParams)
263{
264PRINT(("Settings::_Init(%p, %p)\n", settings, fsParams));
265	status_t error = B_OK;
266	int32 cookie = 0;
267	while (const driver_parameter *parameter
268			= _FindNextParameter(fsParams, "ioctl", cookie)) {
269		if (parameter->value_count == 1) {
270			int command = atoi(parameter->values[0]);
271			if (command > 0) {
272				IOCtlInfo* info = fIOCtlInfos->Remove(command);
273				if (!info) {
274					info = new(nothrow) IOCtlInfo;
275					if (!info)
276						RETURN_ERROR(B_NO_MEMORY);
277				}
278				info->command = command;
279				info->bufferSize
280					= _GetParameterValue(parameter, "buffer_size", 0, 0);
281				info->writeBufferSize
282					= _GetParameterValue(parameter, "write_buffer_size", 0, 0);
283				info->isBuffer = _GetParameterValue(parameter, "is_buffer",
284					false, false);
285				error = fIOCtlInfos->Put(command, info);
286				if (error != B_OK) {
287					delete info;
288					return error;
289				}
290			}
291		}
292	}
293PRINT(("Settings::_Init() done: %s\n", strerror(error)));
294	return error;
295}
296
297