PageRenderTime 60ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/dbus/bus/activation.c

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