1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* activation.c Activation of services 3 * 4 * Copyright (C) 2003 CodeFactory AB 5 * Copyright (C) 2003 Red Hat, Inc. 6 * Copyright (C) 2004 Imendio HB 7 * 8 * Licensed under the Academic Free License version 2.1 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * 24 */ 25 #include "activation.h" 26 #include "desktop-file.h" 27 #include "services.h" 28 #include "test.h" 29 #include "utils.h" 30 #include <dbus/dbus-internals.h> 31 #include <dbus/dbus-hash.h> 32 #include <dbus/dbus-list.h> 33 #include <dbus/dbus-shell.h> 34 #include <dbus/dbus-spawn.h> 35 #include <dbus/dbus-timeout.h> 36 #include <dbus/dbus-sysdeps.h> 37 #include <dirent.h> 38 #include <errno.h> 39 40 #define DBUS_SERVICE_SECTION "D-BUS Service" 41 #define DBUS_SERVICE_NAME "Name" 42 #define DBUS_SERVICE_EXEC "Exec" 43 44 struct BusActivation 45 { 46 int refcount; 47 DBusHashTable *entries; 48 DBusHashTable *pending_activations; 49 char *server_address; 50 BusContext *context; 51 int n_pending_activations; /**< This is in fact the number of BusPendingActivationEntry, 52 * i.e. number of pending activation requests, not pending 53 * activations per se 54 */ 55 DBusHashTable *directories; 56 }; 57 58 typedef struct 59 { 60 int refcount; 61 char *dir_c; 62 DBusHashTable *entries; 63 } BusServiceDirectory; 64 65 typedef struct 66 { 67 int refcount; 68 char *name; 69 char *exec; 70 unsigned long mtime; 71 BusServiceDirectory *s_dir; 72 char *filename; 73 } BusActivationEntry; 74 75 typedef struct BusPendingActivationEntry BusPendingActivationEntry; 76 77 struct BusPendingActivationEntry 78 { 79 DBusMessage *activation_message; 80 DBusConnection *connection; 81 82 dbus_bool_t auto_activation; 83 }; 84 85 typedef struct 86 { 87 int refcount; 88 BusActivation *activation; 89 char *service_name; 90 char *exec; 91 DBusList *entries; 92 int n_entries; 93 DBusBabysitter *babysitter; 94 DBusTimeout *timeout; 95 unsigned int timeout_added : 1; 96 } BusPendingActivation; 97 98 #if 0 99 static BusServiceDirectory * 100 bus_service_directory_ref (BusServiceDirectory *dir) 101 { 102 _dbus_assert (dir->refcount); 103 104 dir->refcount++; 105 106 return dir; 107 } 108 #endif 109 110 static void 111 bus_service_directory_unref (BusServiceDirectory *dir) 112 { 113 if (dir == NULL) 114 return; 115 116 _dbus_assert (dir->refcount > 0); 117 dir->refcount--; 118 119 if (dir->refcount > 0) 120 return; 121 122 if (dir->entries) 123 _dbus_hash_table_unref (dir->entries); 124 125 dbus_free (dir->dir_c); 126 dbus_free (dir); 127 } 128 129 static void 130 bus_pending_activation_entry_free (BusPendingActivationEntry *entry) 131 { 132 if (entry->activation_message) 133 dbus_message_unref (entry->activation_message); 134 135 if (entry->connection) 136 dbus_connection_unref (entry->connection); 137 138 dbus_free (entry); 139 } 140 141 static void 142 handle_timeout_callback (DBusTimeout *timeout, 143 void *data) 144 { 145 BusPendingActivation *pending_activation = data; 146 147 while (!dbus_timeout_handle (pending_activation->timeout)) 148 _dbus_wait_for_memory (); 149 } 150 151 static BusPendingActivation * 152 bus_pending_activation_ref (BusPendingActivation *pending_activation) 153 { 154 _dbus_assert (pending_activation->refcount > 0); 155 pending_activation->refcount += 1; 156 157 return pending_activation; 158 } 159 160 static void 161 bus_pending_activation_unref (BusPendingActivation *pending_activation) 162 { 163 DBusList *link; 164 165 if (pending_activation == NULL) /* hash table requires this */ 166 return; 167 168 _dbus_assert (pending_activation->refcount > 0); 169 pending_activation->refcount -= 1; 170 171 if (pending_activation->refcount > 0) 172 return; 173 174 if (pending_activation->timeout_added) 175 { 176 _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context), 177 pending_activation->timeout, 178 handle_timeout_callback, pending_activation); 179 pending_activation->timeout_added = FALSE; 180 } 181 182 if (pending_activation->timeout) 183 _dbus_timeout_unref (pending_activation->timeout); 184 185 if (pending_activation->babysitter) 186 { 187 if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter, 188 NULL, NULL, NULL, 189 pending_activation->babysitter, 190 NULL)) 191 _dbus_assert_not_reached ("setting watch functions to NULL failed"); 192 193 _dbus_babysitter_unref (pending_activation->babysitter); 194 } 195 196 dbus_free (pending_activation->service_name); 197 dbus_free (pending_activation->exec); 198 199 link = _dbus_list_get_first_link (&pending_activation->entries); 200 201 while (link != NULL) 202 { 203 BusPendingActivationEntry *entry = link->data; 204 205 bus_pending_activation_entry_free (entry); 206 207 link = _dbus_list_get_next_link (&pending_activation->entries, link); 208 } 209 _dbus_list_clear (&pending_activation->entries); 210 211 pending_activation->activation->n_pending_activations -= 212 pending_activation->n_entries; 213 214 _dbus_assert (pending_activation->activation->n_pending_activations >= 0); 215 216 dbus_free (pending_activation); 217 } 218 219 static BusActivationEntry * 220 bus_activation_entry_ref (BusActivationEntry *entry) 221 { 222 _dbus_assert (entry->refcount > 0); 223 entry->refcount++; 224 225 return entry; 226 } 227 228 static void 229 bus_activation_entry_unref (BusActivationEntry *entry) 230 { 231 if (entry == NULL) /* hash table requires this */ 232 return; 233 234 _dbus_assert (entry->refcount > 0); 235 entry->refcount--; 236 237 if (entry->refcount > 0) 238 return; 239 240 dbus_free (entry->name); 241 dbus_free (entry->exec); 242 dbus_free (entry->filename); 243 244 dbus_free (entry); 245 } 246 247 static dbus_bool_t 248 update_desktop_file_entry (BusActivation *activation, 249 BusServiceDirectory *s_dir, 250 DBusString *filename, 251 BusDesktopFile *desktop_file, 252 DBusError *error) 253 { 254 char *name, *exec; 255 BusActivationEntry *entry; 256 DBusStat stat_buf; 257 DBusString file_path; 258 259 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 260 261 name = NULL; 262 exec = NULL; 263 entry = NULL; 264 265 if (!_dbus_string_init (&file_path)) 266 { 267 BUS_SET_OOM (error); 268 return FALSE; 269 } 270 271 if (!_dbus_string_append (&file_path, s_dir->dir_c) || 272 !_dbus_concat_dir_and_file (&file_path, filename)) 273 { 274 BUS_SET_OOM (error); 275 goto failed; 276 } 277 278 if (!_dbus_stat (&file_path, &stat_buf, NULL)) 279 { 280 dbus_set_error (error, DBUS_ERROR_FAILED, 281 "Can't stat the service file\n"); 282 goto failed; 283 } 284 285 if (!bus_desktop_file_get_string (desktop_file, 286 DBUS_SERVICE_SECTION, 287 DBUS_SERVICE_NAME, 288 &name, 289 error)) 290 goto failed; 291 292 if (!bus_desktop_file_get_string (desktop_file, 293 DBUS_SERVICE_SECTION, 294 DBUS_SERVICE_EXEC, 295 &exec, 296 error)) 297 goto failed; 298 299 entry = _dbus_hash_table_lookup_string (s_dir->entries, 300 _dbus_string_get_const_data (filename)); 301 if (entry == NULL) /* New file */ 302 { 303 /* FIXME we need a better-defined algorithm for which service file to 304 * pick than "whichever one is first in the directory listing" 305 */ 306 if (_dbus_hash_table_lookup_string (activation->entries, name)) 307 { 308 dbus_set_error (error, DBUS_ERROR_FAILED, 309 "Service %s already exists in activation entry list\n", name); 310 goto failed; 311 } 312 313 entry = dbus_new0 (BusActivationEntry, 1); 314 if (entry == NULL) 315 { 316 BUS_SET_OOM (error); 317 goto failed; 318 } 319 320 entry->name = name; 321 entry->exec = exec; 322 entry->refcount = 1; 323 324 entry->s_dir = s_dir; 325 entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename)); 326 if (!entry->filename) 327 { 328 BUS_SET_OOM (error); 329 goto failed; 330 } 331 332 if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry))) 333 { 334 BUS_SET_OOM (error); 335 goto failed; 336 } 337 338 if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry))) 339 { 340 /* Revert the insertion in the entries table */ 341 _dbus_hash_table_remove_string (activation->entries, entry->name); 342 BUS_SET_OOM (error); 343 goto failed; 344 } 345 346 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name); 347 } 348 else /* Just update the entry */ 349 { 350 bus_activation_entry_ref (entry); 351 _dbus_hash_table_remove_string (activation->entries, entry->name); 352 353 if (_dbus_hash_table_lookup_string (activation->entries, name)) 354 { 355 _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n", 356 name, _dbus_string_get_const_data (&file_path)); 357 goto failed; 358 } 359 360 dbus_free (entry->name); 361 dbus_free (entry->exec); 362 entry->name = name; 363 entry->exec = exec; 364 if (!_dbus_hash_table_insert_string (activation->entries, 365 entry->name, bus_activation_entry_ref(entry))) 366 { 367 BUS_SET_OOM (error); 368 /* Also remove path to entries hash since we want this in sync with 369 * the entries hash table */ 370 _dbus_hash_table_remove_string (entry->s_dir->entries, 371 entry->filename); 372 bus_activation_entry_unref (entry); 373 return FALSE; 374 } 375 } 376 377 entry->mtime = stat_buf.mtime; 378 379 _dbus_string_free (&file_path); 380 bus_activation_entry_unref (entry); 381 382 return TRUE; 383 384 failed: 385 dbus_free (name); 386 dbus_free (exec); 387 _dbus_string_free (&file_path); 388 389 if (entry) 390 bus_activation_entry_unref (entry); 391 392 return FALSE; 393 } 394 395 static dbus_bool_t 396 check_service_file (BusActivation *activation, 397 BusActivationEntry *entry, 398 BusActivationEntry **updated_entry, 399 DBusError *error) 400 { 401 DBusStat stat_buf; 402 dbus_bool_t retval; 403 BusActivationEntry *tmp_entry; 404 DBusString file_path; 405 DBusString filename; 406 407 retval = TRUE; 408 tmp_entry = entry; 409 410 _dbus_string_init_const (&filename, entry->filename); 411 412 if (!_dbus_string_init (&file_path)) 413 { 414 BUS_SET_OOM (error); 415 return FALSE; 416 } 417 418 if (!_dbus_string_append (&file_path, entry->s_dir->dir_c) || 419 !_dbus_concat_dir_and_file (&file_path, &filename)) 420 { 421 BUS_SET_OOM (error); 422 retval = FALSE; 423 goto out; 424 } 425 426 if (!_dbus_stat (&file_path, &stat_buf, NULL)) 427 { 428 _dbus_verbose ("****** Can't stat file \"%s\", removing from cache\n", 429 _dbus_string_get_const_data (&file_path)); 430 431 _dbus_hash_table_remove_string (activation->entries, entry->name); 432 _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename); 433 434 tmp_entry = NULL; 435 retval = TRUE; 436 goto out; 437 } 438 else 439 { 440 if (stat_buf.mtime > entry->mtime) 441 { 442 BusDesktopFile *desktop_file; 443 DBusError tmp_error; 444 445 dbus_error_init (&tmp_error); 446 447 desktop_file = bus_desktop_file_load (&file_path, &tmp_error); 448 if (desktop_file == NULL) 449 { 450 _dbus_verbose ("Could not load %s: %s\n", 451 _dbus_string_get_const_data (&file_path), 452 tmp_error.message); 453 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) 454 { 455 dbus_move_error (&tmp_error, error); 456 retval = FALSE; 457 goto out; 458 } 459 dbus_error_free (&tmp_error); 460 retval = TRUE; 461 goto out; 462 } 463 464 /* @todo We can return OOM or a DBUS_ERROR_FAILED error 465 * Handle these both better 466 */ 467 if (!update_desktop_file_entry (activation, entry->s_dir, &filename, desktop_file, &tmp_error)) 468 { 469 bus_desktop_file_free (desktop_file); 470 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) 471 { 472 dbus_move_error (&tmp_error, error); 473 retval = FALSE; 474 goto out; 475 } 476 dbus_error_free (&tmp_error); 477 retval = TRUE; 478 goto out; 479 } 480 481 bus_desktop_file_free (desktop_file); 482 retval = TRUE; 483 } 484 } 485 486 out: 487 _dbus_string_free (&file_path); 488 489 if (updated_entry != NULL) 490 *updated_entry = tmp_entry; 491 return retval; 492 } 493 494 495 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip 496 * hash entries it already added. 497 */ 498 static dbus_bool_t 499 update_directory (BusActivation *activation, 500 BusServiceDirectory *s_dir, 501 DBusError *error) 502 { 503 DBusDirIter *iter; 504 DBusString dir, filename; 505 BusDesktopFile *desktop_file; 506 DBusError tmp_error; 507 dbus_bool_t retval; 508 BusActivationEntry *entry; 509 DBusString full_path; 510 511 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 512 513 iter = NULL; 514 desktop_file = NULL; 515 516 _dbus_string_init_const (&dir, s_dir->dir_c); 517 518 if (!_dbus_string_init (&filename)) 519 { 520 BUS_SET_OOM (error); 521 return FALSE; 522 } 523 524 if (!_dbus_string_init (&full_path)) 525 { 526 BUS_SET_OOM (error); 527 _dbus_string_free (&filename); 528 return FALSE; 529 } 530 531 retval = FALSE; 532 533 /* from this point it's safe to "goto out" */ 534 535 iter = _dbus_directory_open (&dir, error); 536 if (iter == NULL) 537 { 538 _dbus_verbose ("Failed to open directory %s: %s\n", 539 s_dir->dir_c, 540 error ? error->message : "unknown"); 541 goto out; 542 } 543 544 /* Now read the files */ 545 dbus_error_init (&tmp_error); 546 while (_dbus_directory_get_next_file (iter, &filename, &tmp_error)) 547 { 548 _dbus_assert (!dbus_error_is_set (&tmp_error)); 549 550 _dbus_string_set_length (&full_path, 0); 551 552 if (!_dbus_string_ends_with_c_str (&filename, ".service")) 553 { 554 _dbus_verbose ("Skipping non-.service file %s\n", 555 _dbus_string_get_const_data (&filename)); 556 continue; 557 } 558 559 entry = _dbus_hash_table_lookup_string (s_dir->entries, _dbus_string_get_const_data (&filename)); 560 if (entry) /* Already has this service file in the cache */ 561 { 562 if (!check_service_file (activation, entry, NULL, error)) 563 goto out; 564 565 continue; 566 } 567 568 if (!_dbus_string_append (&full_path, s_dir->dir_c) || 569 !_dbus_concat_dir_and_file (&full_path, &filename)) 570 { 571 BUS_SET_OOM (error); 572 goto out; 573 } 574 575 /* New file */ 576 desktop_file = bus_desktop_file_load (&full_path, &tmp_error); 577 if (desktop_file == NULL) 578 { 579 _dbus_verbose ("Could not load %s: %s\n", 580 _dbus_string_get_const_data (&full_path), 581 tmp_error.message); 582 583 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) 584 { 585 dbus_move_error (&tmp_error, error); 586 goto out; 587 } 588 589 dbus_error_free (&tmp_error); 590 continue; 591 } 592 593 /* @todo We can return OOM or a DBUS_ERROR_FAILED error 594 * Handle these both better 595 */ 596 if (!update_desktop_file_entry (activation, s_dir, &filename, desktop_file, &tmp_error)) 597 { 598 bus_desktop_file_free (desktop_file); 599 desktop_file = NULL; 600 601 _dbus_verbose ("Could not add %s to activation entry list: %s\n", 602 _dbus_string_get_const_data (&full_path), tmp_error.message); 603 604 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) 605 { 606 dbus_move_error (&tmp_error, error); 607 goto out; 608 } 609 610 dbus_error_free (&tmp_error); 611 continue; 612 } 613 else 614 { 615 bus_desktop_file_free (desktop_file); 616 desktop_file = NULL; 617 continue; 618 } 619 } 620 621 if (dbus_error_is_set (&tmp_error)) 622 { 623 dbus_move_error (&tmp_error, error); 624 goto out; 625 } 626 627 retval = TRUE; 628 629 out: 630 if (!retval) 631 _DBUS_ASSERT_ERROR_IS_SET (error); 632 else 633 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 634 635 if (iter != NULL) 636 _dbus_directory_close (iter); 637 _dbus_string_free (&filename); 638 _dbus_string_free (&full_path); 639 640 return retval; 641 } 642 643 BusActivation* 644 bus_activation_new (BusContext *context, 645 const DBusString *address, 646 DBusList **directories, 647 DBusError *error) 648 { 649 BusActivation *activation; 650 DBusList *link; 651 char *dir; 652 653 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 654 655 activation = dbus_new0 (BusActivation, 1); 656 if (activation == NULL) 657 { 658 BUS_SET_OOM (error); 659 return NULL; 660 } 661 662 activation->refcount = 1; 663 activation->context = context; 664 activation->n_pending_activations = 0; 665 666 if (!_dbus_string_copy_data (address, &activation->server_address)) 667 { 668 BUS_SET_OOM (error); 669 goto failed; 670 } 671 672 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, 673 (DBusFreeFunction)bus_activation_entry_unref); 674 if (activation->entries == NULL) 675 { 676 BUS_SET_OOM (error); 677 goto failed; 678 } 679 680 activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, 681 (DBusFreeFunction)bus_pending_activation_unref); 682 683 if (activation->pending_activations == NULL) 684 { 685 BUS_SET_OOM (error); 686 goto failed; 687 } 688 689 activation->directories = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, 690 (DBusFreeFunction)bus_service_directory_unref); 691 692 if (activation->directories == NULL) 693 { 694 BUS_SET_OOM (error); 695 goto failed; 696 } 697 698 /* Load service files */ 699 link = _dbus_list_get_first_link (directories); 700 while (link != NULL) 701 { 702 BusServiceDirectory *s_dir; 703 704 dir = _dbus_strdup ((const char *) link->data); 705 if (!dir) 706 { 707 BUS_SET_OOM (error); 708 goto failed; 709 } 710 711 s_dir = dbus_new0 (BusServiceDirectory, 1); 712 if (!s_dir) 713 { 714 dbus_free (dir); 715 BUS_SET_OOM (error); 716 goto failed; 717 } 718 719 s_dir->refcount = 1; 720 s_dir->dir_c = dir; 721 722 s_dir->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, 723 (DBusFreeFunction)bus_activation_entry_unref); 724 725 if (!s_dir->entries) 726 { 727 bus_service_directory_unref (s_dir); 728 BUS_SET_OOM (error); 729 goto failed; 730 } 731 732 if (!_dbus_hash_table_insert_string (activation->directories, s_dir->dir_c, s_dir)) 733 { 734 bus_service_directory_unref (s_dir); 735 BUS_SET_OOM (error); 736 goto failed; 737 } 738 739 /* only fail on OOM, it is ok if we can't read the directory */ 740 if (!update_directory (activation, s_dir, error)) 741 { 742 if (dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) 743 goto failed; 744 else 745 dbus_error_free (error); 746 } 747 748 link = _dbus_list_get_next_link (directories, link); 749 } 750 751 return activation; 752 753 failed: 754 bus_activation_unref (activation); 755 return NULL; 756 } 757 758 BusActivation * 759 bus_activation_ref (BusActivation *activation) 760 { 761 _dbus_assert (activation->refcount > 0); 762 763 activation->refcount += 1; 764 765 return activation; 766 } 767 768 void 769 bus_activation_unref (BusActivation *activation) 770 { 771 _dbus_assert (activation->refcount > 0); 772 773 activation->refcount -= 1; 774 775 if (activation->refcount > 0) 776 return; 777 778 dbus_free (activation->server_address); 779 if (activation->entries) 780 _dbus_hash_table_unref (activation->entries); 781 if (activation->pending_activations) 782 _dbus_hash_table_unref (activation->pending_activations); 783 if (activation->directories) 784 _dbus_hash_table_unref (activation->directories); 785 786 dbus_free (activation); 787 } 788 789 static void 790 child_setup (void *data) 791 { 792 BusActivation *activation = data; 793 const char *type; 794 795 /* If no memory, we simply have the child exit, so it won't try 796 * to connect to the wrong thing. 797 */ 798 if (!_dbus_setenv ("DBUS_STARTER_ADDRESS", activation->server_address)) 799 _dbus_exit (1); 800 801 type = bus_context_get_type (activation->context); 802 if (type != NULL) 803 { 804 if (!_dbus_setenv ("DBUS_STARTER_BUS_TYPE", type)) 805 _dbus_exit (1); 806 807 if (strcmp (type, "session") == 0) 808 { 809 if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", 810 activation->server_address)) 811 _dbus_exit (1); 812 } 813 else if (strcmp (type, "system") == 0) 814 { 815 if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS", 816 activation->server_address)) 817 _dbus_exit (1); 818 } 819 } 820 } 821 822 typedef struct 823 { 824 BusPendingActivation *pending_activation; 825 DBusPreallocatedHash *hash_entry; 826 } RestorePendingData; 827 828 static void 829 restore_pending (void *data) 830 { 831 RestorePendingData *d = data; 832 833 _dbus_assert (d->pending_activation != NULL); 834 _dbus_assert (d->hash_entry != NULL); 835 836 _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n", 837 d->pending_activation->service_name, 838 d->pending_activation->timeout_added); 839 840 _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations, 841 d->hash_entry, 842 d->pending_activation->service_name, d->pending_activation); 843 844 bus_pending_activation_ref (d->pending_activation); 845 846 d->hash_entry = NULL; 847 } 848 849 static void 850 free_pending_restore_data (void *data) 851 { 852 RestorePendingData *d = data; 853 854 if (d->hash_entry) 855 _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations, 856 d->hash_entry); 857 858 bus_pending_activation_unref (d->pending_activation); 859 860 dbus_free (d); 861 } 862 863 static dbus_bool_t 864 add_restore_pending_to_transaction (BusTransaction *transaction, 865 BusPendingActivation *pending_activation) 866 { 867 RestorePendingData *d; 868 869 d = dbus_new (RestorePendingData, 1); 870 if (d == NULL) 871 return FALSE; 872 873 d->pending_activation = pending_activation; 874 d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations); 875 876 bus_pending_activation_ref (d->pending_activation); 877 878 if (d->hash_entry == NULL || 879 !bus_transaction_add_cancel_hook (transaction, restore_pending, d, 880 free_pending_restore_data)) 881 { 882 free_pending_restore_data (d); 883 return FALSE; 884 } 885 886 _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n"); 887 888 return TRUE; 889 } 890 891 dbus_bool_t 892 bus_activation_service_created (BusActivation *activation, 893 const char *service_name, 894 BusTransaction *transaction, 895 DBusError *error) 896 { 897 BusPendingActivation *pending_activation; 898 DBusMessage *message; 899 DBusList *link; 900 901 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 902 903 /* Check if it's a pending activation */ 904 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name); 905 906 if (!pending_activation) 907 return TRUE; 908 909 link = _dbus_list_get_first_link (&pending_activation->entries); 910 while (link != NULL) 911 { 912 BusPendingActivationEntry *entry = link->data; 913 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); 914 915 if (dbus_connection_get_is_connected (entry->connection)) 916 { 917 /* Only send activation replies to regular activation requests. */ 918 if (!entry->auto_activation) 919 { 920 dbus_uint32_t result; 921 922 message = dbus_message_new_method_return (entry->activation_message); 923 if (!message) 924 { 925 BUS_SET_OOM (error); 926 goto error; 927 } 928 929 result = DBUS_START_REPLY_SUCCESS; 930 931 if (!dbus_message_append_args (message, 932 DBUS_TYPE_UINT32, &result, 933 DBUS_TYPE_INVALID)) 934 { 935 dbus_message_unref (message); 936 BUS_SET_OOM (error); 937 goto error; 938 } 939 940 if (!bus_transaction_send_from_driver (transaction, entry->connection, message)) 941 { 942 dbus_message_unref (message); 943 BUS_SET_OOM (error); 944 goto error; 945 } 946 947 dbus_message_unref (message); 948 } 949 } 950 951 link = next; 952 } 953 954 return TRUE; 955 956 error: 957 return FALSE; 958 } 959 960 dbus_bool_t 961 bus_activation_send_pending_auto_activation_messages (BusActivation *activation, 962 BusService *service, 963 BusTransaction *transaction, 964 DBusError *error) 965 { 966 BusPendingActivation *pending_activation; 967 DBusList *link; 968 969 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 970 971 /* Check if it's a pending activation */ 972 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, 973 bus_service_get_name (service)); 974 975 if (!pending_activation) 976 return TRUE; 977 978 link = _dbus_list_get_first_link (&pending_activation->entries); 979 while (link != NULL) 980 { 981 BusPendingActivationEntry *entry = link->data; 982 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); 983 984 if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection)) 985 { 986 DBusConnection *addressed_recipient; 987 988 addressed_recipient = bus_service_get_primary_owners_connection (service); 989 990 /* Check the security policy, which has the side-effect of adding an 991 * expected pending reply. 992 */ 993 if (!bus_context_check_security_policy (activation->context, transaction, 994 entry->connection, 995 addressed_recipient, 996 addressed_recipient, 997 entry->activation_message, error)) 998 goto error; 999 1000 if (!bus_transaction_send (transaction, addressed_recipient, entry->activation_message)) 1001 { 1002 BUS_SET_OOM (error); 1003 goto error; 1004 } 1005 } 1006 1007 link = next; 1008 } 1009 1010 if (!add_restore_pending_to_transaction (transaction, pending_activation)) 1011 { 1012 _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n"); 1013 BUS_SET_OOM (error); 1014 goto error; 1015 } 1016 1017 _dbus_hash_table_remove_string (activation->pending_activations, bus_service_get_name (service)); 1018 1019 return TRUE; 1020 1021 error: 1022 return FALSE; 1023 } 1024 1025 /** 1026 * FIXME @todo the error messages here would ideally be preallocated 1027 * so we don't need to allocate memory to send them. 1028 * Using the usual tactic, prealloc an OOM message, then 1029 * if we can't alloc the real error send the OOM error instead. 1030 */ 1031 static dbus_bool_t 1032 try_send_activation_failure (BusPendingActivation *pending_activation, 1033 const DBusError *how) 1034 { 1035 BusActivation *activation; 1036 DBusList *link; 1037 BusTransaction *transaction; 1038 1039 activation = pending_activation->activation; 1040 1041 transaction = bus_transaction_new (activation->context); 1042 if (transaction == NULL) 1043 return FALSE; 1044 1045 link = _dbus_list_get_first_link (&pending_activation->entries); 1046 while (link != NULL) 1047 { 1048 BusPendingActivationEntry *entry = link->data; 1049 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); 1050 1051 if (dbus_connection_get_is_connected (entry->connection)) 1052 { 1053 if (!bus_transaction_send_error_reply (transaction, 1054 entry->connection, 1055 how, 1056 entry->activation_message)) 1057 goto error; 1058 } 1059 1060 link = next; 1061 } 1062 1063 bus_transaction_execute_and_free (transaction); 1064 1065 return TRUE; 1066 1067 error: 1068 if (transaction) 1069 bus_transaction_cancel_and_free (transaction); 1070 return FALSE; 1071 } 1072 1073 /** 1074 * Free the pending activation and send an error message to all the 1075 * connections that were waiting for it. 1076 */ 1077 static void 1078 pending_activation_failed (BusPendingActivation *pending_activation, 1079 const DBusError *how) 1080 { 1081 /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */ 1082 while (!try_send_activation_failure (pending_activation, how)) 1083 _dbus_wait_for_memory (); 1084 1085 /* Destroy this pending activation */ 1086 _dbus_hash_table_remove_string (pending_activation->activation->pending_activations, 1087 pending_activation->service_name); 1088 } 1089 1090 static dbus_bool_t 1091 babysitter_watch_callback (DBusWatch *watch, 1092 unsigned int condition, 1093 void *data) 1094 { 1095 BusPendingActivation *pending_activation = data; 1096 dbus_bool_t retval; 1097 DBusBabysitter *babysitter; 1098 1099 babysitter = pending_activation->babysitter; 1100 1101 _dbus_babysitter_ref (babysitter); 1102 1103 retval = dbus_watch_handle (watch, condition); 1104 1105 /* FIXME this is broken in the same way that 1106 * connection watches used to be; there should be 1107 * a separate callback for status change, instead 1108 * of doing "if we handled a watch status might 1109 * have changed" 1110 * 1111 * Fixing this lets us move dbus_watch_handle 1112 * calls into dbus-mainloop.c 1113 */ 1114 1115 if (_dbus_babysitter_get_child_exited (babysitter)) 1116 { 1117 DBusError error; 1118 DBusHashIter iter; 1119 1120 dbus_error_init (&error); 1121 _dbus_babysitter_set_child_exit_error (babysitter, &error); 1122 1123 /* Destroy all pending activations with the same exec */ 1124 _dbus_hash_iter_init (pending_activation->activation->pending_activations, 1125 &iter); 1126 while (_dbus_hash_iter_next (&iter)) 1127 { 1128 BusPendingActivation *p = _dbus_hash_iter_get_value (&iter); 1129 1130 if (p != pending_activation && strcmp (p->exec, pending_activation->exec) == 0) 1131 pending_activation_failed (p, &error); 1132 } 1133 1134 /* Destroys the pending activation */ 1135 pending_activation_failed (pending_activation, &error); 1136 1137 dbus_error_free (&error); 1138 } 1139 1140 _dbus_babysitter_unref (babysitter); 1141 1142 return retval; 1143 } 1144 1145 static dbus_bool_t 1146 add_babysitter_watch (DBusWatch *watch, 1147 void *data) 1148 { 1149 BusPendingActivation *pending_activation = data; 1150 1151 return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context), 1152 watch, babysitter_watch_callback, pending_activation, 1153 NULL); 1154 } 1155 1156 static void 1157 remove_babysitter_watch (DBusWatch *watch, 1158 void *data) 1159 { 1160 BusPendingActivation *pending_activation = data; 1161 1162 _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context), 1163 watch, babysitter_watch_callback, pending_activation); 1164 } 1165 1166 static dbus_bool_t 1167 pending_activation_timed_out (void *data) 1168 { 1169 BusPendingActivation *pending_activation = data; 1170 DBusError error; 1171 1172 /* Kill the spawned process, since it sucks 1173 * (not sure this is what we want to do, but 1174 * may as well try it for now) 1175 */ 1176 if (pending_activation->babysitter) 1177 _dbus_babysitter_kill_child (pending_activation->babysitter); 1178 1179 dbus_error_init (&error); 1180 1181 dbus_set_error (&error, DBUS_ERROR_TIMED_OUT, 1182 "Activation of %s timed out", 1183 pending_activation->service_name); 1184 1185 pending_activation_failed (pending_activation, &error); 1186 1187 dbus_error_free (&error); 1188 1189 return TRUE; 1190 } 1191 1192 static void 1193 cancel_pending (void *data) 1194 { 1195 BusPendingActivation *pending_activation = data; 1196 1197 _dbus_verbose ("Canceling pending activation of %s\n", 1198 pending_activation->service_name); 1199 1200 if (pending_activation->babysitter) 1201 _dbus_babysitter_kill_child (pending_activation->babysitter); 1202 1203 _dbus_hash_table_remove_string (pending_activation->activation->pending_activations, 1204 pending_activation->service_name); 1205 } 1206 1207 static void 1208 free_pending_cancel_data (void *data) 1209 { 1210 BusPendingActivation *pending_activation = data; 1211 1212 bus_pending_activation_unref (pending_activation); 1213 } 1214 1215 static dbus_bool_t 1216 add_cancel_pending_to_transaction (BusTransaction *transaction, 1217 BusPendingActivation *pending_activation) 1218 { 1219 if (!bus_transaction_add_cancel_hook (transaction, cancel_pending, 1220 pending_activation, 1221 free_pending_cancel_data)) 1222 return FALSE; 1223 1224 bus_pending_activation_ref (pending_activation); 1225 1226 _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n"); 1227 1228 return TRUE; 1229 } 1230 1231 static dbus_bool_t 1232 update_service_cache (BusActivation *activation, DBusError *error) 1233 { 1234 DBusHashIter iter; 1235 1236 _dbus_hash_iter_init (activation->directories, &iter); 1237 while (_dbus_hash_iter_next (&iter)) 1238 { 1239 DBusError tmp_error; 1240 BusServiceDirectory *s_dir; 1241 1242 s_dir = _dbus_hash_iter_get_value (&iter); 1243 1244 dbus_error_init (&tmp_error); 1245 if (!update_directory (activation, s_dir, &tmp_error)) 1246 { 1247 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) 1248 { 1249 dbus_move_error (&tmp_error, error); 1250 return FALSE; 1251 } 1252 1253 dbus_error_free (&tmp_error); 1254 continue; 1255 } 1256 } 1257 1258 return TRUE; 1259 } 1260 1261 static BusActivationEntry * 1262 activation_find_entry (BusActivation *activation, 1263 const char *service_name, 1264 DBusError *error) 1265 { 1266 BusActivationEntry *entry; 1267 1268 entry = _dbus_hash_table_lookup_string (activation->entries, service_name); 1269 if (!entry) 1270 { 1271 if (!update_service_cache (activation, error)) 1272 return NULL; 1273 1274 entry = _dbus_hash_table_lookup_string (activation->entries, 1275 service_name); 1276 } 1277 else 1278 { 1279 BusActivationEntry *updated_entry; 1280 1281 if (!check_service_file (activation, entry, &updated_entry, error)) 1282 return NULL; 1283 1284 entry = updated_entry; 1285 } 1286 1287 if (!entry) 1288 { 1289 dbus_set_error (error, DBUS_ERROR_SERVICE_UNKNOWN, 1290 "The name %s was not provided by any .service files", 1291 service_name); 1292 return NULL; 1293 } 1294 1295 return entry; 1296 } 1297 1298 dbus_bool_t 1299 bus_activation_activate_service (BusActivation *activation, 1300 DBusConnection *connection, 1301 BusTransaction *transaction, 1302 dbus_bool_t auto_activation, 1303 DBusMessage *activation_message, 1304 const char *service_name, 1305 DBusError *error) 1306 { 1307 BusActivationEntry *entry; 1308 BusPendingActivation *pending_activation; 1309 BusPendingActivationEntry *pending_activation_entry; 1310 DBusMessage *message; 1311 DBusString service_str; 1312 char **argv; 1313 int argc; 1314 dbus_bool_t retval; 1315 DBusHashIter iter; 1316 dbus_bool_t activated; 1317 1318 activated = TRUE; 1319 1320 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 1321 1322 if (activation->n_pending_activations >= 1323 bus_context_get_max_pending_activations (activation->context)) 1324 { 1325 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, 1326 "The maximum number of pending activations has been reached, activation of %s failed", 1327 service_name); 1328 return FALSE; 1329 } 1330 1331 entry = activation_find_entry (activation, service_name, error); 1332 if (!entry) 1333 return FALSE; 1334 1335 /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not 1336 * call us if the service is already active. 1337 */ 1338 if (!auto_activation) 1339 { 1340 /* Check if the service is active */ 1341 _dbus_string_init_const (&service_str, service_name); 1342 if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL) 1343 { 1344 dbus_uint32_t result; 1345 1346 _dbus_verbose ("Service \"%s\" is already active\n", service_name); 1347 1348 message = dbus_message_new_method_return (activation_message); 1349 1350 if (!message) 1351 { 1352 _dbus_verbose ("No memory to create reply to activate message\n"); 1353 BUS_SET_OOM (error); 1354 return FALSE; 1355 } 1356 1357 result = DBUS_START_REPLY_ALREADY_RUNNING; 1358 1359 if (!dbus_message_append_args (message, 1360 DBUS_TYPE_UINT32, &result, 1361 DBUS_TYPE_INVALID)) 1362 { 1363 _dbus_verbose ("No memory to set args of reply to activate message\n"); 1364 BUS_SET_OOM (error); 1365 dbus_message_unref (message); 1366 return FALSE; 1367 } 1368 1369 retval = bus_transaction_send_from_driver (transaction, connection, message); 1370 dbus_message_unref (message); 1371 if (!retval) 1372 { 1373 _dbus_verbose ("Failed to send reply\n"); 1374 BUS_SET_OOM (error); 1375 } 1376 1377 return retval; 1378 } 1379 } 1380 1381 pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1); 1382 if (!pending_activation_entry) 1383 { 1384 _dbus_verbose ("Failed to create pending activation entry\n"); 1385 BUS_SET_OOM (error); 1386 return FALSE; 1387 } 1388 1389 pending_activation_entry->auto_activation = auto_activation; 1390 1391 pending_activation_entry->activation_message = activation_message; 1392 dbus_message_ref (activation_message); 1393 pending_activation_entry->connection = connection; 1394 dbus_connection_ref (connection); 1395 1396 /* Check if the service is being activated */ 1397 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name); 1398 if (pending_activation) 1399 { 1400 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) 1401 { 1402 _dbus_verbose ("Failed to append a new entry to pending activation\n"); 1403 1404 BUS_SET_OOM (error); 1405 bus_pending_activation_entry_free (pending_activation_entry); 1406 return FALSE; 1407 } 1408 1409 pending_activation->n_entries += 1; 1410 pending_activation->activation->n_pending_activations += 1; 1411 } 1412 else 1413 { 1414 pending_activation = dbus_new0 (BusPendingActivation, 1); 1415 if (!pending_activation) 1416 { 1417 _dbus_verbose ("Failed to create pending activation\n"); 1418 1419 BUS_SET_OOM (error); 1420 bus_pending_activation_entry_free (pending_activation_entry); 1421 return FALSE; 1422 } 1423 1424 pending_activation->activation = activation; 1425 pending_activation->refcount = 1; 1426 1427 pending_activation->service_name = _dbus_strdup (service_name); 1428 if (!pending_activation->service_name) 1429 { 1430 _dbus_verbose ("Failed to copy service name for pending activation\n"); 1431 1432 BUS_SET_OOM (error); 1433 bus_pending_activation_unref (pending_activation); 1434 bus_pending_activation_entry_free (pending_activation_entry); 1435 return FALSE; 1436 } 1437 1438 pending_activation->exec = _dbus_strdup (entry->exec); 1439 if (!pending_activation->exec) 1440 { 1441 _dbus_verbose ("Failed to copy service exec for pending activation\n"); 1442 BUS_SET_OOM (error); 1443 bus_pending_activation_unref (pending_activation); 1444 bus_pending_activation_entry_free (pending_activation_entry); 1445 return FALSE; 1446 } 1447 1448 pending_activation->timeout = 1449 _dbus_timeout_new (bus_context_get_activation_timeout (activation->context), 1450 pending_activation_timed_out, 1451 pending_activation, 1452 NULL); 1453 if (!pending_activation->timeout) 1454 { 1455 _dbus_verbose ("Failed to create timeout for pending activation\n"); 1456 1457 BUS_SET_OOM (error); 1458 bus_pending_activation_unref (pending_activation); 1459 bus_pending_activation_entry_free (pending_activation_entry); 1460 return FALSE; 1461 } 1462 1463 if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context), 1464 pending_activation->timeout, 1465 handle_timeout_callback, 1466 pending_activation, 1467 NULL)) 1468 { 1469 _dbus_verbose ("Failed to add timeout for pending activation\n"); 1470 1471 BUS_SET_OOM (error); 1472 bus_pending_activation_unref (pending_activation); 1473 bus_pending_activation_entry_free (pending_activation_entry); 1474 return FALSE; 1475 } 1476 1477 pending_activation->timeout_added = TRUE; 1478 1479 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) 1480 { 1481 _dbus_verbose ("Failed to add entry to just-created pending activation\n"); 1482 1483 BUS_SET_OOM (error); 1484 bus_pending_activation_unref (pending_activation); 1485 bus_pending_activation_entry_free (pending_activation_entry); 1486 return FALSE; 1487 } 1488 1489 pending_activation->n_entries += 1; 1490 pending_activation->activation->n_pending_activations += 1; 1491 1492 activated = FALSE; 1493 _dbus_hash_iter_init (activation->pending_activations, &iter); 1494 while (_dbus_hash_iter_next (&iter)) 1495 { 1496 BusPendingActivation *p = _dbus_hash_iter_get_value (&iter); 1497 1498 if (strcmp (p->exec, entry->exec) == 0) 1499 { 1500 activated = TRUE; 1501 break; 1502 } 1503 } 1504 1505 if (!_dbus_hash_table_insert_string (activation->pending_activations, 1506 pending_activation->service_name, 1507 pending_activation)) 1508 { 1509 _dbus_verbose ("Failed to put pending activation in hash table\n"); 1510 1511 BUS_SET_OOM (error); 1512 bus_pending_activation_unref (pending_activation); 1513 return FALSE; 1514 } 1515 } 1516 1517 if (!add_cancel_pending_to_transaction (transaction, pending_activation)) 1518 { 1519 _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n"); 1520 BUS_SET_OOM (error); 1521 _dbus_hash_table_remove_string (activation->pending_activations, 1522 pending_activation->service_name); 1523 1524 return FALSE; 1525 } 1526 1527 if (activated) 1528 return TRUE; 1529 1530 /* Now try to spawn the process */ 1531 if (!_dbus_shell_parse_argv (entry->exec, &argc, &argv, error)) 1532 { 1533 _dbus_verbose ("Failed to parse command line: %s\n", entry->exec); 1534 _DBUS_ASSERT_ERROR_IS_SET (error); 1535 1536 _dbus_hash_table_remove_string (activation->pending_activations, 1537 pending_activation->service_name); 1538 1539 return FALSE; 1540 } 1541 1542 _dbus_verbose ("Spawning %s ...\n", argv[0]); 1543 if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv, 1544 child_setup, activation, 1545 error)) 1546 { 1547 _dbus_verbose ("Failed to spawn child\n"); 1548 _DBUS_ASSERT_ERROR_IS_SET (error); 1549 dbus_free_string_array (argv); 1550 1551 return FALSE; 1552 } 1553 1554 dbus_free_string_array (argv); 1555 1556 _dbus_assert (pending_activation->babysitter != NULL); 1557 1558 if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter, 1559 add_babysitter_watch, 1560 remove_babysitter_watch, 1561 NULL, 1562 pending_activation, 1563 NULL)) 1564 { 1565 BUS_SET_OOM (error); 1566 _dbus_verbose ("Failed to set babysitter watch functions\n"); 1567 return FALSE; 1568 } 1569 1570 return TRUE; 1571 } 1572 1573 dbus_bool_t 1574 bus_activation_list_services (BusActivation *activation, 1575 char ***listp, 1576 int *array_len) 1577 { 1578 int i, j, len; 1579 char **retval; 1580 DBusHashIter iter; 1581 1582 len = _dbus_hash_table_get_n_entries (activation->entries); 1583 retval = dbus_new (char *, len + 1); 1584 1585 if (retval == NULL) 1586 return FALSE; 1587 1588 _dbus_hash_iter_init (activation->entries, &iter); 1589 i = 0; 1590 while (_dbus_hash_iter_next (&iter)) 1591 { 1592 BusActivationEntry *entry = _dbus_hash_iter_get_value (&iter); 1593 1594 retval[i] = _dbus_strdup (entry->name); 1595 if (retval[i] == NULL) 1596 goto error; 1597 1598 i++; 1599 } 1600 1601 retval[i] = NULL; 1602 1603 if (array_len) 1604 *array_len = len; 1605 1606 *listp = retval; 1607 return TRUE; 1608 1609 error: 1610 for (j = 0; j < i; j++) 1611 dbus_free (retval[i]); 1612 dbus_free (retval); 1613 1614 return FALSE; 1615 } 1616 1617 1618 #ifdef DBUS_BUILD_TESTS 1619 1620 #include <stdio.h> 1621 1622 #define SERVICE_NAME_1 "MyService1" 1623 #define SERVICE_NAME_2 "MyService2" 1624 #define SERVICE_NAME_3 "MyService3" 1625 1626 #define SERVICE_FILE_1 "service-1.service" 1627 #define SERVICE_FILE_2 "service-2.service" 1628 #define SERVICE_FILE_3 "service-3.service" 1629 1630 static dbus_bool_t 1631 test_create_service_file (DBusString *dir, 1632 const char *filename, 1633 const char *name, 1634 const char *exec) 1635 { 1636 DBusString file_name, full_path; 1637 FILE *file; 1638 dbus_bool_t ret_val; 1639 1640 ret_val = TRUE; 1641 _dbus_string_init_const (&file_name, filename); 1642 1643 if (!_dbus_string_init (&full_path)) 1644 return FALSE; 1645 1646 if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) || 1647 !_dbus_concat_dir_and_file (&full_path, &file_name)) 1648 { 1649 ret_val = FALSE; 1650 goto out; 1651 } 1652 1653 file = fopen (_dbus_string_get_const_data (&full_path), "w"); 1654 if (!file) 1655 { 1656 ret_val = FALSE; 1657 goto out; 1658 } 1659 1660 fprintf (file, "[D-BUS Service]\nName=%s\nExec=%s\n", name, exec); 1661 fclose (file); 1662 1663 out: 1664 _dbus_string_free (&full_path); 1665 return ret_val; 1666 } 1667 1668 static dbus_bool_t 1669 test_remove_service_file (DBusString *dir, const char *filename) 1670 { 1671 DBusString file_name, full_path; 1672 dbus_bool_t ret_val; 1673 1674 ret_val = TRUE; 1675 1676 _dbus_string_init_const (&file_name, filename); 1677 1678 if (!_dbus_string_init (&full_path)) 1679 return FALSE; 1680 1681 if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) || 1682 !_dbus_concat_dir_and_file (&full_path, &file_name)) 1683 { 1684 ret_val = FALSE; 1685 goto out; 1686 } 1687 1688 if (!_dbus_delete_file (&full_path, NULL)) 1689 { 1690 ret_val = FALSE; 1691 goto out; 1692 } 1693 1694 out: 1695 _dbus_string_free (&full_path); 1696 return ret_val; 1697 } 1698 1699 static dbus_bool_t 1700 test_remove_directory (DBusString *dir) 1701 { 1702 DBusDirIter *iter; 1703 DBusString filename, full_path; 1704 dbus_bool_t ret_val; 1705 1706 ret_val = TRUE; 1707 1708 if (!_dbus_string_init (&filename)) 1709 return FALSE; 1710 1711 if (!_dbus_string_init (&full_path)) 1712 { 1713 _dbus_string_free (&filename); 1714 return FALSE; 1715 } 1716 1717 iter = _dbus_directory_open (dir, NULL); 1718 if (iter == NULL) 1719 { 1720 ret_val = FALSE; 1721 goto out; 1722 } 1723 1724 while (_dbus_directory_get_next_file (iter, &filename, NULL)) 1725 { 1726 if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename))) 1727 { 1728 ret_val = FALSE; 1729 goto out; 1730 } 1731 } 1732 _dbus_directory_close (iter); 1733 1734 if (!_dbus_delete_directory (dir, NULL)) 1735 { 1736 ret_val = FALSE; 1737 goto out; 1738 } 1739 1740 out: 1741 _dbus_string_free (&filename); 1742 _dbus_string_free (&full_path); 1743 1744 return ret_val; 1745 } 1746 1747 static dbus_bool_t 1748 init_service_reload_test (DBusString *dir) 1749 { 1750 DBusStat stat_buf; 1751 1752 if (!_dbus_stat (dir, &stat_buf, NULL)) 1753 { 1754 if (!_dbus_create_directory (dir, NULL)) 1755 return FALSE; 1756 } 1757 else 1758 { 1759 if (!test_remove_directory (dir)) 1760 return FALSE; 1761 1762 if (!_dbus_create_directory (dir, NULL)) 1763 return FALSE; 1764 } 1765 1766 /* Create one initial file */ 1767 if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1")) 1768 return FALSE; 1769 1770 return TRUE; 1771 } 1772 1773 static dbus_bool_t 1774 cleanup_service_reload_test (DBusString *dir) 1775 { 1776 if (!test_remove_directory (dir)) 1777 return FALSE; 1778 1779 return TRUE; 1780 } 1781 1782 typedef struct 1783 { 1784 BusActivation *activation; 1785 const char *service_name; 1786 dbus_bool_t expecting_find; 1787 } CheckData; 1788 1789 static dbus_bool_t 1790 check_func (void *data) 1791 { 1792 CheckData *d; 1793 BusActivationEntry *entry; 1794 DBusError error; 1795 dbus_bool_t ret_val; 1796 1797 ret_val = TRUE; 1798 d = data; 1799 1800 dbus_error_init (&error); 1801 1802 entry = activation_find_entry (d->activation, d->service_name, &error); 1803 if (entry == NULL) 1804 { 1805 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 1806 { 1807 ret_val = TRUE; 1808 } 1809 else 1810 { 1811 if (d->expecting_find) 1812 ret_val = FALSE; 1813 } 1814 1815 dbus_error_free (&error); 1816 } 1817 else 1818 { 1819 if (!d->expecting_find) 1820 ret_val = FALSE; 1821 } 1822 1823 return ret_val; 1824 } 1825 1826 static dbus_bool_t 1827 do_test (const char *description, dbus_bool_t oom_test, CheckData *data) 1828 { 1829 dbus_bool_t err; 1830 1831 if (oom_test) 1832 err = !_dbus_test_oom_handling (description, check_func, data); 1833 else 1834 err = !check_func (data); 1835 1836 if (err) 1837 _dbus_assert_not_reached ("Test failed"); 1838 1839 return TRUE; 1840 } 1841 1842 static dbus_bool_t 1843 do_service_reload_test (DBusString *dir, dbus_bool_t oom_test) 1844 { 1845 BusActivation *activation; 1846 DBusString address; 1847 DBusList *directories; 1848 CheckData d; 1849 1850 directories = NULL; 1851 _dbus_string_init_const (&address, ""); 1852 1853 if (!_dbus_list_append (&directories, _dbus_string_get_data (dir))) 1854 return FALSE; 1855 1856 activation = bus_activation_new (NULL, &address, &directories, NULL); 1857 if (!activation) 1858 return FALSE; 1859 1860 d.activation = activation; 1861 1862 /* Check for existing service file */ 1863 d.expecting_find = TRUE; 1864 d.service_name = SERVICE_NAME_1; 1865 1866 if (!do_test ("Existing service file", oom_test, &d)) 1867 return FALSE; 1868 1869 /* Check for non-existing service file */ 1870 d.expecting_find = FALSE; 1871 d.service_name = SERVICE_NAME_3; 1872 1873 if (!do_test ("Nonexisting service file", oom_test, &d)) 1874 return FALSE; 1875 1876 /* Check for added service file */ 1877 if (!test_create_service_file (dir, SERVICE_FILE_2, SERVICE_NAME_2, "exec-2")) 1878 return FALSE; 1879 1880 d.expecting_find = TRUE; 1881 d.service_name = SERVICE_NAME_2; 1882 1883 if (!do_test ("Added service file", oom_test, &d)) 1884 return FALSE; 1885 1886 /* Check for removed service file */ 1887 if (!test_remove_service_file (dir, SERVICE_FILE_2)) 1888 return FALSE; 1889 1890 d.expecting_find = FALSE; 1891 d.service_name = SERVICE_FILE_2; 1892 1893 if (!do_test ("Removed service file", oom_test, &d)) 1894 return FALSE; 1895 1896 /* Check for updated service file */ 1897 1898 _dbus_sleep_milliseconds (1000); /* Sleep a second to make sure the mtime is updated */ 1899 1900 if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_3, "exec-3")) 1901 return FALSE; 1902 1903 d.expecting_find = TRUE; 1904 d.service_name = SERVICE_NAME_3; 1905 1906 if (!do_test ("Updated service file, part 1", oom_test, &d)) 1907 return FALSE; 1908 1909 d.expecting_find = FALSE; 1910 d.service_name = SERVICE_NAME_1; 1911 1912 if (!do_test ("Updated service file, part 2", oom_test, &d)) 1913 return FALSE; 1914 1915 bus_activation_unref (activation); 1916 _dbus_list_clear (&directories); 1917 1918 return TRUE; 1919 } 1920 1921 dbus_bool_t 1922 bus_activation_service_reload_test (const DBusString *test_data_dir) 1923 { 1924 DBusString directory; 1925 1926 if (!_dbus_string_init (&directory)) 1927 return FALSE; 1928 1929 if (!_dbus_string_append (&directory, _dbus_get_tmpdir())) 1930 return FALSE; 1931 1932 if (!_dbus_string_append (&directory, "/dbus-reload-test-") || 1933 !_dbus_generate_random_ascii (&directory, 6)) 1934 { 1935 return FALSE; 1936 } 1937 1938 /* Do normal tests */ 1939 if (!init_service_reload_test (&directory)) 1940 _dbus_assert_not_reached ("could not initiate service reload test"); 1941 1942 if (!do_service_reload_test (&directory, FALSE)) 1943 ; /* Do nothing? */ 1944 1945 /* Do OOM tests */ 1946 if (!init_service_reload_test (&directory)) 1947 _dbus_assert_not_reached ("could not initiate service reload test"); 1948 1949 if (!do_service_reload_test (&directory, TRUE)) 1950 ; /* Do nothing? */ 1951 1952 /* Cleanup test directory */ 1953 if (!cleanup_service_reload_test (&directory)) 1954 return FALSE; 1955 1956 _dbus_string_free (&directory); 1957 1958 return TRUE; 1959 } 1960 1961 #endif /* DBUS_BUILD_TESTS */ 1962