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