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 ¶m = container->parameters[cookie]; 42 if (!strcmp(param.name, name)) 43 parameter = ¶m; 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 ¶m = 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