1 /* 2 * Copyright 2004-2009, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marcus Overhagen 7 * Axel Dörfler, axeld@pinc-software.de 8 * Jérôme Duval 9 */ 10 11 12 //! Manager for input_server add-ons (devices, filters, methods) 13 14 15 #include "AddOnManager.h" 16 17 #include <stdio.h> 18 #include <string.h> 19 20 #include <Autolock.h> 21 #include <Deskbar.h> 22 #include <Directory.h> 23 #include <Entry.h> 24 #include <FindDirectory.h> 25 #include <image.h> 26 #include <Path.h> 27 #include <Roster.h> 28 #include <String.h> 29 30 #include <PathMonitor.h> 31 32 #include "InputServer.h" 33 #include "InputServerTypes.h" 34 #include "MethodReplicant.h" 35 36 37 #undef TRACE 38 //#define TRACE_ADD_ON_MONITOR 39 #ifdef TRACE_ADD_ON_MONITOR 40 # define TRACE(x...) debug_printf(x) 41 # define ERROR(x...) debug_printf(x) 42 #else 43 # define TRACE(x...) ; 44 // TODO: probably better to the syslog 45 # define ERROR(x...) debug_printf(x) 46 #endif 47 48 49 50 class AddOnManager::MonitorHandler : public AddOnMonitorHandler { 51 public: 52 MonitorHandler(AddOnManager* manager) 53 { 54 fManager = manager; 55 } 56 57 virtual void AddOnEnabled(const add_on_entry_info* entryInfo) 58 { 59 CALLED(); 60 entry_ref ref; 61 make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node, 62 entryInfo->name, &ref); 63 BEntry entry(&ref, false); 64 65 fManager->_RegisterAddOn(entry); 66 } 67 68 virtual void AddOnDisabled(const add_on_entry_info* entryInfo) 69 { 70 CALLED(); 71 entry_ref ref; 72 make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node, 73 entryInfo->name, &ref); 74 BEntry entry(&ref, false); 75 76 fManager->_UnregisterAddOn(entry); 77 } 78 79 private: 80 AddOnManager* fManager; 81 }; 82 83 84 // #pragma mark - 85 86 87 template<class T> T* 88 instantiate_add_on(image_id image, const char* path, const char* type) 89 { 90 T* (*instantiateFunction)(); 91 92 BString functionName = "instantiate_input_"; 93 functionName += type; 94 95 if (get_image_symbol(image, functionName.String(), B_SYMBOL_TYPE_TEXT, 96 (void**)&instantiateFunction) < B_OK) { 97 ERROR("AddOnManager::_RegisterAddOn(): can't find %s() in \"%s\"\n", 98 functionName.String(), path); 99 return NULL; 100 } 101 102 T* addOn = (*instantiateFunction)(); 103 if (addOn == NULL) { 104 ERROR("AddOnManager::_RegisterAddOn(): %s() in \"%s\" returned " 105 "NULL\n", functionName.String(), path); 106 return NULL; 107 } 108 109 status_t status = addOn->InitCheck(); 110 if (status != B_OK) { 111 ERROR("AddOnManager::_RegisterAddOn(): InitCheck() in \"%s\" " 112 "returned %s\n", path, strerror(status)); 113 delete addOn; 114 return NULL; 115 } 116 117 return addOn; 118 } 119 120 121 // #pragma mark - 122 123 124 AddOnManager::AddOnManager(bool safeMode) 125 : BLooper("add-on manager"), 126 fSafeMode(safeMode) 127 { 128 } 129 130 131 AddOnManager::~AddOnManager() 132 { 133 } 134 135 136 void 137 AddOnManager::LoadState() 138 { 139 _RegisterAddOns(); 140 } 141 142 143 void 144 AddOnManager::SaveState() 145 { 146 CALLED(); 147 _UnregisterAddOns(); 148 } 149 150 151 // #pragma mark - 152 153 154 void 155 AddOnManager::_RegisterAddOns() 156 { 157 CALLED(); 158 BAutolock locker(this); 159 status_t err; 160 161 fHandler = new MonitorHandler(this); 162 fAddOnMonitor = new AddOnMonitor(fHandler); 163 164 err = fAddOnMonitor->InitCheck(); 165 if (err != B_OK) { 166 ERROR("AddOnManager::RegisterAddOns(): fAddOnMonitor->InitCheck() " 167 "returned %s\n", strerror(err)); 168 return; 169 } 170 171 const directory_which directories[] = { 172 B_USER_ADDONS_DIRECTORY, 173 B_COMMON_ADDONS_DIRECTORY, 174 B_BEOS_ADDONS_DIRECTORY 175 }; 176 const char* subDirectories[] = { 177 "input_server/devices", 178 "input_server/filters", 179 "input_server/methods" 180 }; 181 int32 subDirectoryCount = sizeof(subDirectories) / sizeof(const char*); 182 183 node_ref nref; 184 BDirectory directory; 185 BPath path; 186 // when safemode, only B_BEOS_ADDONS_DIRECTORY is used 187 for (uint32 i = fSafeMode ? 2 : 0; 188 i < sizeof(directories) / sizeof(directory_which); i++) { 189 for (int32 j = 0; j < subDirectoryCount; j++) { 190 if (find_directory(directories[i], &path) == B_OK 191 && path.Append(subDirectories[j]) == B_OK 192 && directory.SetTo(path.Path()) == B_OK 193 && directory.GetNodeRef(&nref) == B_OK) { 194 fHandler->AddDirectory(&nref); 195 } 196 } 197 } 198 } 199 200 201 void 202 AddOnManager::_UnregisterAddOns() 203 { 204 BAutolock locker(this); 205 206 BMessenger messenger(fAddOnMonitor); 207 messenger.SendMessage(B_QUIT_REQUESTED); 208 int32 exitValue; 209 wait_for_thread(fAddOnMonitor->Thread(), &exitValue); 210 delete fHandler; 211 fHandler = NULL; 212 213 // We have to stop manually the add-ons because the monitor doesn't 214 // disable them on exit 215 216 while (device_info* info = fDeviceList.RemoveItemAt(0)) { 217 gInputServer->StartStopDevices(*info->add_on, false); 218 delete info; 219 } 220 221 // TODO: what about the filters/methods lists in the input_server? 222 223 while (filter_info* info = fFilterList.RemoveItemAt(0)) { 224 delete info; 225 } 226 227 while (method_info* info = fMethodList.RemoveItemAt(0)) { 228 delete info; 229 } 230 } 231 232 233 bool 234 AddOnManager::_IsDevice(const char* path) const 235 { 236 return strstr(path, "input_server/devices") != 0; 237 } 238 239 240 bool 241 AddOnManager::_IsFilter(const char* path) const 242 { 243 return strstr(path, "input_server/filters") != 0; 244 } 245 246 247 bool 248 AddOnManager::_IsMethod(const char* path) const 249 { 250 return strstr(path, "input_server/methods") != 0; 251 } 252 253 254 status_t 255 AddOnManager::_RegisterAddOn(BEntry& entry) 256 { 257 BPath path(&entry); 258 259 entry_ref ref; 260 status_t status = entry.GetRef(&ref); 261 if (status < B_OK) 262 return status; 263 264 TRACE("AddOnManager::RegisterAddOn(): trying to load \"%s\"\n", 265 path.Path()); 266 267 image_id image = load_add_on(path.Path()); 268 if (image < B_OK) { 269 ERROR("load addon %s failed\n", path.Path()); 270 return image; 271 } 272 273 status = B_ERROR; 274 275 if (_IsDevice(path.Path())) { 276 BInputServerDevice* device = instantiate_add_on<BInputServerDevice>( 277 image, path.Path(), "device"); 278 if (device != NULL) 279 status = _RegisterDevice(device, ref, image); 280 } else if (_IsFilter(path.Path())) { 281 BInputServerFilter* filter = instantiate_add_on<BInputServerFilter>( 282 image, path.Path(), "filter"); 283 if (filter != NULL) 284 status = _RegisterFilter(filter, ref, image); 285 } else if (_IsMethod(path.Path())) { 286 BInputServerMethod* method = instantiate_add_on<BInputServerMethod>( 287 image, path.Path(), "method"); 288 if (method != NULL) 289 status = _RegisterMethod(method, ref, image); 290 } else { 291 ERROR("AddOnManager::_RegisterAddOn(): addon type not found for " 292 "\"%s\" \n", path.Path()); 293 } 294 295 if (status != B_OK) 296 unload_add_on(image); 297 298 return status; 299 } 300 301 302 status_t 303 AddOnManager::_UnregisterAddOn(BEntry& entry) 304 { 305 BPath path(&entry); 306 307 entry_ref ref; 308 status_t status = entry.GetRef(&ref); 309 if (status < B_OK) 310 return status; 311 312 TRACE("AddOnManager::UnregisterAddOn(): trying to unload \"%s\"\n", 313 path.Path()); 314 315 BAutolock _(this); 316 317 if (_IsDevice(path.Path())) { 318 for (int32 i = fDeviceList.CountItems(); i-- > 0;) { 319 device_info* info = fDeviceList.ItemAt(i); 320 if (!strcmp(info->ref.name, ref.name)) { 321 gInputServer->StartStopDevices(*info->add_on, false); 322 delete fDeviceList.RemoveItemAt(i); 323 break; 324 } 325 } 326 } else if (_IsFilter(path.Path())) { 327 for (int32 i = fFilterList.CountItems(); i-- > 0;) { 328 filter_info* info = fFilterList.ItemAt(i); 329 if (!strcmp(info->ref.name, ref.name)) { 330 BAutolock locker(InputServer::gInputFilterListLocker); 331 InputServer::gInputFilterList.RemoveItem(info->add_on); 332 delete fFilterList.RemoveItemAt(i); 333 break; 334 } 335 } 336 } else if (_IsMethod(path.Path())) { 337 BInputServerMethod* method = NULL; 338 339 for (int32 i = fMethodList.CountItems(); i-- > 0;) { 340 method_info* info = fMethodList.ItemAt(i); 341 if (!strcmp(info->ref.name, ref.name)) { 342 BAutolock locker(InputServer::gInputMethodListLocker); 343 InputServer::gInputMethodList.RemoveItem(info->add_on); 344 method = info->add_on; 345 // this will only be used as a cookie, and not referenced 346 // anymore 347 delete fMethodList.RemoveItemAt(i); 348 break; 349 } 350 } 351 352 if (fMethodList.CountItems() <= 0) { 353 // we remove the method replicant 354 BDeskbar().RemoveItem(REPLICANT_CTL_NAME); 355 gInputServer->SetMethodReplicant(NULL); 356 } else if (method != NULL) { 357 BMessage msg(IS_REMOVE_METHOD); 358 msg.AddInt32("cookie", (uint32)method); 359 if (gInputServer->MethodReplicant()) 360 gInputServer->MethodReplicant()->SendMessage(&msg); 361 } 362 } 363 364 return B_OK; 365 } 366 367 368 //! Takes over ownership of the \a device, regardless of success. 369 status_t 370 AddOnManager::_RegisterDevice(BInputServerDevice* device, const entry_ref& ref, 371 image_id addOnImage) 372 { 373 BAutolock locker(this); 374 375 for (int32 i = fDeviceList.CountItems(); i-- > 0;) { 376 device_info* info = fDeviceList.ItemAt(i); 377 if (!strcmp(info->ref.name, ref.name)) { 378 // we already know this device 379 delete device; 380 return B_NAME_IN_USE; 381 } 382 } 383 384 TRACE("AddOnManager::RegisterDevice, name %s\n", ref.name); 385 386 device_info* info = new(std::nothrow) device_info; 387 if (info == NULL) { 388 delete device; 389 return B_NO_MEMORY; 390 } 391 392 info->ref = ref; 393 info->add_on = device; 394 395 if (!fDeviceList.AddItem(info)) { 396 delete info; 397 return B_NO_MEMORY; 398 } 399 400 info->image = addOnImage; 401 402 return B_OK; 403 } 404 405 406 //! Takes over ownership of the \a filter, regardless of success. 407 status_t 408 AddOnManager::_RegisterFilter(BInputServerFilter* filter, const entry_ref& ref, 409 image_id addOnImage) 410 { 411 BAutolock _(this); 412 413 for (int32 i = fFilterList.CountItems(); i-- > 0;) { 414 filter_info* info = fFilterList.ItemAt(i); 415 if (!strcmp(info->ref.name, ref.name)) { 416 // we already know this ref 417 delete filter; 418 return B_NAME_IN_USE; 419 } 420 } 421 422 TRACE("%s, name %s\n", __PRETTY_FUNCTION__, ref.name); 423 424 filter_info* info = new(std::nothrow) filter_info; 425 if (info == NULL) { 426 delete filter; 427 return B_NO_MEMORY; 428 } 429 430 info->ref = ref; 431 info->add_on = filter; 432 433 if (!fFilterList.AddItem(info)) { 434 delete info; 435 return B_NO_MEMORY; 436 } 437 438 BAutolock locker(InputServer::gInputFilterListLocker); 439 if (!InputServer::gInputFilterList.AddItem(filter)) { 440 fFilterList.RemoveItem(info); 441 delete info; 442 return B_NO_MEMORY; 443 } 444 445 info->image = addOnImage; 446 447 return B_OK; 448 } 449 450 451 //! Takes over ownership of the \a method, regardless of success. 452 status_t 453 AddOnManager::_RegisterMethod(BInputServerMethod* method, const entry_ref& ref, 454 image_id addOnImage) 455 { 456 BAutolock _(this); 457 458 for (int32 i = fMethodList.CountItems(); i-- > 0;) { 459 method_info* info = fMethodList.ItemAt(i); 460 if (!strcmp(info->ref.name, ref.name)) { 461 // we already know this ref 462 delete method; 463 return B_NAME_IN_USE; 464 } 465 } 466 467 TRACE("%s, name %s\n", __PRETTY_FUNCTION__, ref.name); 468 469 method_info* info = new(std::nothrow) method_info; 470 if (info == NULL) { 471 delete method; 472 return B_NO_MEMORY; 473 } 474 475 info->ref = ref; 476 info->add_on = method; 477 478 if (!fMethodList.AddItem(info)) { 479 delete info; 480 return B_NO_MEMORY; 481 } 482 483 BAutolock locker(InputServer::gInputMethodListLocker); 484 if (!InputServer::gInputMethodList.AddItem(method)) { 485 fMethodList.RemoveItem(info); 486 delete info; 487 return B_NO_MEMORY; 488 } 489 490 info->image = addOnImage; 491 492 if (gInputServer->MethodReplicant() == NULL) { 493 _LoadReplicant(); 494 495 if (gInputServer->MethodReplicant()) { 496 _BMethodAddOn_ *addon = InputServer::gKeymapMethod.fOwner; 497 addon->AddMethod(); 498 } 499 } 500 501 if (gInputServer->MethodReplicant() != NULL) { 502 _BMethodAddOn_ *addon = method->fOwner; 503 addon->AddMethod(); 504 } 505 506 return B_OK; 507 } 508 509 510 // #pragma mark - 511 512 513 void 514 AddOnManager::_UnloadReplicant() 515 { 516 BDeskbar().RemoveItem(REPLICANT_CTL_NAME); 517 } 518 519 520 void 521 AddOnManager::_LoadReplicant() 522 { 523 CALLED(); 524 app_info info; 525 be_app->GetAppInfo(&info); 526 527 status_t err = BDeskbar().AddItem(&info.ref); 528 if (err != B_OK) { 529 ERROR("Deskbar refuses to add method replicant: %s\n", strerror(err)); 530 } 531 BMessage request(B_GET_PROPERTY); 532 BMessenger to; 533 BMessenger status; 534 535 request.AddSpecifier("Messenger"); 536 request.AddSpecifier("Shelf"); 537 538 // In the Deskbar the Shelf is in the View "Status" in Window "Deskbar" 539 request.AddSpecifier("View", "Status"); 540 request.AddSpecifier("Window", "Deskbar"); 541 to = BMessenger("application/x-vnd.Be-TSKB", -1); 542 543 BMessage reply; 544 545 if (to.SendMessage(&request, &reply) == B_OK 546 && reply.FindMessenger("result", &status) == B_OK) { 547 // enum replicant in Status view 548 int32 index = 0; 549 int32 uid; 550 while ((uid = _GetReplicantAt(status, index++)) >= B_OK) { 551 BMessage replicantInfo; 552 if (_GetReplicantName(status, uid, &replicantInfo) != B_OK) 553 continue; 554 555 const char *name; 556 if (replicantInfo.FindString("result", &name) == B_OK 557 && !strcmp(name, REPLICANT_CTL_NAME)) { 558 BMessage replicant; 559 if (_GetReplicantView(status, uid, &replicant) == B_OK) { 560 BMessenger result; 561 if (replicant.FindMessenger("result", &result) == B_OK) { 562 gInputServer->SetMethodReplicant(new BMessenger(result)); 563 } 564 } 565 } 566 } 567 } 568 569 if (!gInputServer->MethodReplicant()) { 570 ERROR("LoadReplicant(): Method replicant not found!\n"); 571 } 572 } 573 574 575 int32 576 AddOnManager::_GetReplicantAt(BMessenger target, int32 index) const 577 { 578 // So here we want to get the Unique ID of the replicant at the given index 579 // in the target Shelf. 580 581 BMessage request(B_GET_PROPERTY);// We're getting the ID property 582 BMessage reply; 583 status_t err; 584 585 request.AddSpecifier("ID");// want the ID 586 request.AddSpecifier("Replicant", index);// of the index'th replicant 587 588 if ((err = target.SendMessage(&request, &reply)) != B_OK) 589 return err; 590 591 int32 uid; 592 if ((err = reply.FindInt32("result", &uid)) != B_OK) 593 return err; 594 595 return uid; 596 } 597 598 599 status_t 600 AddOnManager::_GetReplicantName(BMessenger target, int32 uid, 601 BMessage* reply) const 602 { 603 // We send a message to the target shelf, asking it for the Name of the 604 // replicant with the given unique id. 605 606 BMessage request(B_GET_PROPERTY); 607 BMessage uid_specifier(B_ID_SPECIFIER);// specifying via ID 608 status_t err; 609 status_t e; 610 611 request.AddSpecifier("Name");// ask for the Name of the replicant 612 613 // IDs are specified using code like the following 3 lines: 614 uid_specifier.AddInt32("id", uid); 615 uid_specifier.AddString("property", "Replicant"); 616 request.AddSpecifier(&uid_specifier); 617 618 if ((err = target.SendMessage(&request, reply)) != B_OK) 619 return err; 620 621 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 622 return err ? err : e; 623 624 return B_OK; 625 } 626 627 628 status_t 629 AddOnManager::_GetReplicantView(BMessenger target, int32 uid, 630 BMessage* reply) const 631 { 632 // We send a message to the target shelf, asking it for the Name of the 633 // replicant with the given unique id. 634 635 BMessage request(B_GET_PROPERTY); 636 BMessage uid_specifier(B_ID_SPECIFIER); 637 // specifying via ID 638 status_t err; 639 status_t e; 640 641 request.AddSpecifier("View"); 642 // ask for the Name of the replicant 643 644 // IDs are specified using code like the following 3 lines: 645 uid_specifier.AddInt32("id", uid); 646 uid_specifier.AddString("property", "Replicant"); 647 request.AddSpecifier(&uid_specifier); 648 649 if ((err = target.SendMessage(&request, reply)) != B_OK) 650 return err; 651 652 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 653 return err ? err : e; 654 655 return B_OK; 656 } 657 658 659 void 660 AddOnManager::MessageReceived(BMessage* message) 661 { 662 CALLED(); 663 664 BMessage reply; 665 status_t status; 666 667 ERROR("%s what: %.4s\n", __PRETTY_FUNCTION__, (char*)&message->what); 668 669 switch (message->what) { 670 case IS_FIND_DEVICES: 671 status = _HandleFindDevices(message, &reply); 672 break; 673 case IS_WATCH_DEVICES: 674 status = _HandleWatchDevices(message, &reply); 675 break; 676 case IS_IS_DEVICE_RUNNING: 677 status = _HandleIsDeviceRunning(message, &reply); 678 break; 679 case IS_START_DEVICE: 680 status = _HandleStartStopDevices(message, &reply); 681 break; 682 case IS_STOP_DEVICE: 683 status = _HandleStartStopDevices(message, &reply); 684 break; 685 case IS_CONTROL_DEVICES: 686 status = _HandleControlDevices(message, &reply); 687 break; 688 case SYSTEM_SHUTTING_DOWN: 689 status = _HandleSystemShuttingDown(message, &reply); 690 break; 691 case IS_METHOD_REGISTER: 692 status = _HandleMethodReplicant(message, &reply); 693 break; 694 695 case B_PATH_MONITOR: 696 _HandleDeviceMonitor(message); 697 return; 698 699 default: 700 return; 701 } 702 703 reply.AddInt32("status", status); 704 message->SendReply(&reply); 705 } 706 707 708 status_t 709 AddOnManager::_HandleStartStopDevices(BMessage* message, BMessage* reply) 710 { 711 const char *name = NULL; 712 int32 type = 0; 713 if (!((message->FindInt32("type", &type) != B_OK) 714 ^ (message->FindString("device", &name) != B_OK))) 715 return B_ERROR; 716 717 return gInputServer->StartStopDevices(name, (input_device_type)type, 718 message->what == IS_START_DEVICE); 719 } 720 721 722 status_t 723 AddOnManager::_HandleFindDevices(BMessage* message, BMessage* reply) 724 { 725 CALLED(); 726 const char *name = NULL; 727 input_device_type type; 728 if (message->FindString("device", &name) == B_OK) { 729 if (gInputServer->GetDeviceInfo(name, &type) != B_OK) 730 return B_NAME_NOT_FOUND; 731 reply->AddString("device", name); 732 reply->AddInt32("type", type); 733 } else { 734 gInputServer->GetDeviceInfos(reply); 735 } 736 return B_OK; 737 } 738 739 740 status_t 741 AddOnManager::_HandleWatchDevices(BMessage* message, BMessage* reply) 742 { 743 // TODO 744 return B_OK; 745 } 746 747 748 status_t 749 AddOnManager::_HandleIsDeviceRunning(BMessage* message, BMessage* reply) 750 { 751 const char* name; 752 bool running; 753 if (message->FindString("device", &name) != B_OK 754 || gInputServer->GetDeviceInfo(name, NULL, &running) != B_OK) 755 return B_NAME_NOT_FOUND; 756 757 return running ? B_OK : B_ERROR; 758 } 759 760 761 status_t 762 AddOnManager::_HandleControlDevices(BMessage* message, BMessage* reply) 763 { 764 CALLED(); 765 const char *name = NULL; 766 int32 type = 0; 767 if (!((message->FindInt32("type", &type) != B_OK) 768 ^ (message->FindString("device", &name) != B_OK))) 769 return B_BAD_VALUE; 770 771 uint32 code = 0; 772 BMessage controlMessage; 773 bool hasMessage = true; 774 if (message->FindInt32("code", (int32*)&code) != B_OK) 775 return B_BAD_VALUE; 776 if (message->FindMessage("message", &controlMessage) != B_OK) 777 hasMessage = false; 778 779 return gInputServer->ControlDevices(name, (input_device_type)type, 780 code, hasMessage ? &controlMessage : NULL); 781 } 782 783 784 status_t 785 AddOnManager::_HandleSystemShuttingDown(BMessage* message, BMessage* reply) 786 { 787 CALLED(); 788 789 for (int32 i = 0; i < fDeviceList.CountItems(); i++) { 790 device_info* info = fDeviceList.ItemAt(i); 791 info->add_on->SystemShuttingDown(); 792 } 793 794 return B_OK; 795 } 796 797 798 status_t 799 AddOnManager::_HandleMethodReplicant(BMessage* message, BMessage* reply) 800 { 801 CALLED(); 802 803 if (InputServer::gInputMethodList.CountItems() == 0) { 804 _UnloadReplicant(); 805 return B_OK; 806 } 807 808 _LoadReplicant(); 809 810 BAutolock lock(InputServer::gInputMethodListLocker); 811 812 if (gInputServer->MethodReplicant()) { 813 _BMethodAddOn_* addon = InputServer::gKeymapMethod.fOwner; 814 addon->AddMethod(); 815 816 for (int32 i = 0; i < InputServer::gInputMethodList.CountItems(); i++) { 817 BInputServerMethod* method 818 = (BInputServerMethod*)InputServer::gInputMethodList.ItemAt(i); 819 820 _BMethodAddOn_* addon = method->fOwner; 821 addon->AddMethod(); 822 } 823 } 824 825 return B_OK; 826 } 827 828 829 void 830 AddOnManager::_HandleDeviceMonitor(BMessage* message) 831 { 832 int32 opcode; 833 if (message->FindInt32("opcode", &opcode) != B_OK) 834 return; 835 836 switch (opcode) { 837 case B_ENTRY_CREATED: 838 case B_ENTRY_REMOVED: 839 { 840 const char* path; 841 const char* watchedPath; 842 if (message->FindString("watched_path", &watchedPath) != B_OK 843 || message->FindString("path", &path) != B_OK) { 844 #if DEBUG 845 char string[1024]; 846 sprintf(string, "message does not contain all fields - " 847 "watched_path: %d, path: %d\n", 848 message->HasString("watched_path"), 849 message->HasString("path")); 850 debugger(string); 851 #endif 852 return; 853 } 854 855 // Notify all watching devices 856 857 for (int32 i = 0; i < fDeviceAddOns.CountItems(); i++) { 858 DeviceAddOn* addOn = fDeviceAddOns.ItemAt(i); 859 if (!addOn->HasPath(watchedPath)) 860 continue; 861 862 addOn->Device()->Control(NULL, NULL, B_NODE_MONITOR, message); 863 } 864 break; 865 } 866 } 867 } 868 869 870 status_t 871 AddOnManager::_AddDevicePath(DeviceAddOn* addOn, const char* path, 872 bool& newPath) 873 { 874 newPath = !fDevicePaths.HasPath(path); 875 876 status_t status = fDevicePaths.AddPath(path); 877 if (status == B_OK) { 878 status = addOn->AddPath(path); 879 if (status == B_OK) { 880 if (!fDeviceAddOns.HasItem(addOn) 881 && !fDeviceAddOns.AddItem(addOn)) { 882 addOn->RemovePath(path); 883 status = B_NO_MEMORY; 884 } 885 } else 886 fDevicePaths.RemovePath(path); 887 } 888 889 return status; 890 } 891 892 893 status_t 894 AddOnManager::_RemoveDevicePath(DeviceAddOn* addOn, const char* path, 895 bool& lastPath) 896 { 897 if (!fDevicePaths.HasPath(path) || !addOn->HasPath(path)) 898 return B_ENTRY_NOT_FOUND; 899 900 fDevicePaths.RemovePath(path); 901 902 lastPath = !fDevicePaths.HasPath(path); 903 904 addOn->RemovePath(path); 905 if (addOn->CountPaths() == 0) 906 fDeviceAddOns.RemoveItem(addOn); 907 908 return B_OK; 909 } 910 911 912 status_t 913 AddOnManager::StartMonitoringDevice(DeviceAddOn* addOn, const char* device) 914 { 915 CALLED(); 916 917 BString path; 918 if (device[0] != '/') 919 path = "/dev/"; 920 path += device; 921 922 TRACE("AddOnMonitor::StartMonitoringDevice(%s)\n", path.String()); 923 924 bool newPath; 925 status_t status = _AddDevicePath(addOn, path.String(), newPath); 926 if (status == B_OK && newPath) { 927 status = BPathMonitor::StartWatching(path.String(), B_ENTRY_CREATED 928 | B_ENTRY_REMOVED | B_ENTRY_MOVED | B_WATCH_FILES_ONLY 929 | B_WATCH_RECURSIVELY, this); 930 if (status != B_OK) { 931 bool lastPath; 932 _RemoveDevicePath(addOn, path.String(), lastPath); 933 } 934 } 935 936 return status; 937 } 938 939 940 status_t 941 AddOnManager::StopMonitoringDevice(DeviceAddOn* addOn, const char *device) 942 { 943 CALLED(); 944 945 BString path; 946 if (device[0] != '/') 947 path = "/dev/"; 948 path += device; 949 950 TRACE("AddOnMonitor::StopMonitoringDevice(%s)\n", path.String()); 951 952 bool lastPath; 953 status_t status = _RemoveDevicePath(addOn, path.String(), lastPath); 954 if (status == B_OK && lastPath) 955 BPathMonitor::StopWatching(path.String(), this); 956 957 return status; 958 } 959