1/* 2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10#include "Settings.h" 11 12#include <Directory.h> 13#include <FindDirectory.h> 14#include <fs_interface.h> 15#include <Path.h> 16#include <PathMonitor.h> 17#include <String.h> 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22 23 24struct settings_template { 25 uint32 type; 26 const char* name; 27 const settings_template* sub_template; 28 bool parent_value; 29}; 30 31// Interface templates 32 33const static settings_template kInterfaceAddressTemplate[] = { 34 {B_STRING_TYPE, "family", NULL, true}, 35 {B_STRING_TYPE, "address", NULL}, 36 {B_STRING_TYPE, "mask", NULL}, 37 {B_STRING_TYPE, "peer", NULL}, 38 {B_STRING_TYPE, "broadcast", NULL}, 39 {B_STRING_TYPE, "gateway", NULL}, 40 {B_BOOL_TYPE, "auto_config", NULL}, 41 {0, NULL, NULL} 42}; 43 44const static settings_template kInterfaceTemplate[] = { 45 {B_STRING_TYPE, "device", NULL, true}, 46 {B_BOOL_TYPE, "disabled", NULL}, 47 {B_MESSAGE_TYPE, "address", kInterfaceAddressTemplate}, 48 {B_STRING_TYPE, "network", NULL}, 49 {B_INT32_TYPE, "flags", NULL}, 50 {B_INT32_TYPE, "metric", NULL}, 51 {B_INT32_TYPE, "mtu", NULL}, 52 {0, NULL, NULL} 53}; 54 55const static settings_template kInterfacesTemplate[] = { 56 {B_MESSAGE_TYPE, "interface", kInterfaceTemplate}, 57 {0, NULL, NULL} 58}; 59 60// Network templates 61 62const static settings_template kNetworkTemplate[] = { 63 {B_STRING_TYPE, "name", NULL, true}, 64 {B_STRING_TYPE, "mac", NULL}, 65 {B_STRING_TYPE, "password", NULL}, 66 {B_STRING_TYPE, "authentication", NULL}, 67 {B_STRING_TYPE, "cipher", NULL}, 68 {B_STRING_TYPE, "group_cipher", NULL}, 69 {B_STRING_TYPE, "key", NULL}, 70 {0, NULL, NULL} 71}; 72 73const static settings_template kNetworksTemplate[] = { 74 {B_MESSAGE_TYPE, "network", kNetworkTemplate}, 75 {0, NULL, NULL} 76}; 77 78// Service templates 79 80const static settings_template kServiceAddressTemplate[] = { 81 {B_STRING_TYPE, "family", NULL, true}, 82 {B_STRING_TYPE, "type", NULL}, 83 {B_STRING_TYPE, "protocol", NULL}, 84 {B_STRING_TYPE, "address", NULL}, 85 {B_INT32_TYPE, "port", NULL}, 86 {0, NULL, NULL} 87}; 88 89const static settings_template kServiceTemplate[] = { 90 {B_STRING_TYPE, "name", NULL, true}, 91 {B_MESSAGE_TYPE, "address", kServiceAddressTemplate}, 92 {B_STRING_TYPE, "user", NULL}, 93 {B_STRING_TYPE, "group", NULL}, 94 {B_STRING_TYPE, "launch", NULL}, 95 {B_STRING_TYPE, "family", NULL}, 96 {B_STRING_TYPE, "type", NULL}, 97 {B_STRING_TYPE, "protocol", NULL}, 98 {B_INT32_TYPE, "port", NULL}, 99 {B_BOOL_TYPE, "stand_alone", NULL}, 100 {0, NULL, NULL} 101}; 102 103const static settings_template kServicesTemplate[] = { 104 {B_MESSAGE_TYPE, "service", kServiceTemplate}, 105 {0, NULL, NULL} 106}; 107 108 109Settings::Settings() 110{ 111 _Load(); 112} 113 114 115Settings::~Settings() 116{ 117} 118 119 120status_t 121Settings::_GetPath(const char* name, BPath& path) 122{ 123 if (find_directory(B_COMMON_SETTINGS_DIRECTORY, &path, true) != B_OK) 124 return B_ERROR; 125 126 path.Append("network"); 127 create_directory(path.Path(), 0755); 128 129 if (name != NULL) 130 path.Append(name); 131 return B_OK; 132} 133 134 135const settings_template* 136Settings::_FindSettingsTemplate(const settings_template* settingsTemplate, 137 const char* name) 138{ 139 while (settingsTemplate->name != NULL) { 140 if (!strcmp(name, settingsTemplate->name)) 141 return settingsTemplate; 142 143 settingsTemplate++; 144 } 145 146 return NULL; 147} 148 149 150const settings_template* 151Settings::_FindParentValueTemplate(const settings_template* settingsTemplate) 152{ 153 settingsTemplate = settingsTemplate->sub_template; 154 if (settingsTemplate == NULL) 155 return NULL; 156 157 while (settingsTemplate->name != NULL) { 158 if (settingsTemplate->parent_value) 159 return settingsTemplate; 160 161 settingsTemplate++; 162 } 163 164 return NULL; 165} 166 167 168status_t 169Settings::_AddParameter(const driver_parameter& parameter, const char* name, 170 uint32 type, BMessage& message) 171{ 172 for (int32 i = 0; i < parameter.value_count; i++) { 173 switch (type) { 174 case B_STRING_TYPE: 175 message.AddString(name, parameter.values[i]); 176 break; 177 case B_INT32_TYPE: 178 message.AddInt32(name, atoi(parameter.values[i])); 179 break; 180 case B_BOOL_TYPE: 181 if (!strcasecmp(parameter.values[i], "true") 182 || !strcasecmp(parameter.values[i], "on") 183 || !strcasecmp(parameter.values[i], "enabled") 184 || !strcasecmp(parameter.values[i], "1")) 185 message.AddBool(name, true); 186 else 187 message.AddBool(name, false); 188 break; 189 } 190 } 191 if (type == B_BOOL_TYPE && parameter.value_count == 0) { 192 // boolean parameters are always true 193 message.AddBool(name, true); 194 } 195 196 return B_OK; 197} 198 199 200status_t 201Settings::_ConvertFromDriverParameter(const driver_parameter& parameter, 202 const settings_template* settingsTemplate, BMessage& message) 203{ 204 settingsTemplate = _FindSettingsTemplate(settingsTemplate, parameter.name); 205 if (settingsTemplate == NULL) { 206 fprintf(stderr, "unknown parameter %s\n", parameter.name); 207 return B_BAD_VALUE; 208 } 209 210 _AddParameter(parameter, parameter.name, settingsTemplate->type, message); 211 212 if (settingsTemplate->type == B_MESSAGE_TYPE 213 && parameter.parameter_count > 0) { 214 status_t status = B_OK; 215 BMessage subMessage; 216 for (int32 j = 0; j < parameter.parameter_count; j++) { 217 status = _ConvertFromDriverParameter(parameter.parameters[j], 218 settingsTemplate->sub_template, subMessage); 219 if (status != B_OK) 220 break; 221 222 const settings_template* parentValueTemplate 223 = _FindParentValueTemplate(settingsTemplate); 224 if (parentValueTemplate != NULL) { 225 _AddParameter(parameter, parentValueTemplate->name, 226 parentValueTemplate->type, subMessage); 227 } 228 } 229 if (status == B_OK) 230 message.AddMessage(parameter.name, &subMessage); 231 } 232 233 return B_OK; 234} 235 236 237status_t 238Settings::_ConvertFromDriverSettings(const driver_settings& settings, 239 const settings_template* settingsTemplate, BMessage& message) 240{ 241 message.MakeEmpty(); 242 243 for (int32 i = 0; i < settings.parameter_count; i++) { 244 status_t status = _ConvertFromDriverParameter(settings.parameters[i], 245 settingsTemplate, message); 246 if (status == B_BAD_VALUE) { 247 // ignore unknown entries 248 continue; 249 } 250 if (status != B_OK) 251 return status; 252 } 253 254 return B_OK; 255} 256 257 258status_t 259Settings::_ConvertFromDriverSettings(const char* name, 260 const settings_template* settingsTemplate, BMessage& message) 261{ 262 BPath path; 263 status_t status = _GetPath(name, path); 264 if (status != B_OK) 265 return status; 266 267 void* handle = load_driver_settings(path.Path()); 268 if (handle == NULL) 269 return B_ENTRY_NOT_FOUND; 270 271 const driver_settings* settings = get_driver_settings(handle); 272 if (settings != NULL) { 273 status = _ConvertFromDriverSettings(*settings, settingsTemplate, 274 message); 275 } 276 277 unload_driver_settings(handle); 278 return status; 279} 280 281 282status_t 283Settings::_AppendSettings(const settings_template* settingsTemplate, 284 BString& settings, const BMessage& message, const char* name, 285 type_code type, int32 count, const char* settingName) 286{ 287 const settings_template* valueTemplate 288 = _FindSettingsTemplate(settingsTemplate, name); 289 if (valueTemplate == NULL) { 290 fprintf(stderr, "unknown field %s\n", name); 291 return B_BAD_VALUE; 292 } 293 294 if (valueTemplate->type != type) { 295 fprintf(stderr, "field type mismatch %s\n", name); 296 return B_BAD_VALUE; 297 } 298 299 if (settingName == NULL) 300 settingName = name; 301 302 if (type != B_MESSAGE_TYPE) { 303 settings.Append("\n"); 304 settings.Append(settingName); 305 settings.Append("\t"); 306 } 307 308 for (int32 valueIndex = 0; valueIndex < count; valueIndex++) { 309 if (valueIndex > 0 && type != B_MESSAGE_TYPE) 310 settings.Append(" "); 311 312 switch (type) { 313 case B_BOOL_TYPE: 314 { 315 bool value; 316 status_t result = message.FindBool(name, valueIndex, &value); 317 if (result != B_OK) 318 return result; 319 320 settings.Append(value ? "true" : "false"); 321 break; 322 } 323 324 case B_STRING_TYPE: 325 { 326 const char* value = NULL; 327 status_t result = message.FindString(name, valueIndex, &value); 328 if (result != B_OK) 329 return result; 330 331 settings.Append(value); 332 break; 333 } 334 335 case B_INT32_TYPE: 336 { 337 int32 value; 338 status_t result = message.FindInt32(name, valueIndex, &value); 339 if (result != B_OK) 340 return result; 341 342 char buffer[100]; 343 snprintf(buffer, sizeof(buffer), "%"B_PRId32, value); 344 settings.Append(buffer, sizeof(buffer)); 345 break; 346 } 347 348 case B_MESSAGE_TYPE: 349 { 350 BMessage subMessage; 351 status_t result = message.FindMessage(name, valueIndex, 352 &subMessage); 353 if (result != B_OK) 354 return result; 355 356 const settings_template* parentValueTemplate 357 = _FindParentValueTemplate(valueTemplate); 358 if (parentValueTemplate != NULL) { 359 _AppendSettings(valueTemplate->sub_template, settings, 360 subMessage, parentValueTemplate->name, 361 parentValueTemplate->type, 1, name); 362 subMessage.RemoveName(parentValueTemplate->name); 363 } 364 365 BString subSettings; 366 _ConvertToDriverSettings(valueTemplate->sub_template, 367 subSettings, subMessage); 368 subSettings.ReplaceAll("\n", "\n\t"); 369 subSettings.RemoveFirst("\n"); 370 371 settings.Append(" {\n"); 372 settings.Append(subSettings); 373 settings.Append("\n}"); 374 } 375 } 376 } 377 378 return B_OK; 379} 380 381 382status_t 383Settings::_ConvertToDriverSettings(const settings_template* settingsTemplate, 384 BString& settings, const BMessage& message) 385{ 386 int32 index = 0; 387 char *name = NULL; 388 type_code type; 389 int32 count = 0; 390 391 while (message.GetInfo(B_ANY_TYPE, index++, &name, &type, &count) == B_OK) { 392 status_t result = _AppendSettings(settingsTemplate, settings, message, 393 name, type, count); 394 if (result != B_OK) 395 return result; 396 } 397 398 return B_OK; 399} 400 401 402status_t 403Settings::_ConvertToDriverSettings(const char* name, 404 const settings_template* settingsTemplate, const BMessage& message) 405{ 406 BPath path; 407 status_t status = _GetPath(name, path); 408 if (status != B_OK) 409 return status; 410 411 BString settings; 412 status = _ConvertToDriverSettings(settingsTemplate, settings, message); 413 if (status == B_OK) { 414 settings.RemoveFirst("\n"); 415 // TODO: actually write the settings.String() out into the file 416 printf("settings:\n%s\n", settings.String()); 417 } 418 419 return status; 420} 421 422 423status_t 424Settings::_Load(const char* name, uint32* _type) 425{ 426 status_t status = B_ENTRY_NOT_FOUND; 427 428 if (name == NULL || strcmp(name, "interfaces") == 0) { 429 status = _ConvertFromDriverSettings("interfaces", kInterfacesTemplate, 430 fInterfaces); 431 if (status == B_OK && _type != NULL) 432 *_type = kMsgInterfaceSettingsUpdated; 433 } 434 if (name == NULL || strcmp(name, "wireless_networks") == 0) { 435 status = _ConvertFromDriverSettings("wireless_networks", 436 kNetworksTemplate, fNetworks); 437 if (status == B_OK && _type != NULL) 438 *_type = kMsgInterfaceSettingsUpdated; 439 } 440 if (name == NULL || strcmp(name, "services") == 0) { 441 status = _ConvertFromDriverSettings("services", kServicesTemplate, 442 fServices); 443 if (status == B_OK && _type != NULL) 444 *_type = kMsgServiceSettingsUpdated; 445 } 446 447 return status; 448} 449 450 451status_t 452Settings::_Save(const char* name) 453{ 454 status_t status = B_ENTRY_NOT_FOUND; 455 456 if (name == NULL || strcmp(name, "interfaces") == 0) { 457 status = _ConvertToDriverSettings("interfaces", kInterfacesTemplate, 458 fInterfaces); 459 } 460 if (name == NULL || strcmp(name, "wireless_networks") == 0) { 461 status = _ConvertToDriverSettings("wireless_networks", 462 kNetworksTemplate, fNetworks); 463 } 464 if (name == NULL || strcmp(name, "services") == 0) { 465 status = _ConvertToDriverSettings("services", kServicesTemplate, 466 fServices); 467 } 468 469 return status; 470} 471 472 473status_t 474Settings::_StartWatching(const char* name, const BMessenger& target) 475{ 476 BPath path; 477 status_t status = _GetPath(name, path); 478 if (status != B_OK) 479 return status; 480 481 return BPrivate::BPathMonitor::StartWatching(path.Path(), B_WATCH_STAT, 482 target); 483} 484 485 486status_t 487Settings::StartMonitoring(const BMessenger& target) 488{ 489 if (_IsWatching(target)) 490 return B_OK; 491 if (_IsWatching()) 492 StopMonitoring(fListener); 493 494 fListener = target; 495 496 status_t status = _StartWatching("interfaces", target); 497 if (status == B_OK) 498 status = _StartWatching("wireless_networks", target); 499 if (status == B_OK) 500 status = _StartWatching("services", target); 501 502 return status; 503} 504 505 506status_t 507Settings::StopMonitoring(const BMessenger& target) 508{ 509 // TODO: this needs to be changed in case the server will watch 510 // anything else but settings 511 return BPrivate::BPathMonitor::StopWatching(target); 512} 513 514 515status_t 516Settings::Update(BMessage* message) 517{ 518 const char* pathName; 519 int32 opcode; 520 if (message->FindInt32("opcode", &opcode) != B_OK 521 || message->FindString("path", &pathName) != B_OK) 522 return B_BAD_VALUE; 523 524 BPath settingsFolderPath; 525 _GetPath(NULL, settingsFolderPath); 526 if (strncmp(pathName, settingsFolderPath.Path(), 527 strlen(settingsFolderPath.Path()))) { 528 return B_NAME_NOT_FOUND; 529 } 530 531 if (message->FindBool("removed")) { 532 // for now, we only consider existing settings files 533 // (ie. deleting "services" won't stop any) 534 return B_OK; 535 } 536 537 int32 fields; 538 if (opcode == B_STAT_CHANGED 539 && message->FindInt32("fields", &fields) == B_OK 540 && (fields & (B_STAT_MODIFICATION_TIME | B_STAT_SIZE)) == 0) { 541 // only update when the modified time or size has changed 542 return B_OK; 543 } 544 545 BPath path(pathName); 546 uint32 type; 547 if (_Load(path.Leaf(), &type) == B_OK) { 548 BMessage update(type); 549 fListener.SendMessage(&update); 550 } 551 552 return B_OK; 553} 554 555 556status_t 557Settings::GetNextInterface(uint32& cookie, BMessage& interface) 558{ 559 status_t status = fInterfaces.FindMessage("interface", cookie, &interface); 560 if (status != B_OK) 561 return status; 562 563 cookie++; 564 return B_OK; 565} 566 567 568int32 569Settings::CountNetworks() const 570{ 571 int32 count = 0; 572 if (fNetworks.GetInfo("network", NULL, &count) != B_OK) 573 return 0; 574 575 return count; 576} 577 578 579status_t 580Settings::GetNextNetwork(uint32& cookie, BMessage& network) const 581{ 582 status_t status = fNetworks.FindMessage("network", cookie, &network); 583 if (status != B_OK) 584 return status; 585 586 cookie++; 587 return B_OK; 588} 589 590 591status_t 592Settings::AddNetwork(const BMessage& network) 593{ 594 const char* name = NULL; 595 network.FindString("name", &name); 596 RemoveNetwork(name); 597 598 status_t result = fNetworks.AddMessage("network", &network); 599 if (result != B_OK) 600 return result; 601 602 return _Save("wireless_networks"); 603} 604 605 606status_t 607Settings::RemoveNetwork(const char* name) 608{ 609 int32 index = 0; 610 BMessage network; 611 while (fNetworks.FindMessage("network", index, &network) == B_OK) { 612 const char* networkName = NULL; 613 if (network.FindString("name", &networkName) == B_OK 614 && strcmp(networkName, name) == 0) { 615 fNetworks.RemoveData("network", index); 616 return _Save("wireless_networks"); 617 } 618 619 index++; 620 } 621 622 return B_ENTRY_NOT_FOUND; 623} 624 625 626status_t 627Settings::GetNextService(uint32& cookie, BMessage& service) 628{ 629 status_t status = fServices.FindMessage("service", cookie, &service); 630 if (status != B_OK) 631 return status; 632 633 cookie++; 634 return B_OK; 635} 636 637 638const BMessage& 639Settings::Services() const 640{ 641 return fServices; 642} 643 644