xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Settings.cpp (revision 71452e98334eaac603bf542d159e24788a46bebb)
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 
16 using std::nothrow;
17 
18 static 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 };
24 static const char *kFSSubpath = "/userlandfs/file_systems/";
25 
26 // IOCtlInfoMap
27 struct Settings::IOCtlInfoMap : public HashMap<HashKey32<int>, IOCtlInfo*> {
28 };
29 
30 
31 // _FindNextParameter
32 template<typename container_t>
33 static
34 const 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
50 template<typename container_t>
51 static
52 const 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
70 static inline
71 bool
72 contains(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
82 template<typename container_t>
83 static
84 bool
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
112 template<typename container_t>
113 static
114 int
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
130 static
131 const 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)) {
138 PRINT(("  found file_system parameter\n"));
139 if (parameter->value_count > 0)
140 PRINT(("    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
151 Settings::Settings()
152 	: fIOCtlInfos(NULL)
153 {
154 }
155 
156 // destructor
157 Settings::~Settings()
158 {
159 	Unset();
160 }
161 
162 // SetTo
163 status_t
164 Settings::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
219 void
220 Settings::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
234 const IOCtlInfo*
235 Settings::GetIOCtlInfo(int command) const
236 {
237 	return (fIOCtlInfos ? fIOCtlInfos->Get(command) : NULL);
238 }
239 
240 // Dump
241 void
242 Settings::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
260 status_t
261 Settings::_Init(const driver_settings *settings,
262 				const driver_parameter *fsParams)
263 {
264 PRINT(("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 	}
293 PRINT(("Settings::_Init() done: %s\n", strerror(error)));
294 	return error;
295 }
296 
297