searchcode logo
Dogecoin is an open source peer-to-peer cryptocurrency

Tizin /dbus/bus/activation.c

git clone https://review.tizen.org/git/

Language

C

MD5 Hash

6c3aef1e2235e07461f7c1046e5ceada

Lines in File 2534
Blank Lines 469 (18.51%)
Comment Lines 141 (6%)
Code Lines 1923 (76%)
Estimated Development Effort (Months)4.77
Estimated Development Effort (Years)0
Estimated Developers1.05
Estimated Cost$53681.00
Generated using David A. Wheeler's 'SLOCCount'.
  1. /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23.  *
  24.  */
  25.  
  26. #include <config.h>
  27. #include "activation.h"
  28. #include "activation-exit-codes.h"
  29. #include "desktop-file.h"
  30. #include "dispatch.h"
  31. #include "services.h"
  32. #include "test.h"
  33. #include "utils.h"
  34. #include <dbus/dbus-internals.h>
  35. #include <dbus/dbus-hash.h>
  36. #include <dbus/dbus-list.h>
  37. #include <dbus/dbus-shell.h>
  38. #include <dbus/dbus-spawn.h>
  39. #include <dbus/dbus-timeout.h>
  40. #include <dbus/dbus-sysdeps.h>
  41. #ifdef HAVE_ERRNO_H
  42. #include <errno.h>
  43. #endif
  44.  
  45. struct BusActivation
  46. {
  47. int refcount;
  48. DBusHashTable *entries;
  49. DBusHashTable *pending_activations;
  50. char *server_address;
  51. BusContext *context;
  52. int n_pending_activations; /**< This is in fact the number of BusPendingActivationEntry,
  53.   * i.e. number of pending activation requests, not pending
  54.   * activations per se
  55.   */
  56. DBusHashTable *directories;
  57. DBusHashTable *environment;
  58. };
  59.  
  60. typedef struct
  61. {
  62. int refcount;
  63. char *dir_c;
  64. DBusHashTable *entries;
  65. } BusServiceDirectory;
  66.  
  67. typedef struct
  68. {
  69. int refcount;
  70. char *name;
  71. char *exec;
  72. char *user;
  73. char *systemd_service;
  74. unsigned long mtime;
  75. BusServiceDirectory *s_dir;
  76. char *filename;
  77. } BusActivationEntry;
  78.  
  79. typedef struct BusPendingActivationEntry BusPendingActivationEntry;
  80.  
  81. struct BusPendingActivationEntry
  82. {
  83. DBusMessage *activation_message;
  84. DBusConnection *connection;
  85.  
  86. dbus_bool_t auto_activation;
  87. };
  88.  
  89. typedef struct
  90. {
  91. int refcount;
  92. BusActivation *activation;
  93. char *service_name;
  94. char *exec;
  95. char *systemd_service;
  96. DBusList *entries;
  97. int n_entries;
  98. DBusBabysitter *babysitter;
  99. DBusTimeout *timeout;
  100. unsigned int timeout_added : 1;
  101. } BusPendingActivation;
  102.  
  103. #if 0
  104. static BusServiceDirectory *
  105. bus_service_directory_ref (BusServiceDirectory *dir)
  106. {
  107. _dbus_assert (dir->refcount);
  108.  
  109. dir->refcount++;
  110.  
  111. return dir;
  112. }
  113. #endif
  114.  
  115. static void
  116. bus_service_directory_unref (BusServiceDirectory *dir)
  117. {
  118. if (dir == NULL)
  119. return;
  120.  
  121. _dbus_assert (dir->refcount > 0);
  122. dir->refcount--;
  123.  
  124. if (dir->refcount > 0)
  125. return;
  126.  
  127. if (dir->entries)
  128. _dbus_hash_table_unref (dir->entries);
  129.  
  130. dbus_free (dir->dir_c);
  131. dbus_free (dir);
  132. }
  133.  
  134. static void
  135. bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
  136. {
  137. if (entry->activation_message)
  138. dbus_message_unref (entry->activation_message);
  139.  
  140. if (entry->connection)
  141. dbus_connection_unref (entry->connection);
  142.  
  143. dbus_free (entry);
  144. }
  145.  
  146. static void
  147. handle_timeout_callback (DBusTimeout *timeout,
  148. void *data)
  149. {
  150. BusPendingActivation *pending_activation = data;
  151.  
  152. while (!dbus_timeout_handle (pending_activation->timeout))
  153. _dbus_wait_for_memory ();
  154. }
  155.  
  156. static BusPendingActivation *
  157. bus_pending_activation_ref (BusPendingActivation *pending_activation)
  158. {
  159. _dbus_assert (pending_activation->refcount > 0);
  160. pending_activation->refcount += 1;
  161.  
  162. return pending_activation;
  163. }
  164.  
  165. static void
  166. bus_pending_activation_unref (BusPendingActivation *pending_activation)
  167. {
  168. DBusList *link;
  169.  
  170. if (pending_activation == NULL) /* hash table requires this */
  171. return;
  172.  
  173. _dbus_assert (pending_activation->refcount > 0);
  174. pending_activation->refcount -= 1;
  175.  
  176. if (pending_activation->refcount > 0)
  177. return;
  178.  
  179. if (pending_activation->timeout_added)
  180. {
  181. _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context),
  182. pending_activation->timeout,
  183. handle_timeout_callback, pending_activation);
  184. pending_activation->timeout_added = FALSE;
  185. }
  186.  
  187. if (pending_activation->timeout)
  188. _dbus_timeout_unref (pending_activation->timeout);
  189.  
  190. if (pending_activation->babysitter)
  191. {
  192. if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
  193. NULL, NULL, NULL,
  194. pending_activation->babysitter,
  195. NULL))
  196. _dbus_assert_not_reached ("setting watch functions to NULL failed");
  197.  
  198. _dbus_babysitter_unref (pending_activation->babysitter);
  199. }
  200.  
  201. dbus_free (pending_activation->service_name);
  202. dbus_free (pending_activation->exec);
  203. dbus_free (pending_activation->systemd_service);
  204.  
  205. link = _dbus_list_get_first_link (&pending_activation->entries);
  206.  
  207. while (link != NULL)
  208. {
  209. BusPendingActivationEntry *entry = link->data;
  210.  
  211. bus_pending_activation_entry_free (entry);
  212.  
  213. link = _dbus_list_get_next_link (&pending_activation->entries, link);
  214. }
  215. _dbus_list_clear (&pending_activation->entries);
  216.  
  217. pending_activation->activation->n_pending_activations -=
  218. pending_activation->n_entries;
  219.  
  220. _dbus_assert (pending_activation->activation->n_pending_activations >= 0);
  221.  
  222. dbus_free (pending_activation);
  223. }
  224.  
  225. static BusActivationEntry *
  226. bus_activation_entry_ref (BusActivationEntry *entry)
  227. {
  228. _dbus_assert (entry->refcount > 0);
  229. entry->refcount++;
  230.  
  231. return entry;
  232. }
  233.  
  234. static void
  235. bus_activation_entry_unref (BusActivationEntry *entry)
  236. {
  237. if (entry == NULL) /* hash table requires this */
  238. return;
  239.  
  240. _dbus_assert (entry->refcount > 0);
  241. entry->refcount--;
  242.  
  243. if (entry->refcount > 0)
  244. return;
  245.  
  246. dbus_free (entry->name);
  247. dbus_free (entry->exec);
  248. dbus_free (entry->user);
  249. dbus_free (entry->filename);
  250. dbus_free (entry->systemd_service);
  251.  
  252. dbus_free (entry);
  253. }
  254.  
  255. static dbus_bool_t
  256. update_desktop_file_entry (BusActivation *activation,
  257. BusServiceDirectory *s_dir,
  258. DBusString *filename,
  259. BusDesktopFile *desktop_file,
  260. DBusError *error)
  261. {
  262. char *name, *exec, *user, *exec_tmp, *systemd_service;
  263. BusActivationEntry *entry;
  264. DBusStat stat_buf;
  265. DBusString file_path;
  266. DBusError tmp_error;
  267. dbus_bool_t retval;
  268.  
  269. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  270.  
  271. name = NULL;
  272. exec = NULL;
  273. user = NULL;
  274. exec_tmp = NULL;
  275. entry = NULL;
  276. systemd_service = NULL;
  277.  
  278. dbus_error_init (&tmp_error);
  279.  
  280. if (!_dbus_string_init (&file_path))
  281. {
  282. BUS_SET_OOM (error);
  283. return FALSE;
  284. }
  285.  
  286. if (!_dbus_string_append (&file_path, s_dir->dir_c) ||
  287. !_dbus_concat_dir_and_file (&file_path, filename))
  288. {
  289. BUS_SET_OOM (error);
  290. goto out;
  291. }
  292.  
  293. if (!_dbus_stat (&file_path, &stat_buf, NULL))
  294. {
  295. dbus_set_error (error, DBUS_ERROR_FAILED,
  296. "Can't stat the service file\n");
  297. goto out;
  298. }
  299.  
  300. if (!bus_desktop_file_get_string (desktop_file,
  301. DBUS_SERVICE_SECTION,
  302. DBUS_SERVICE_NAME,
  303. &name,
  304. error))
  305. goto out;
  306.  
  307. if (!bus_desktop_file_get_string (desktop_file,
  308. DBUS_SERVICE_SECTION,
  309. DBUS_SERVICE_EXEC,
  310. &exec_tmp,
  311. error))
  312. goto out;
  313.  
  314. exec = _dbus_strdup (_dbus_replace_install_prefix (exec_tmp));
  315. dbus_free (exec_tmp);
  316. exec_tmp = NULL;
  317.  
  318. /* user is not _required_ unless we are using system activation */
  319. if (!bus_desktop_file_get_string (desktop_file,
  320. DBUS_SERVICE_SECTION,
  321. DBUS_SERVICE_USER,
  322. &user, &tmp_error))
  323. {
  324. _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
  325. /* if we got OOM, then exit */
  326. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  327. {
  328. dbus_move_error (&tmp_error, error);
  329. goto out;
  330. }
  331. else
  332. {
  333. /* if we have error because we didn't find anything then continue */
  334. dbus_error_free (&tmp_error);
  335. dbus_free (user);
  336. user = NULL;
  337. }
  338. }
  339. _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
  340.  
  341. /* systemd service is never required */
  342. if (!bus_desktop_file_get_string (desktop_file,
  343. DBUS_SERVICE_SECTION,
  344. DBUS_SERVICE_SYSTEMD_SERVICE,
  345. &systemd_service, &tmp_error))
  346. {
  347. _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
  348. /* if we got OOM, then exit */
  349. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  350. {
  351. dbus_move_error (&tmp_error, error);
  352. goto out;
  353. }
  354. else
  355. {
  356. /* if we have error because we didn't find anything then continue */
  357. dbus_error_free (&tmp_error);
  358. dbus_free (systemd_service);
  359. systemd_service = NULL;
  360. }
  361. }
  362.  
  363. _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
  364.  
  365. entry = _dbus_hash_table_lookup_string (s_dir->entries,
  366. _dbus_string_get_const_data (filename));
  367.  
  368. if (entry == NULL) /* New file */
  369. {
  370. /* FIXME we need a better-defined algorithm for which service file to
  371.   * pick than "whichever one is first in the directory listing"
  372.   */
  373. if (_dbus_hash_table_lookup_string (activation->entries, name))
  374. {
  375. dbus_set_error (error, DBUS_ERROR_FAILED,
  376. "Service %s already exists in activation entry list\n", name);
  377. goto out;
  378. }
  379.  
  380. entry = dbus_new0 (BusActivationEntry, 1);
  381. if (entry == NULL)
  382. {
  383. BUS_SET_OOM (error);
  384. goto out;
  385. }
  386.  
  387. entry->name = name;
  388. entry->exec = exec;
  389. entry->user = user;
  390. entry->systemd_service = systemd_service;
  391. entry->refcount = 1;
  392.  
  393. /* ownership has been transferred to entry, do not free separately */
  394. name = NULL;
  395. exec = NULL;
  396. user = NULL;
  397. systemd_service = NULL;
  398.  
  399. entry->s_dir = s_dir;
  400. entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename));
  401. if (!entry->filename)
  402. {
  403. BUS_SET_OOM (error);
  404. goto out;
  405. }
  406.  
  407. if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry)))
  408. {
  409. BUS_SET_OOM (error);
  410. goto out;
  411. }
  412.  
  413. if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry)))
  414. {
  415. /* Revert the insertion in the entries table */
  416. _dbus_hash_table_remove_string (activation->entries, entry->name);
  417. BUS_SET_OOM (error);
  418. goto out;
  419. }
  420.  
  421. _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
  422. }
  423. else /* Just update the entry */
  424. {
  425. bus_activation_entry_ref (entry);
  426. _dbus_hash_table_remove_string (activation->entries, entry->name);
  427.  
  428. if (_dbus_hash_table_lookup_string (activation->entries, name))
  429. {
  430. _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n",
  431. name, _dbus_string_get_const_data (&file_path));
  432. goto out;
  433. }
  434.  
  435. /* ownership has been transferred to entry, do not free separately */
  436. dbus_free (entry->name);
  437. entry->name = name;
  438. name = NULL;
  439.  
  440. dbus_free (entry->exec);
  441. entry->exec = exec;
  442. exec = NULL;
  443.  
  444. dbus_free (entry->user);
  445. entry->user = user;
  446. user = NULL;
  447.  
  448. dbus_free (entry->systemd_service);
  449. entry->systemd_service = systemd_service;
  450. systemd_service = NULL;
  451.  
  452. if (!_dbus_hash_table_insert_string (activation->entries,
  453. entry->name, bus_activation_entry_ref(entry)))
  454. {
  455. BUS_SET_OOM (error);
  456. /* Also remove path to entries hash since we want this in sync with
  457.   * the entries hash table */
  458. _dbus_hash_table_remove_string (entry->s_dir->entries,
  459. entry->filename);
  460. bus_activation_entry_unref (entry);
  461. return FALSE;
  462. }
  463. }
  464.  
  465. entry->mtime = stat_buf.mtime;
  466. retval = TRUE;
  467.  
  468. out:
  469. /* if these have been transferred into entry, the variables will be NULL */
  470. dbus_free (name);
  471. dbus_free (exec);
  472. dbus_free (user);
  473. dbus_free (systemd_service);
  474. _dbus_string_free (&file_path);
  475.  
  476. if (entry)
  477. bus_activation_entry_unref (entry);
  478.  
  479. return FALSE;
  480. }
  481.  
  482. static dbus_bool_t
  483. check_service_file (BusActivation *activation,
  484. BusActivationEntry *entry,
  485. BusActivationEntry **updated_entry,
  486. DBusError *error)
  487. {
  488. DBusStat stat_buf;
  489. dbus_bool_t retval;
  490. BusActivationEntry *tmp_entry;
  491. DBusString file_path;
  492. DBusString filename;
  493.  
  494. retval = TRUE;
  495. tmp_entry = entry;
  496.  
  497. _dbus_string_init_const (&filename, entry->filename);
  498.  
  499. if (!_dbus_string_init (&file_path))
  500. {
  501. BUS_SET_OOM (error);
  502. return FALSE;
  503. }
  504.  
  505. if (!_dbus_string_append (&file_path, entry->s_dir->dir_c) ||
  506. !_dbus_concat_dir_and_file (&file_path, &filename))
  507. {
  508. BUS_SET_OOM (error);
  509. retval = FALSE;
  510. goto out;
  511. }
  512.  
  513. if (!_dbus_stat (&file_path, &stat_buf, NULL))
  514. {
  515. _dbus_verbose ("****** Can't stat file \"%s\", removing from cache\n",
  516. _dbus_string_get_const_data (&file_path));
  517.  
  518. _dbus_hash_table_remove_string (activation->entries, entry->name);
  519. _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename);
  520.  
  521. tmp_entry = NULL;
  522. retval = TRUE;
  523. goto out;
  524. }
  525. else
  526. {
  527. if (stat_buf.mtime > entry->mtime)
  528. {
  529. BusDesktopFile *desktop_file;
  530. DBusError tmp_error;
  531.  
  532. dbus_error_init (&tmp_error);
  533.  
  534. desktop_file = bus_desktop_file_load (&file_path, &tmp_error);
  535. if (desktop_file == NULL)
  536. {
  537. _dbus_verbose ("Could not load %s: %s\n",
  538. _dbus_string_get_const_data (&file_path),
  539. tmp_error.message);
  540. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  541. {
  542. dbus_move_error (&tmp_error, error);
  543. retval = FALSE;
  544. goto out;
  545. }
  546. dbus_error_free (&tmp_error);
  547. retval = TRUE;
  548. goto out;
  549. }
  550.  
  551. /* @todo We can return OOM or a DBUS_ERROR_FAILED error
  552.   * Handle these both better
  553.   */
  554. if (!update_desktop_file_entry (activation, entry->s_dir, &filename, desktop_file, &tmp_error))
  555. {
  556. bus_desktop_file_free (desktop_file);
  557. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  558. {
  559. dbus_move_error (&tmp_error, error);
  560. retval = FALSE;
  561. goto out;
  562. }
  563. dbus_error_free (&tmp_error);
  564. retval = TRUE;
  565. goto out;
  566. }
  567.  
  568. bus_desktop_file_free (desktop_file);
  569. retval = TRUE;
  570. }
  571. }
  572.  
  573. out:
  574. _dbus_string_free (&file_path);
  575.  
  576. if (updated_entry != NULL)
  577. *updated_entry = tmp_entry;
  578. return retval;
  579. }
  580.  
  581.  
  582. /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
  583.  * hash entries it already added.
  584.  */
  585. static dbus_bool_t
  586. update_directory (BusActivation *activation,
  587. BusServiceDirectory *s_dir,
  588. DBusError *error)
  589. {
  590. DBusDirIter *iter;
  591. DBusString dir, filename;
  592. BusDesktopFile *desktop_file;
  593. DBusError tmp_error;
  594. dbus_bool_t retval;
  595. BusActivationEntry *entry;
  596. DBusString full_path;
  597.  
  598. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  599.  
  600. iter = NULL;
  601. desktop_file = NULL;
  602.  
  603. _dbus_string_init_const (&dir, s_dir->dir_c);
  604.  
  605. if (!_dbus_string_init (&filename))
  606. {
  607. BUS_SET_OOM (error);
  608. return FALSE;
  609. }
  610.  
  611. if (!_dbus_string_init (&full_path))
  612. {
  613. BUS_SET_OOM (error);
  614. _dbus_string_free (&filename);
  615. return FALSE;
  616. }
  617.  
  618. retval = FALSE;
  619.  
  620. /* from this point it's safe to "goto out" */
  621.  
  622. iter = _dbus_directory_open (&dir, error);
  623. if (iter == NULL)
  624. {
  625. _dbus_verbose ("Failed to open directory %s: %s\n",
  626. s_dir->dir_c,
  627. error ? error->message : "unknown");
  628. goto out;
  629. }
  630.  
  631. /* Now read the files */
  632. dbus_error_init (&tmp_error);
  633. while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
  634. {
  635. _dbus_assert (!dbus_error_is_set (&tmp_error));
  636.  
  637. _dbus_string_set_length (&full_path, 0);
  638.  
  639. if (!_dbus_string_ends_with_c_str (&filename, ".service"))
  640. {
  641. _dbus_verbose ("Skipping non-.service file %s\n",
  642. _dbus_string_get_const_data (&filename));
  643. continue;
  644. }
  645.  
  646. entry = _dbus_hash_table_lookup_string (s_dir->entries, _dbus_string_get_const_data (&filename));
  647. if (entry) /* Already has this service file in the cache */
  648. {
  649. if (!check_service_file (activation, entry, NULL, error))
  650. goto out;
  651.  
  652. continue;
  653. }
  654.  
  655. if (!_dbus_string_append (&full_path, s_dir->dir_c) ||
  656. !_dbus_concat_dir_and_file (&full_path, &filename))
  657. {
  658. BUS_SET_OOM (error);
  659. goto out;
  660. }
  661.  
  662. /* New file */
  663. desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
  664. if (desktop_file == NULL)
  665. {
  666. _dbus_verbose ("Could not load %s: %s\n",
  667. _dbus_string_get_const_data (&full_path),
  668. tmp_error.message);
  669.  
  670. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  671. {
  672. dbus_move_error (&tmp_error, error);
  673. goto out;
  674. }
  675.  
  676. dbus_error_free (&tmp_error);
  677. continue;
  678. }
  679.  
  680. /* @todo We can return OOM or a DBUS_ERROR_FAILED error
  681.   * Handle these both better
  682.   */
  683. if (!update_desktop_file_entry (activation, s_dir, &filename, desktop_file, &tmp_error))
  684. {
  685. bus_desktop_file_free (desktop_file);
  686. desktop_file = NULL;
  687.  
  688. _dbus_verbose ("Could not add %s to activation entry list: %s\n",
  689. _dbus_string_get_const_data (&full_path), tmp_error.message);
  690.  
  691. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  692. {
  693. dbus_move_error (&tmp_error, error);
  694. goto out;
  695. }
  696.  
  697. dbus_error_free (&tmp_error);
  698. continue;
  699. }
  700. else
  701. {
  702. bus_desktop_file_free (desktop_file);
  703. desktop_file = NULL;
  704. continue;
  705. }
  706. }
  707.  
  708. if (dbus_error_is_set (&tmp_error))
  709. {
  710. dbus_move_error (&tmp_error, error);
  711. goto out;
  712. }
  713.  
  714. retval = TRUE;
  715.  
  716. out:
  717. if (!retval)
  718. _DBUS_ASSERT_ERROR_IS_SET (error);
  719. else
  720. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  721.  
  722. if (iter != NULL)
  723. _dbus_directory_close (iter);
  724. _dbus_string_free (&filename);
  725. _dbus_string_free (&full_path);
  726.  
  727. return retval;
  728. }
  729.  
  730. static dbus_bool_t
  731. populate_environment (BusActivation *activation)
  732. {
  733. DBusString key;
  734. DBusString value;
  735. int i;
  736. char **environment;
  737. dbus_bool_t retval = FALSE;
  738.  
  739. environment = _dbus_get_environment ();
  740.  
  741. if (environment == NULL)
  742. return FALSE;
  743.  
  744. if (!_dbus_string_init (&key))
  745. {
  746. dbus_free_string_array (environment);
  747. return FALSE;
  748. }
  749.  
  750. if (!_dbus_string_init (&value))
  751. {
  752. _dbus_string_free (&key);
  753. dbus_free_string_array (environment);
  754. return FALSE;
  755. }
  756.  
  757. for (i = 0; environment[i] != NULL; i++)
  758. {
  759. if (!_dbus_string_append (&key, environment[i]))
  760. break;
  761.  
  762. if (_dbus_string_split_on_byte (&key, '=', &value))
  763. {
  764. char *hash_key, *hash_value;
  765.  
  766. if (!_dbus_string_steal_data (&key, &hash_key))
  767. break;
  768.  
  769. if (!_dbus_string_steal_data (&value, &hash_value))
  770. break;
  771.  
  772. if (!_dbus_hash_table_insert_string (activation->environment,
  773. hash_key, hash_value))
  774. break;
  775. }
  776. _dbus_string_set_length (&key, 0);
  777. _dbus_string_set_length (&value, 0);
  778. }
  779.  
  780. if (environment[i] != NULL)
  781. goto out;
  782.  
  783. retval = TRUE;
  784. out:
  785.  
  786. _dbus_string_free (&key);
  787. _dbus_string_free (&value);
  788. dbus_free_string_array (environment);
  789.  
  790. return retval;
  791. }
  792.  
  793. dbus_bool_t
  794. bus_activation_reload (BusActivation *activation,
  795. const DBusString *address,
  796. DBusList **directories,
  797. DBusError *error)
  798. {
  799. DBusList *link;
  800. char *dir;
  801.  
  802. if (activation->server_address != NULL)
  803. dbus_free (activation->server_address);
  804. if (!_dbus_string_copy_data (address, &activation->server_address))
  805. {
  806. BUS_SET_OOM (error);
  807. goto failed;
  808. }
  809.  
  810. if (activation->entries != NULL)
  811. _dbus_hash_table_unref (activation->entries);
  812. activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
  813. (DBusFreeFunction)bus_activation_entry_unref);
  814. if (activation->entries == NULL)
  815. {
  816. BUS_SET_OOM (error);
  817. goto failed;
  818. }
  819.  
  820. if (activation->directories != NULL)
  821. _dbus_hash_table_unref (activation->directories);
  822. activation->directories = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
  823. (DBusFreeFunction)bus_service_directory_unref);
  824.  
  825. if (activation->directories == NULL)
  826. {
  827. BUS_SET_OOM (error);
  828. goto failed;
  829. }
  830.  
  831. link = _dbus_list_get_first_link (directories);
  832. while (link != NULL)
  833. {
  834. BusServiceDirectory *s_dir;
  835.  
  836. dir = _dbus_strdup ((const char *) link->data);
  837. if (!dir)
  838. {
  839. BUS_SET_OOM (error);
  840. goto failed;
  841. }
  842.  
  843. s_dir = dbus_new0 (BusServiceDirectory, 1);
  844. if (!s_dir)
  845. {
  846. dbus_free (dir);
  847. BUS_SET_OOM (error);
  848. goto failed;
  849. }
  850.  
  851. s_dir->refcount = 1;
  852. s_dir->dir_c = dir;
  853.  
  854. s_dir->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
  855. (DBusFreeFunction)bus_activation_entry_unref);
  856.  
  857. if (!s_dir->entries)
  858. {
  859. bus_service_directory_unref (s_dir);
  860. BUS_SET_OOM (error);
  861. goto failed;
  862. }
  863.  
  864. if (!_dbus_hash_table_insert_string (activation->directories, s_dir->dir_c, s_dir))
  865. {
  866. bus_service_directory_unref (s_dir);
  867. BUS_SET_OOM (error);
  868. goto failed;
  869. }
  870.  
  871. /* only fail on OOM, it is ok if we can't read the directory */
  872. if (!update_directory (activation, s_dir, error))
  873. {
  874. if (dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
  875. goto failed;
  876. else
  877. dbus_error_free (error);
  878. }
  879.  
  880. link = _dbus_list_get_next_link (directories, link);
  881. }
  882.  
  883. return TRUE;
  884. failed:
  885. return FALSE;
  886. }
  887.  
  888. BusActivation*
  889. bus_activation_new (BusContext *context,
  890. const DBusString *address,
  891. DBusList **directories,
  892. DBusError *error)
  893. {
  894. BusActivation *activation;
  895. DBusList *link;
  896. char *dir;
  897.  
  898. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  899.  
  900. activation = dbus_new0 (BusActivation, 1);
  901. if (activation == NULL)
  902. {
  903. BUS_SET_OOM (error);
  904. return NULL;
  905. }
  906.  
  907. activation->refcount = 1;
  908. activation->context = context;
  909. activation->n_pending_activations = 0;
  910.  
  911. if (!bus_activation_reload (activation, address, directories, error))
  912. goto failed;
  913.  
  914. /* Initialize this hash table once, we don't want to lose pending
  915.   * activations on reload. */
  916. activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
  917. (DBusFreeFunction)bus_pending_activation_unref);
  918.  
  919. if (activation->pending_activations == NULL)
  920. {
  921. BUS_SET_OOM (error);
  922. goto failed;
  923. }
  924.  
  925. activation->environment = _dbus_hash_table_new (DBUS_HASH_STRING,
  926. (DBusFreeFunction) dbus_free,
  927. (DBusFreeFunction) dbus_free);
  928.  
  929. if (activation->environment == NULL)
  930. {
  931. BUS_SET_OOM (error);
  932. goto failed;
  933. }
  934.  
  935. if (!populate_environment (activation))
  936. {
  937. BUS_SET_OOM (error);
  938. goto failed;
  939. }
  940.  
  941. return activation;
  942.  
  943. failed:
  944. bus_activation_unref (activation);
  945. return NULL;
  946. }
  947.  
  948. BusActivation *
  949. bus_activation_ref (BusActivation *activation)
  950. {
  951. _dbus_assert (activation->refcount > 0);
  952.  
  953. activation->refcount += 1;
  954.  
  955. return activation;
  956. }
  957.  
  958. void
  959. bus_activation_unref (BusActivation *activation)
  960. {
  961. _dbus_assert (activation->refcount > 0);
  962.  
  963. activation->refcount -= 1;
  964.  
  965. if (activation->refcount > 0)
  966. return;
  967.  
  968. dbus_free (activation->server_address);
  969. if (activation->entries)
  970. _dbus_hash_table_unref (activation->entries);
  971. if (activation->pending_activations)
  972. _dbus_hash_table_unref (activation->pending_activations);
  973. if (activation->directories)
  974. _dbus_hash_table_unref (activation->directories);
  975. if (activation->environment)
  976. _dbus_hash_table_unref (activation->environment);
  977.  
  978. dbus_free (activation);
  979. }
  980.  
  981. static dbus_bool_t
  982. add_bus_environment (BusActivation *activation,
  983. DBusError *error)
  984. {
  985. const char *type;
  986.  
  987. if (!bus_activation_set_environment_variable (activation,
  988. "DBUS_STARTER_ADDRESS",
  989. activation->server_address,
  990. error))
  991. return FALSE;
  992.  
  993. type = bus_context_get_type (activation->context);
  994. if (type != NULL)
  995. {
  996. if (!bus_activation_set_environment_variable (activation,
  997. "DBUS_STARTER_BUS_TYPE", type,
  998. error))
  999. return FALSE;
  1000.  
  1001. if (strcmp (type, "session") == 0)
  1002. {
  1003. if (!bus_activation_set_environment_variable (activation,
  1004. "DBUS_SESSION_BUS_ADDRESS",
  1005. activation->server_address,
  1006. error))
  1007. return FALSE;
  1008. }
  1009. else if (strcmp (type, "system") == 0)
  1010. {
  1011. if (!bus_activation_set_environment_variable (activation,
  1012. "DBUS_SYSTEM_BUS_ADDRESS",
  1013. activation->server_address,
  1014. error))
  1015. return FALSE;
  1016. }
  1017. }
  1018.  
  1019. return TRUE;
  1020. }
  1021.  
  1022. typedef struct
  1023. {
  1024. BusPendingActivation *pending_activation;
  1025. DBusPreallocatedHash *hash_entry;
  1026. } RestorePendingData;
  1027.  
  1028. static void
  1029. restore_pending (void *data)
  1030. {
  1031. RestorePendingData *d = data;
  1032.  
  1033. _dbus_assert (d->pending_activation != NULL);
  1034. _dbus_assert (d->hash_entry != NULL);
  1035.  
  1036. _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n",
  1037. d->pending_activation->service_name,
  1038. d->pending_activation->timeout_added);
  1039.  
  1040. _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations,
  1041. d->hash_entry,
  1042. d->pending_activation->service_name, d->pending_activation);
  1043.  
  1044. bus_pending_activation_ref (d->pending_activation);
  1045.  
  1046. d->hash_entry = NULL;
  1047. }
  1048.  
  1049. static void
  1050. free_pending_restore_data (void *data)
  1051. {
  1052. RestorePendingData *d = data;
  1053.  
  1054. if (d->hash_entry)
  1055. _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations,
  1056. d->hash_entry);
  1057.  
  1058. bus_pending_activation_unref (d->pending_activation);
  1059.  
  1060. dbus_free (d);
  1061. }
  1062.  
  1063. static dbus_bool_t
  1064. add_restore_pending_to_transaction (BusTransaction *transaction,
  1065. BusPendingActivation *pending_activation)
  1066. {
  1067. RestorePendingData *d;
  1068.  
  1069. d = dbus_new (RestorePendingData, 1);
  1070. if (d == NULL)
  1071. return FALSE;
  1072.  
  1073. d->pending_activation = pending_activation;
  1074. d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations);
  1075.  
  1076. bus_pending_activation_ref (d->pending_activation);
  1077.  
  1078. if (d->hash_entry == NULL ||
  1079. !bus_transaction_add_cancel_hook (transaction, restore_pending, d,
  1080. free_pending_restore_data))
  1081. {
  1082. free_pending_restore_data (d);
  1083. return FALSE;
  1084. }
  1085.  
  1086. _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n");
  1087.  
  1088. return TRUE;
  1089. }
  1090.  
  1091. dbus_bool_t
  1092. bus_activation_service_created (BusActivation *activation,
  1093. const char *service_name,
  1094. BusTransaction *transaction,
  1095. DBusError *error)
  1096. {
  1097. BusPendingActivation *pending_activation;
  1098. DBusMessage *message;
  1099. DBusList *link;
  1100.  
  1101. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  1102.  
  1103. /* Check if it's a pending activation */
  1104. pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
  1105.  
  1106. if (!pending_activation)
  1107. return TRUE;
  1108.  
  1109. link = _dbus_list_get_first_link (&pending_activation->entries);
  1110. while (link != NULL)
  1111. {
  1112. BusPendingActivationEntry *entry = link->data;
  1113. DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
  1114.  
  1115. if (dbus_connection_get_is_connected (entry->connection))
  1116. {
  1117. /* Only send activation replies to regular activation requests. */
  1118. if (!entry->auto_activation)
  1119. {
  1120. dbus_uint32_t result;
  1121.  
  1122. message = dbus_message_new_method_return (entry->activation_message);
  1123. if (!message)
  1124. {
  1125. BUS_SET_OOM (error);
  1126. goto error;
  1127. }
  1128.  
  1129. result = DBUS_START_REPLY_SUCCESS;
  1130.  
  1131. if (!dbus_message_append_args (message,
  1132. DBUS_TYPE_UINT32, &result,
  1133. DBUS_TYPE_INVALID))
  1134. {
  1135. dbus_message_unref (message);
  1136. BUS_SET_OOM (error);
  1137. goto error;
  1138. }
  1139.  
  1140. if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
  1141. {
  1142. dbus_message_unref (message);
  1143. BUS_SET_OOM (error);
  1144. goto error;
  1145. }
  1146.  
  1147. dbus_message_unref (message);
  1148. }
  1149. }
  1150.  
  1151. link = next;
  1152. }
  1153.  
  1154. return TRUE;
  1155.  
  1156. error:
  1157. return FALSE;
  1158. }
  1159.  
  1160. dbus_bool_t
  1161. bus_activation_send_pending_auto_activation_messages (BusActivation *activation,
  1162. BusService *service,
  1163. BusTransaction *transaction,
  1164. DBusError *error)
  1165. {
  1166. BusPendingActivation *pending_activation;
  1167. DBusList *link;
  1168.  
  1169. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  1170.  
  1171. /* Check if it's a pending activation */
  1172. pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations,
  1173. bus_service_get_name (service));
  1174.  
  1175. if (!pending_activation)
  1176. return TRUE;
  1177.  
  1178. link = _dbus_list_get_first_link (&pending_activation->entries);
  1179. while (link != NULL)
  1180. {
  1181. BusPendingActivationEntry *entry = link->data;
  1182. DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
  1183.  
  1184. if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection))
  1185. {
  1186. DBusConnection *addressed_recipient;
  1187.  
  1188. addressed_recipient = bus_service_get_primary_owners_connection (service);
  1189.  
  1190. /* Resume dispatching where we left off in bus_dispatch() */
  1191. if (!bus_dispatch_matches (transaction,
  1192. entry->connection,
  1193. addressed_recipient,
  1194. entry->activation_message, error))
  1195. goto error;
  1196. }
  1197.  
  1198. link = next;
  1199. }
  1200.  
  1201. if (!add_restore_pending_to_transaction (transaction, pending_activation))
  1202. {
  1203. _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n");
  1204. BUS_SET_OOM (error);
  1205. goto error;
  1206. }
  1207.  
  1208. _dbus_hash_table_remove_string (activation->pending_activations, bus_service_get_name (service));
  1209.  
  1210. return TRUE;
  1211.  
  1212. error:
  1213. return FALSE;
  1214. }
  1215.  
  1216. /**
  1217.  * FIXME @todo the error messages here would ideally be preallocated
  1218.  * so we don't need to allocate memory to send them.
  1219.  * Using the usual tactic, prealloc an OOM message, then
  1220.  * if we can't alloc the real error send the OOM error instead.
  1221.  */
  1222. static dbus_bool_t
  1223. try_send_activation_failure (BusPendingActivation *pending_activation,
  1224. const DBusError *how)
  1225. {
  1226. BusActivation *activation;
  1227. DBusList *link;
  1228. BusTransaction *transaction;
  1229.  
  1230. activation = pending_activation->activation;
  1231.  
  1232. transaction = bus_transaction_new (activation->context);
  1233. if (transaction == NULL)
  1234. return FALSE;
  1235.  
  1236. link = _dbus_list_get_first_link (&pending_activation->entries);
  1237. while (link != NULL)
  1238. {
  1239. BusPendingActivationEntry *entry = link->data;
  1240. DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
  1241.  
  1242. if (dbus_connection_get_is_connected (entry->connection))
  1243. {
  1244. if (!bus_transaction_send_error_reply (transaction,
  1245. entry->connection,
  1246. how,
  1247. entry->activation_message))
  1248. goto error;
  1249. }
  1250.  
  1251. link = next;
  1252. }
  1253.  
  1254. bus_transaction_execute_and_free (transaction);
  1255.  
  1256. return TRUE;
  1257.  
  1258. error:
  1259. if (transaction)
  1260. bus_transaction_cancel_and_free (transaction);
  1261. return FALSE;
  1262. }
  1263.  
  1264. /**
  1265.  * Free the pending activation and send an error message to all the
  1266.  * connections that were waiting for it.
  1267.  */
  1268. static void
  1269. pending_activation_failed (BusPendingActivation *pending_activation,
  1270. const DBusError *how)
  1271. {
  1272. /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */
  1273. while (!try_send_activation_failure (pending_activation, how))
  1274. _dbus_wait_for_memory ();
  1275.  
  1276. /* Destroy this pending activation */
  1277. _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
  1278. pending_activation->service_name);
  1279. }
  1280.  
  1281. /**
  1282.  * Depending on the exit code of the helper, set the error accordingly
  1283.  */
  1284. static void
  1285. handle_servicehelper_exit_error (int exit_code,
  1286. DBusError *error)
  1287. {
  1288. switch (exit_code)
  1289. {
  1290. case BUS_SPAWN_EXIT_CODE_NO_MEMORY:
  1291. dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
  1292. "Launcher could not run (out of memory)");
  1293. break;
  1294. case BUS_SPAWN_EXIT_CODE_SETUP_FAILED:
  1295. dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED,
  1296. "Failed to setup environment correctly");
  1297. break;
  1298. case BUS_SPAWN_EXIT_CODE_NAME_INVALID:
  1299. dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_INVALID,
  1300. "Bus name is not valid or missing");
  1301. break;
  1302. case BUS_SPAWN_EXIT_CODE_SERVICE_NOT_FOUND:
  1303. dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND,
  1304. "Bus name not found in system service directory");
  1305. break;
  1306. case BUS_SPAWN_EXIT_CODE_PERMISSIONS_INVALID:
  1307. dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID,
  1308. "The permission of the setuid helper is not correct");
  1309. break;
  1310. case BUS_SPAWN_EXIT_CODE_FILE_INVALID:
  1311. dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID,
  1312. "The service file is incorrect or does not have all required attributes");
  1313. break;
  1314. case BUS_SPAWN_EXIT_CODE_EXEC_FAILED:
  1315. dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
  1316. "Cannot launch daemon, file not found or permissions invalid");
  1317. break;
  1318. case BUS_SPAWN_EXIT_CODE_INVALID_ARGS:
  1319. dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
  1320. "Invalid arguments to command line");
  1321. break;
  1322. case BUS_SPAWN_EXIT_CODE_CHILD_SIGNALED:
  1323. dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
  1324. "Launched child was signaled, it probably crashed");
  1325. break;
  1326. default:
  1327. dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
  1328. "Launch helper exited with unknown return code %i", exit_code);
  1329. break;
  1330. }
  1331. }
  1332.  
  1333. static dbus_bool_t
  1334. babysitter_watch_callback (DBusWatch *watch,
  1335. unsigned int condition,
  1336. void *data)
  1337. {
  1338. BusPendingActivation *pending_activation = data;
  1339. dbus_bool_t retval;
  1340. DBusBabysitter *babysitter;
  1341. dbus_bool_t uses_servicehelper;
  1342.  
  1343. babysitter = pending_activation->babysitter;
  1344.  
  1345. _dbus_babysitter_ref (babysitter);
  1346.  
  1347. retval = dbus_watch_handle (watch, condition);
  1348.  
  1349. /* There are two major cases here; are we the system bus or the session? Here this
  1350.   * is distinguished by whether or not we use a setuid helper launcher. With the launch helper,
  1351.   * some process exit codes are meaningful, processed by handle_servicehelper_exit_error.
  1352.   *
  1353.   * In both cases though, just ignore when a process exits with status 0; it's possible for
  1354.   * a program to (misguidedly) "daemonize", and that appears to us as an exit. This closes a race
  1355.   * condition between this code and the child process claiming the bus name.
  1356.   */
  1357. uses_servicehelper = bus_context_get_servicehelper (pending_activation->activation->context) != NULL;
  1358.  
  1359. /* FIXME this is broken in the same way that
  1360.   * connection watches used to be; there should be
  1361.   * a separate callback for status change, instead
  1362.   * of doing "if we handled a watch status might
  1363.   * have changed"
  1364.   *
  1365.   * Fixing this lets us move dbus_watch_handle
  1366.   * calls into dbus-mainloop.c
  1367.   */
  1368. if (_dbus_babysitter_get_child_exited (babysitter))
  1369. {
  1370. DBusError error;
  1371. DBusHashIter iter;
  1372. dbus_bool_t activation_failed;
  1373. int exit_code = 0;
  1374.  
  1375. dbus_error_init (&error);
  1376.  
  1377. _dbus_babysitter_set_child_exit_error (babysitter, &error);
  1378.  
  1379. /* Explicitly check for SPAWN_CHILD_EXITED to avoid overwriting an
  1380.   * exec error */
  1381. if (dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)
  1382. && _dbus_babysitter_get_child_exit_status (babysitter, &exit_code))
  1383. {
  1384. activation_failed = exit_code != 0;
  1385.  
  1386. dbus_error_free(&error);
  1387.  
  1388. if (activation_failed)
  1389. {
  1390. if (uses_servicehelper)
  1391. handle_servicehelper_exit_error (exit_code, &error);
  1392. else
  1393. _dbus_babysitter_set_child_exit_error (babysitter, &error);
  1394. }
  1395. }
  1396. else
  1397. {
  1398. activation_failed = TRUE;
  1399. }
  1400.  
  1401. if (activation_failed)
  1402. {
  1403. /* Destroy all pending activations with the same exec */
  1404. _dbus_hash_iter_init (pending_activation->activation->pending_activations,
  1405. &iter);
  1406. while (_dbus_hash_iter_next (&iter))
  1407. {
  1408. BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
  1409.  
  1410. if (p != pending_activation && strcmp (p->exec, pending_activation->exec) == 0)
  1411. pending_activation_failed (p, &error);
  1412. }
  1413.  
  1414. /* Destroys the pending activation */
  1415. pending_activation_failed (pending_activation, &error);
  1416.  
  1417. dbus_error_free (&error);
  1418. }
  1419. }
  1420.  
  1421. _dbus_babysitter_unref (babysitter);
  1422.  
  1423. return retval;
  1424. }
  1425.  
  1426. static dbus_bool_t
  1427. add_babysitter_watch (DBusWatch *watch,
  1428. void *data)
  1429. {
  1430. BusPendingActivation *pending_activation = data;
  1431.  
  1432. return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context),
  1433. watch, babysitter_watch_callback, pending_activation,
  1434. NULL);
  1435. }
  1436.  
  1437. static void
  1438. remove_babysitter_watch (DBusWatch *watch,
  1439. void *data)
  1440. {
  1441. BusPendingActivation *pending_activation = data;
  1442.  
  1443. _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context),
  1444. watch, babysitter_watch_callback, pending_activation);
  1445. }
  1446.  
  1447. static dbus_bool_t
  1448. pending_activation_timed_out (void *data)
  1449. {
  1450. BusPendingActivation *pending_activation = data;
  1451. DBusError error;
  1452.  
  1453. /* Kill the spawned process, since it sucks
  1454.   * (not sure this is what we want to do, but
  1455.   * may as well try it for now)
  1456.   */
  1457. if (pending_activation->babysitter)
  1458. _dbus_babysitter_kill_child (pending_activation->babysitter);
  1459.  
  1460. dbus_error_init (&error);
  1461.  
  1462. dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
  1463. "Activation of %s timed out",
  1464. pending_activation->service_name);
  1465.  
  1466. pending_activation_failed (pending_activation, &error);
  1467.  
  1468. dbus_error_free (&error);
  1469.  
  1470. return TRUE;
  1471. }
  1472.  
  1473. static void
  1474. cancel_pending (void *data)
  1475. {
  1476. BusPendingActivation *pending_activation = data;
  1477.  
  1478. _dbus_verbose ("Canceling pending activation of %s\n",
  1479. pending_activation->service_name);
  1480.  
  1481. if (pending_activation->babysitter)
  1482. _dbus_babysitter_kill_child (pending_activation->babysitter);
  1483.  
  1484. _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
  1485. pending_activation->service_name);
  1486. }
  1487.  
  1488. static void
  1489. free_pending_cancel_data (void *data)
  1490. {
  1491. BusPendingActivation *pending_activation = data;
  1492.  
  1493. bus_pending_activation_unref (pending_activation);
  1494. }
  1495.  
  1496. static dbus_bool_t
  1497. add_cancel_pending_to_transaction (BusTransaction *transaction,
  1498. BusPendingActivation *pending_activation)
  1499. {
  1500. if (!bus_transaction_add_cancel_hook (transaction, cancel_pending,
  1501. pending_activation,
  1502. free_pending_cancel_data))
  1503. return FALSE;
  1504.  
  1505. bus_pending_activation_ref (pending_activation);
  1506.  
  1507. _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n");
  1508.  
  1509. return TRUE;
  1510. }
  1511.  
  1512. static dbus_bool_t
  1513. update_service_cache (BusActivation *activation, DBusError *error)
  1514. {
  1515. DBusHashIter iter;
  1516.  
  1517. _dbus_hash_iter_init (activation->directories, &iter);
  1518. while (_dbus_hash_iter_next (&iter))
  1519. {
  1520. DBusError tmp_error;
  1521. BusServiceDirectory *s_dir;
  1522.  
  1523. s_dir = _dbus_hash_iter_get_value (&iter);
  1524.  
  1525. dbus_error_init (&tmp_error);
  1526. if (!update_directory (activation, s_dir, &tmp_error))
  1527. {
  1528. if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
  1529. {
  1530. dbus_move_error (&tmp_error, error);
  1531. return FALSE;
  1532. }
  1533.  
  1534. dbus_error_free (&tmp_error);
  1535. continue;
  1536. }
  1537. }
  1538.  
  1539. return TRUE;
  1540. }
  1541.  
  1542. static BusActivationEntry *
  1543. activation_find_entry (BusActivation *activation,
  1544. const char *service_name,
  1545. DBusError *error)
  1546. {
  1547. BusActivationEntry *entry;
  1548.  
  1549. entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
  1550. if (!entry)
  1551. {
  1552. if (!update_service_cache (activation, error))
  1553. return NULL;
  1554.  
  1555. entry = _dbus_hash_table_lookup_string (activation->entries,
  1556. service_name);
  1557. }
  1558. else
  1559. {
  1560. BusActivationEntry *updated_entry;
  1561.  
  1562. if (!check_service_file (activation, entry, &updated_entry, error))
  1563. return NULL;
  1564.  
  1565. entry = updated_entry;
  1566. }
  1567.  
  1568. if (!entry)
  1569. {
  1570. dbus_set_error (error, DBUS_ERROR_SERVICE_UNKNOWN,
  1571. "The name %s was not provided by any .service files",
  1572. service_name);
  1573. return NULL;
  1574. }
  1575.  
  1576. return entry;
  1577. }
  1578.  
  1579. static char **
  1580. bus_activation_get_environment (BusActivation *activation)
  1581. {
  1582. char **environment;
  1583. int i, length;
  1584. DBusString entry;
  1585. DBusHashIter iter;
  1586.  
  1587. length = _dbus_hash_table_get_n_entries (activation->environment);
  1588.  
  1589. environment = dbus_new0 (char *, length + 1);
  1590.  
  1591. if (environment == NULL)
  1592. return NULL;
  1593.  
  1594. i = 0;
  1595. _dbus_hash_iter_init (activation->environment, &iter);
  1596.  
  1597. if (!_dbus_string_init (&entry))
  1598. {
  1599. dbus_free_string_array (environment);
  1600. return NULL;
  1601. }
  1602.  
  1603. while (_dbus_hash_iter_next (&iter))
  1604. {
  1605. const char *key, *value;
  1606.  
  1607. key = (const char *) _dbus_hash_iter_get_string_key (&iter);
  1608. value = (const char *) _dbus_hash_iter_get_value (&iter);
  1609.  
  1610. if (!_dbus_string_append_printf (&entry, "%s=%s", key, value))
  1611. break;
  1612.  
  1613. if (!_dbus_string_steal_data (&entry, environment + i))
  1614. break;
  1615. i++;
  1616. }
  1617.  
  1618. _dbus_string_free (&entry);
  1619.  
  1620. if (i != length)
  1621. {
  1622. dbus_free_string_array (environment);
  1623. environment = NULL;
  1624. }
  1625.  
  1626. return environment;
  1627. }
  1628.  
  1629. dbus_bool_t
  1630. bus_activation_set_environment_variable (BusActivation *activation,
  1631. const char *key,
  1632. const char *value,
  1633. DBusError *error)
  1634. {
  1635. char *hash_key;
  1636. char *hash_value;
  1637. dbus_bool_t retval;
  1638.  
  1639. retval = FALSE;
  1640. hash_key = NULL;
  1641. hash_value = NULL;
  1642. hash_key = _dbus_strdup (key);
  1643.  
  1644. if (hash_key == NULL)
  1645. goto out;
  1646.  
  1647. hash_value = _dbus_strdup (value);
  1648.  
  1649. if (hash_value == NULL)
  1650. goto out;
  1651.  
  1652. if (!_dbus_hash_table_insert_string (activation->environment,
  1653. hash_key, hash_value))
  1654. goto out;
  1655.  
  1656. retval = TRUE;
  1657. out:
  1658. if (retval == FALSE)
  1659. {
  1660. dbus_free (hash_key);
  1661. dbus_free (hash_value);
  1662. BUS_SET_OOM (error);
  1663. }
  1664.  
  1665. return retval;
  1666. }
  1667.  
  1668. dbus_bool_t
  1669. bus_activation_activate_service (BusActivation *activation,
  1670. DBusConnection *connection,
  1671. BusTransaction *transaction,
  1672. dbus_bool_t auto_activation,
  1673. DBusMessage *activation_message,
  1674. const char *service_name,
  1675. DBusError *error)
  1676. {
  1677. BusActivationEntry *entry;
  1678. BusPendingActivation *pending_activation;
  1679. BusPendingActivationEntry *pending_activation_entry;
  1680. DBusMessage *message;
  1681. DBusString service_str;
  1682. const char *servicehelper;
  1683. char **argv;
  1684. char **envp = NULL;
  1685. int argc;
  1686. dbus_bool_t retval;
  1687. DBusHashIter iter;
  1688. dbus_bool_t was_pending_activation;
  1689. DBusString command;
  1690.  
  1691. _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  1692.  
  1693. if (activation->n_pending_activations >=
  1694. bus_context_get_max_pending_activations (activation->context))
  1695. {
  1696. dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
  1697. "The maximum number of pending activations has been reached, activation of %s failed",
  1698. service_name);
  1699. return FALSE;
  1700. }
  1701.  
  1702. entry = activation_find_entry (activation, service_name, error);
  1703. if (!entry)
  1704. return FALSE;
  1705.  
  1706. /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not
  1707.   * call us if the service is already active.
  1708.   */
  1709. if (!auto_activation)
  1710. {
  1711. /* Check if the service is active */
  1712. _dbus_string_init_const (&service_str, service_name);
  1713. if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
  1714. {
  1715. dbus_uint32_t result;
  1716.  
  1717. _dbus_verbose ("Service \"%s\" is already active\n", service_name);
  1718.  
  1719. message = dbus_message_new_method_return (activation_message);
  1720.  
  1721. if (!message)
  1722. {
  1723. _dbus_verbose ("No memory to create reply to activate message\n");
  1724. BUS_SET_OOM (error);
  1725. return FALSE;
  1726. }
  1727.  
  1728. result = DBUS_START_REPLY_ALREADY_RUNNING;
  1729.  
  1730. if (!dbus_message_append_args (message,
  1731. DBUS_TYPE_UINT32, &result,
  1732. DBUS_TYPE_INVALID))
  1733. {
  1734. _dbus_verbose ("No memory to set args of reply to activate message\n");
  1735. BUS_SET_OOM (error);
  1736. dbus_message_unref (message);
  1737. return FALSE;
  1738. }
  1739.  
  1740. retval = bus_transaction_send_from_driver (transaction, connection, message);
  1741. dbus_message_unref (message);
  1742. if (!retval)
  1743. {
  1744. _dbus_verbose ("Failed to send reply\n");
  1745. BUS_SET_OOM (error);
  1746. }
  1747.  
  1748. return retval;
  1749. }
  1750. }
  1751.  
  1752. pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
  1753. if (!pending_activation_entry)
  1754. {
  1755. _dbus_verbose ("Failed to create pending activation entry\n");
  1756. BUS_SET_OOM (error);
  1757. return FALSE;
  1758. }
  1759.  
  1760. pending_activation_entry->auto_activation = auto_activation;
  1761.  
  1762. pending_activation_entry->activation_message = activation_message;
  1763. dbus_message_ref (activation_message);
  1764. pending_activation_entry->connection = connection;
  1765. dbus_connection_ref (connection);
  1766.  
  1767. /* Check if the service is being activated */
  1768. pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
  1769. was_pending_activation = (pending_activation != NULL);
  1770. if (was_pending_activation)
  1771. {
  1772. if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
  1773. {
  1774. _dbus_verbose ("Failed to append a new entry to pending activation\n");
  1775.  
  1776. BUS_SET_OOM (error);
  1777. bus_pending_activation_entry_free (pending_activation_entry);
  1778. return FALSE;
  1779. }
  1780.  
  1781. pending_activation->n_entries += 1;
  1782. pending_activation->activation->n_pending_activations += 1;
  1783. }
  1784. else
  1785. {
  1786. pending_activation = dbus_new0 (BusPendingActivation, 1);
  1787. if (!pending_activation)
  1788. {
  1789. _dbus_verbose ("Failed to create pending activation\n");
  1790.  
  1791. BUS_SET_OOM (error);
  1792. bus_pending_activation_entry_free (pending_activation_entry);
  1793. return FALSE;
  1794. }
  1795.  
  1796. pending_activation->activation = activation;
  1797. pending_activation->refcount = 1;
  1798.  
  1799. pending_activation->service_name = _dbus_strdup (service_name);
  1800. if (!pending_activation->service_name)
  1801. {
  1802. _dbus_verbose ("Failed to copy service name for pending activation\n");
  1803.  
  1804. BUS_SET_OOM (error);
  1805. bus_pending_activation_unref (pending_activation);
  1806. bus_pending_activation_entry_free (pending_activation_entry);
  1807. return FALSE;
  1808. }
  1809.  
  1810. pending_activation->exec = _dbus_strdup (entry->exec);
  1811. if (!pending_activation->exec)
  1812. {
  1813. _dbus_verbose ("Failed to copy service exec for pending activation\n");
  1814. BUS_SET_OOM (error);
  1815. bus_pending_activation_unref (pending_activation);
  1816. bus_pending_activation_entry_free (pending_activation_entry);
  1817. return FALSE;
  1818. }
  1819.  
  1820. if (entry->systemd_service)
  1821. {
  1822. pending_activation->systemd_service = _dbus_strdup (entry->systemd_service);
  1823. if (!pending_activation->systemd_service)
  1824. {
  1825. _dbus_verbose ("Failed to copy systemd service for pending activation\n");
  1826. BUS_SET_OOM (error);
  1827. bus_pending_activation_unref (pending_activation);
  1828. bus_pending_activation_entry_free (pending_activation_entry);
  1829. return FALSE;
  1830. }
  1831. }
  1832.  
  1833. pending_activation->timeout =
  1834. _dbus_timeout_new (bus_context_get_activation_timeout (activation->context),
  1835. pending_activation_timed_out,
  1836. pending_activation,
  1837. NULL);
  1838. if (!pending_activation->timeout)
  1839. {
  1840. _dbus_verbose ("Failed to create timeout for pending activation\n");
  1841.  
  1842. BUS_SET_OOM (error);
  1843. bus_pending_activation_unref (pending_activation);
  1844. bus_pending_activation_entry_free (pending_activation_entry);
  1845. return FALSE;
  1846. }
  1847.  
  1848. if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
  1849. pending_activation->timeout,
  1850. handle_timeout_callback,
  1851. pending_activation,
  1852. NULL))
  1853. {
  1854. _dbus_verbose ("Failed to add timeout for pending activation\n");
  1855.  
  1856. BUS_SET_OOM (error);
  1857. bus_pending_activation_unref (pending_activation);
  1858. bus_pending_activation_entry_free (pending_activation_entry);
  1859. return FALSE;
  1860. }
  1861.  
  1862. pending_activation->timeout_added = TRUE;
  1863.  
  1864. if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
  1865. {
  1866. _dbus_verbose ("Failed to add entry to just-created pending activation\n");
  1867.  
  1868. BUS_SET_OOM (error);
  1869. bus_pending_activation_unref (pending_activation);
  1870. bus_pending_activation_entry_free (pending_activation_entry);
  1871. return FALSE;
  1872. }
  1873.  
  1874. pending_activation->n_entries += 1;
  1875. pending_activation->activation->n_pending_activations += 1;
  1876.  
  1877. if (!_dbus_hash_table_insert_string (activation->pending_activations,
  1878. pending_activation->service_name,
  1879. pending_activation))
  1880. {
  1881. _dbus_verbose ("Failed to put pending activation in hash table\n");
  1882.  
  1883. BUS_SET_OOM (error);
  1884. bus_pending_activation_unref (pending_activation);
  1885. return FALSE;
  1886. }
  1887. }
  1888.  
  1889. if (!add_cancel_pending_to_transaction (transaction, pending_activation))
  1890. {
  1891. _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n");
  1892. BUS_SET_OOM (error);
  1893. _dbus_hash_table_remove_string (activation->pending_activations,
  1894. pending_activation->service_name);
  1895.  
  1896. return FALSE;
  1897. }
  1898.  
  1899. if (was_pending_activation)
  1900. return TRUE;
  1901.  
  1902. if (bus_context_get_systemd_activation (activation->context))
  1903. {
  1904. if (strcmp (service_name, "org.freedesktop.systemd1") == 0)
  1905. /* systemd itself is missing apparently. That can happen
  1906.   only during early startup. Let's just wait until systemd
  1907.   connects to us and do nothing. */
  1908. return TRUE;
  1909.  
  1910. if (entry->systemd_service)
  1911. {
  1912. BusTransaction *activation_transaction;
  1913. DBusString service_string;
  1914. BusService *service;
  1915. BusRegistry *registry;
  1916.  
  1917. /* OK, we have a systemd service configured for this entry,
  1918.   hence let's enqueue an activation request message. This
  1919.   is implemented as a directed signal, not a method call,
  1920.   for three reasons: 1) we don't expect a response on
  1921.   success, where we just expect a name appearing on the
  1922.   bus; 2) at this time the systemd service might not yet
  1923.   have connected, so we wouldn't know the message serial at
  1924.   this point to set up a pending call; 3) it is ugly if the
  1925.   bus suddenly becomes the caller of a remote method. */
  1926.  
  1927. message = dbus_message_new_signal (DBUS_PATH_DBUS,
  1928. "org.freedesktop.systemd1.Activator",
  1929. "ActivationRequest");
  1930. if (!message)
  1931. {
  1932. _dbus_verbose ("No memory to create activation message\n");
  1933. BUS_SET_OOM (error);
  1934. return FALSE;
  1935. }
  1936.  
  1937. if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
  1938. !dbus_message_set_destination (message, "org.freedesktop.systemd1") ||
  1939. !dbus_message_append_args (message,
  1940. DBUS_TYPE_STRING, &entry->systemd_service,
  1941. DBUS_TYPE_INVALID))
  1942. {
  1943. _dbus_verbose ("No memory to set args of activation message\n");
  1944. dbus_message_unref (message);
  1945. BUS_SET_OOM (error);
  1946. return FALSE;
  1947. }
  1948.  
  1949. /* Create our transaction */
  1950. activation_transaction = bus_transaction_new (activation->context);
  1951. if (activation_transaction == NULL)
  1952. {
  1953. _dbus_verbose ("No memory to create activation transaction\n");
  1954. dbus_message_unref (message);
  1955. BUS_SET_OOM (error);
  1956. return FALSE;
  1957. }
  1958.  
  1959. /* Check whether systemd is already connected */
  1960. registry = bus_connection_get_registry (connection);
  1961. _dbus_string_init_const (&service_string, "org.freedesktop.systemd1");
  1962. service = bus_registry_lookup (registry, &service_string);
  1963.  
  1964. if (service != NULL)
  1965. /* Wonderful, systemd is connected, let's just send the msg */
  1966. retval = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
  1967. message, error);
  1968. else
  1969. /* systemd is not around, let's "activate" it. */
  1970. retval = bus_activation_activate_service (activation, connection, activation_transaction, TRUE,
  1971. message, "org.freedesktop.systemd1", error);
  1972.  
  1973. dbus_message_unref (message);
  1974.  
  1975. if (!retval)
  1976. {
  1977. _DBUS_ASSERT_ERROR_IS_SET (error);
  1978. _dbus_verbose ("failed to send activation message: %s\n", error->name);
  1979. bus_transaction_cancel_and_free (activation_transaction);
  1980. return FALSE;
  1981. }
  1982.  
  1983. bus_transaction_execute_and_free (activation_transaction);
  1984. return TRUE;
  1985. }
  1986.  
  1987. /* OK, we have no configured systemd service, hence let's
  1988.   proceed with traditional activation. */
  1989. }
  1990.  
  1991. /* use command as system and session different */
  1992. if (!_dbus_string_init (&command))
  1993. {
  1994. BUS_SET_OOM (error);
  1995. return FALSE;
  1996. }
  1997.  
  1998. /* does the bus use a helper? */
  1999. servicehelper = bus_context_get_servicehelper (activation->context);
  2000. if (servicehelper != NULL)
  2001. {
  2002. if (entry->user == NULL)
  2003. {
  2004. _dbus_string_free (&command);
  2005. dbus_set_error (error, DBUS_ERROR_SPAWN_FILE_INVALID,
  2006. "Cannot do system-bus activation with no user\n");
  2007. return FALSE;
  2008. }
  2009.  
  2010. /* join the helper path and the service name */
  2011. if (!_dbus_string_append (&command, servicehelper))
  2012. {
  2013. _dbus_string_free (&command);
  2014. BUS_SET_OOM (error);
  2015. return FALSE;
  2016. }
  2017. if (!_dbus_string_append (&command, " "))
  2018. {
  2019. _dbus_string_free (&command);
  2020. BUS_SET_OOM (error);
  2021. return FALSE;
  2022. }
  2023. if (!_dbus_string_append (&command, service_name))
  2024. {
  2025. _dbus_string_free (&command);
  2026. BUS_SET_OOM (error);
  2027. return FALSE;
  2028. }
  2029. }
  2030. else
  2031. {
  2032. /* the bus does not use a helper, so we can append arguments with the exec line */
  2033. if (!_dbus_string_append (&command, entry->exec))
  2034. {
  2035. _dbus_string_free (&command);
  2036. BUS_SET_OOM (error);
  2037. return FALSE;
  2038. }
  2039. }
  2040.  
  2041. /* convert command into arguments */
  2042. if (!_dbus_shell_parse_argv (_dbus_string_get_const_data (&command), &argc, &argv, error))
  2043. {
  2044. _dbus_verbose ("Failed to parse command line: %s\n", entry->exec);
  2045. _DBUS_ASSERT_ERROR_IS_SET (error);
  2046.  
  2047. _dbus_hash_table_remove_string (activation->pending_activations,
  2048. pending_activation->service_name);
  2049.  
  2050. _dbus_string_free (&command);
  2051. return FALSE;
  2052. }
  2053. _dbus_string_free (&command);
  2054.  
  2055. if (!add_bus_environment (activation, error))
  2056. {
  2057. _DBUS_ASSERT_ERROR_IS_SET (error);
  2058. dbus_free_string_array (argv);
  2059. return FALSE;
  2060. }
  2061.  
  2062. envp = bus_activation_get_environment (activation);
  2063.  
  2064. if (envp == NULL)
  2065. {
  2066. BUS_SET_OOM (error);
  2067. dbus_free_string_array (argv);
  2068. return FALSE;
  2069. }
  2070.  
  2071. _dbus_verbose ("Spawning %s ...\n", argv[0]);
  2072. if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
  2073. envp,
  2074. NULL, activation,
  2075. error))
  2076. {
  2077. _dbus_verbose ("Failed to spawn child\n");
  2078. _DBUS_ASSERT_ERROR_IS_SET (error);
  2079. dbus_free_string_array (argv);
  2080. dbus_free_string_array (envp);
  2081.  
  2082. return FALSE;
  2083. }
  2084.  
  2085. dbus_free_string_array (argv);
  2086. envp = NULL;
  2087.  
  2088. _dbus_assert (pending_activation->babysitter != NULL);
  2089.  
  2090. if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
  2091. add_babysitter_watch,
  2092. remove_babysitter_watch,
  2093. NULL,
  2094. pending_activation,
  2095. NULL))
  2096. {
  2097. BUS_SET_OOM (error);
  2098. _dbus_verbose ("Failed to set babysitter watch functions\n");
  2099. return FALSE;
  2100. }
  2101.  
  2102. return TRUE;
  2103. }
  2104.  
  2105. dbus_bool_t
  2106. bus_activation_list_services (BusActivation *activation,
  2107. char ***listp,
  2108. int *array_len)
  2109. {
  2110. int i, j, len;
  2111. char **retval;
  2112. DBusHashIter iter;
  2113.  
  2114. len = _dbus_hash_table_get_n_entries (activation->entries);
  2115. retval = dbus_new (char *, len + 1);
  2116.  
  2117. if (retval == NULL)
  2118. return FALSE;
  2119.  
  2120. _dbus_hash_iter_init (activation->entries, &iter);
  2121. i = 0;
  2122. while (_dbus_hash_iter_next (&iter))
  2123. {
  2124. BusActivationEntry *entry = _dbus_hash_iter_get_value (&iter);
  2125.  
  2126. retval[i] = _dbus_strdup (entry->name);
  2127. if (retval[i] == NULL)
  2128. goto error;
  2129.  
  2130. i++;
  2131. }
  2132.  
  2133. retval[i] = NULL;
  2134.  
  2135. if (array_len)
  2136. *array_len = len;
  2137.  
  2138. *listp = retval;
  2139. return TRUE;
  2140.  
  2141. error:
  2142. for (j = 0; j < i; j++)
  2143. dbus_free (retval[i]);
  2144. dbus_free (retval);
  2145.  
  2146. return FALSE;
  2147. }
  2148.  
  2149. dbus_bool_t
  2150. dbus_activation_systemd_failure (BusActivation *activation,
  2151. DBusMessage *message)
  2152. {
  2153. DBusError error;
  2154. const char *code, *str, *unit = NULL;
  2155.  
  2156. dbus_error_init(&error);
  2157.  
  2158. /* This is called whenever the systemd activator sent us a
  2159.   response. We'll invalidate all pending activations that match the
  2160.   unit name. */
  2161.  
  2162. if (dbus_message_get_args (message, &error,
  2163. DBUS_TYPE_STRING, &unit,
  2164. DBUS_TYPE_STRING, &code,
  2165. DBUS_TYPE_STRING, &str,
  2166. DBUS_TYPE_INVALID))
  2167. dbus_set_error(&error, code, str);
  2168.  
  2169. if (unit)
  2170. {
  2171. DBusHashIter iter;
  2172.  
  2173. _dbus_hash_iter_init (activation->pending_activations,
  2174. &iter);
  2175.  
  2176. while (_dbus_hash_iter_next (&iter))
  2177. {
  2178. BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
  2179.  
  2180. if (p->systemd_service && strcmp (p->systemd_service, unit) == 0)
  2181. pending_activation_failed(p, &error);
  2182. }
  2183. }
  2184.  
  2185. dbus_error_free(&error);
  2186.  
  2187. return TRUE;
  2188. }
  2189.  
  2190. #ifdef DBUS_BUILD_TESTS
  2191.  
  2192. #include <stdio.h>
  2193.  
  2194. #define SERVICE_NAME_1 "MyService1"
  2195. #define SERVICE_NAME_2 "MyService2"
  2196. #define SERVICE_NAME_3 "MyService3"
  2197.  
  2198. #define SERVICE_FILE_1 "service-1.service"
  2199. #define SERVICE_FILE_2 "service-2.service"
  2200. #define SERVICE_FILE_3 "service-3.service"
  2201.  
  2202. static dbus_bool_t
  2203. test_create_service_file (DBusString *dir,
  2204. const char *filename,
  2205. const char *name,
  2206. const char *exec)
  2207. {
  2208. DBusString file_name, full_path;
  2209. FILE *file;
  2210. dbus_bool_t ret_val;
  2211.  
  2212. ret_val = TRUE;
  2213. _dbus_string_init_const (&file_name, filename);
  2214.  
  2215. if (!_dbus_string_init (&full_path))
  2216. return FALSE;
  2217.  
  2218. if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
  2219. !_dbus_concat_dir_and_file (&full_path, &file_name))
  2220. {
  2221. ret_val = FALSE;
  2222. goto out;
  2223. }
  2224.  
  2225. file = fopen (_dbus_string_get_const_data (&full_path), "w");
  2226. if (!file)
  2227. {
  2228. ret_val = FALSE;
  2229. goto out;
  2230. }
  2231.  
  2232. fprintf (file, "[D-BUS Service]\nName=%s\nExec=%s\n", name, exec);
  2233. fclose (file);
  2234.  
  2235. out:
  2236. _dbus_string_free (&full_path);
  2237. return ret_val;
  2238. }
  2239.  
  2240. static dbus_bool_t
  2241. test_remove_service_file (DBusString *dir, const char *filename)
  2242. {
  2243. DBusString file_name, full_path;
  2244. dbus_bool_t ret_val;
  2245.  
  2246. ret_val = TRUE;
  2247.  
  2248. _dbus_string_init_const (&file_name, filename);
  2249.  
  2250. if (!_dbus_string_init (&full_path))
  2251. return FALSE;
  2252.  
  2253. if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
  2254. !_dbus_concat_dir_and_file (&full_path, &file_name))
  2255. {
  2256. ret_val = FALSE;
  2257. goto out;
  2258. }
  2259.  
  2260. if (!_dbus_delete_file (&full_path, NULL))
  2261. {
  2262. ret_val = FALSE;
  2263. goto out;
  2264. }
  2265.  
  2266. out:
  2267. _dbus_string_free (&full_path);
  2268. return ret_val;
  2269. }
  2270.  
  2271. static dbus_bool_t
  2272. test_remove_directory (DBusString *dir)
  2273. {
  2274. DBusDirIter *iter;
  2275. DBusString filename, full_path;
  2276. dbus_bool_t ret_val;
  2277.  
  2278. ret_val = TRUE;
  2279.  
  2280. if (!_dbus_string_init (&filename))
  2281. return FALSE;
  2282.  
  2283. if (!_dbus_string_init (&full_path))
  2284. {
  2285. _dbus_string_free (&filename);
  2286. return FALSE;
  2287. }
  2288.  
  2289. iter = _dbus_directory_open (dir, NULL);
  2290. if (iter == NULL)
  2291. {
  2292. ret_val = FALSE;
  2293. goto out;
  2294. }
  2295.  
  2296. while (_dbus_directory_get_next_file (iter, &filename, NULL))
  2297. {
  2298. if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename)))
  2299. {
  2300. ret_val = FALSE;
  2301. goto out;
  2302. }
  2303. }
  2304. _dbus_directory_close (iter);
  2305.  
  2306. if (!_dbus_delete_directory (dir, NULL))
  2307. {
  2308. ret_val = FALSE;
  2309. goto out;
  2310. }
  2311.  
  2312. out:
  2313. _dbus_string_free (&filename);
  2314. _dbus_string_free (&full_path);
  2315.  
  2316. return ret_val;
  2317. }
  2318.  
  2319. static dbus_bool_t
  2320. init_service_reload_test (DBusString *dir)
  2321. {
  2322. DBusStat stat_buf;
  2323.  
  2324. if (!_dbus_stat (dir, &stat_buf, NULL))
  2325. {
  2326. if (!_dbus_create_directory (dir, NULL))
  2327. return FALSE;
  2328. }
  2329. else
  2330. {
  2331. if (!test_remove_directory (dir))
  2332. return FALSE;
  2333.  
  2334. if (!_dbus_create_directory (dir, NULL))
  2335. return FALSE;
  2336. }
  2337.  
  2338. /* Create one initial file */
  2339. if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1"))
  2340. return FALSE;
  2341.  
  2342. return TRUE;
  2343. }
  2344.  
  2345. static dbus_bool_t
  2346. cleanup_service_reload_test (DBusString *dir)
  2347. {
  2348. if (!test_remove_directory (dir))
  2349. return FALSE;
  2350.  
  2351. return TRUE;
  2352. }
  2353.  
  2354. typedef struct
  2355. {
  2356. BusActivation *activation;
  2357. const char *service_name;
  2358. dbus_bool_t expecting_find;
  2359. } CheckData;
  2360.  
  2361. static dbus_bool_t
  2362. check_func (void *data)
  2363. {
  2364. CheckData *d;
  2365. BusActivationEntry *entry;
  2366. DBusError error;
  2367. dbus_bool_t ret_val;
  2368.  
  2369. ret_val = TRUE;
  2370. d = data;
  2371.  
  2372. dbus_error_init (&error);
  2373.  
  2374. entry = activation_find_entry (d->activation, d->service_name, &error);
  2375. if (entry == NULL)
  2376. {
  2377. if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
  2378. {
  2379. ret_val = TRUE;
  2380. }
  2381. else
  2382. {
  2383. if (d->expecting_find)
  2384. ret_val = FALSE;
  2385. }
  2386.  
  2387. dbus_error_free (&error);
  2388. }
  2389. else
  2390. {
  2391. if (!d->expecting_find)
  2392. ret_val = FALSE;
  2393. }
  2394.  
  2395. return ret_val;
  2396. }
  2397.  
  2398. static dbus_bool_t
  2399. do_test (const char *description, dbus_bool_t oom_test, CheckData *data)
  2400. {
  2401. dbus_bool_t err;
  2402.  
  2403. if (oom_test)
  2404. err = !_dbus_test_oom_handling (description, check_func, data);
  2405. else
  2406. err = !check_func (data);
  2407.  
  2408. if (err)
  2409. _dbus_assert_not_reached ("Test failed");
  2410.  
  2411. return TRUE;
  2412. }
  2413.  
  2414. static dbus_bool_t
  2415. do_service_reload_test (DBusString *dir, dbus_bool_t oom_test)
  2416. {
  2417. BusActivation *activation;
  2418. DBusString address;
  2419. DBusList *directories;
  2420. CheckData d;
  2421.  
  2422. directories = NULL;
  2423. _dbus_string_init_const (&address, "");
  2424.  
  2425. if (!_dbus_list_append (&directories, _dbus_string_get_data (dir)))
  2426. return FALSE;
  2427.  
  2428. activation = bus_activation_new (NULL, &address, &directories, NULL);
  2429. if (!activation)
  2430. return FALSE;
  2431.  
  2432. d.activation = activation;
  2433.  
  2434. /* Check for existing service file */
  2435. d.expecting_find = TRUE;
  2436. d.service_name = SERVICE_NAME_1;
  2437.  
  2438. if (!do_test ("Existing service file", oom_test, &d))
  2439. return FALSE;
  2440.  
  2441. /* Check for non-existing service file */
  2442. d.expecting_find = FALSE;
  2443. d.service_name = SERVICE_NAME_3;
  2444.  
  2445. if (!do_test ("Nonexisting service file", oom_test, &d))
  2446. return FALSE;
  2447.  
  2448. /* Check for added service file */
  2449. if (!test_create_service_file (dir, SERVICE_FILE_2, SERVICE_NAME_2, "exec-2"))
  2450. return FALSE;
  2451.  
  2452. d.expecting_find = TRUE;
  2453. d.service_name = SERVICE_NAME_2;
  2454.  
  2455. if (!do_test ("Added service file", oom_test, &d))
  2456. return FALSE;
  2457.  
  2458. /* Check for removed service file */
  2459. if (!test_remove_service_file (dir, SERVICE_FILE_2))
  2460. return FALSE;
  2461.  
  2462. d.expecting_find = FALSE;
  2463. d.service_name = SERVICE_FILE_2;
  2464.  
  2465. if (!do_test ("Removed service file", oom_test, &d))
  2466. return FALSE;
  2467.  
  2468. /* Check for updated service file */
  2469.  
  2470. _dbus_sleep_milliseconds (1000); /* Sleep a second to make sure the mtime is updated */
  2471.  
  2472. if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_3, "exec-3"))
  2473. return FALSE;
  2474.  
  2475. d.expecting_find = TRUE;
  2476. d.service_name = SERVICE_NAME_3;
  2477.  
  2478. if (!do_test ("Updated service file, part 1", oom_test, &d))
  2479. return FALSE;
  2480.  
  2481. d.expecting_find = FALSE;
  2482. d.service_name = SERVICE_NAME_1;
  2483.  
  2484. if (!do_test ("Updated service file, part 2", oom_test, &d))
  2485. return FALSE;
  2486.  
  2487. bus_activation_unref (activation);
  2488. _dbus_list_clear (&directories);
  2489.  
  2490. return TRUE;
  2491. }
  2492.  
  2493. dbus_bool_t
  2494. bus_activation_service_reload_test (const DBusString *test_data_dir)
  2495. {
  2496. DBusString directory;
  2497.  
  2498. if (!_dbus_string_init (&directory))
  2499. return FALSE;
  2500.  
  2501. if (!_dbus_string_append (&directory, _dbus_get_tmpdir()))
  2502. return FALSE;
  2503.  
  2504. if (!_dbus_string_append (&directory, "/dbus-reload-test-") ||
  2505. !_dbus_generate_random_ascii (&directory, 6))
  2506. {
  2507. return FALSE;
  2508. }
  2509.  
  2510. /* Do normal tests */
  2511. if (!init_service_reload_test (&directory))
  2512. _dbus_assert_not_reached ("could not initiate service reload test");
  2513.  
  2514. if (!do_service_reload_test (&directory, FALSE))
  2515. ; /* Do nothing? */
  2516.  
  2517. /* Do OOM tests */
  2518. if (!init_service_reload_test (&directory))
  2519. _dbus_assert_not_reached ("could not initiate service reload test");
  2520.  
  2521. if (!do_service_reload_test (&directory, TRUE))
  2522. ; /* Do nothing? */
  2523.  
  2524. /* Cleanup test directory */
  2525. if (!cleanup_service_reload_test (&directory))
  2526. return FALSE;
  2527.  
  2528. _dbus_string_free (&directory);
  2529.  
  2530. return TRUE;
  2531. }
  2532.  
  2533. #endif /* DBUS_BUILD_TESTS */
  2534.