LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-track.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 6 161 3.7 %
Date: 2015-07-29 18:47:03 Functions: 2 18 11.1 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include "sd-bus.h"
      23             : #include "bus-util.h"
      24             : #include "bus-internal.h"
      25             : #include "bus-track.h"
      26             : 
      27             : struct sd_bus_track {
      28             :         unsigned n_ref;
      29             :         sd_bus *bus;
      30             :         sd_bus_track_handler_t handler;
      31             :         void *userdata;
      32             :         Hashmap *names;
      33             :         LIST_FIELDS(sd_bus_track, queue);
      34             :         Iterator iterator;
      35             :         bool in_queue;
      36             :         bool modified;
      37             : };
      38             : 
      39             : #define MATCH_PREFIX                                        \
      40             :         "type='signal',"                                    \
      41             :         "sender='org.freedesktop.DBus',"                    \
      42             :         "path='/org/freedesktop/DBus',"                     \
      43             :         "interface='org.freedesktop.DBus',"                 \
      44             :         "member='NameOwnerChanged',"                        \
      45             :         "arg0='"
      46             : 
      47             : #define MATCH_SUFFIX \
      48             :         "'"
      49             : 
      50             : #define MATCH_FOR_NAME(name)                                            \
      51             :         ({                                                              \
      52             :                 char *_x;                                               \
      53             :                 size_t _l = strlen(name);                               \
      54             :                 _x = alloca(strlen(MATCH_PREFIX)+_l+strlen(MATCH_SUFFIX)+1); \
      55             :                 strcpy(stpcpy(stpcpy(_x, MATCH_PREFIX), name), MATCH_SUFFIX); \
      56             :                 _x;                                                     \
      57             :         })
      58             : 
      59           0 : static void bus_track_add_to_queue(sd_bus_track *track) {
      60           0 :         assert(track);
      61             : 
      62           0 :         if (track->in_queue)
      63           0 :                 return;
      64             : 
      65           0 :         if (!track->handler)
      66           0 :                 return;
      67             : 
      68           0 :         LIST_PREPEND(queue, track->bus->track_queue, track);
      69           0 :         track->in_queue = true;
      70             : }
      71             : 
      72           0 : static void bus_track_remove_from_queue(sd_bus_track *track) {
      73           0 :         assert(track);
      74             : 
      75           0 :         if (!track->in_queue)
      76           0 :                 return;
      77             : 
      78           0 :         LIST_REMOVE(queue, track->bus->track_queue, track);
      79           0 :         track->in_queue = false;
      80             : }
      81             : 
      82           0 : _public_ int sd_bus_track_new(
      83             :                 sd_bus *bus,
      84             :                 sd_bus_track **track,
      85             :                 sd_bus_track_handler_t handler,
      86             :                 void *userdata) {
      87             : 
      88             :         sd_bus_track *t;
      89             : 
      90           0 :         assert_return(bus, -EINVAL);
      91           0 :         assert_return(track, -EINVAL);
      92             : 
      93           0 :         if (!bus->bus_client)
      94           0 :                 return -EINVAL;
      95             : 
      96           0 :         t = new0(sd_bus_track, 1);
      97           0 :         if (!t)
      98           0 :                 return -ENOMEM;
      99             : 
     100           0 :         t->n_ref = 1;
     101           0 :         t->handler = handler;
     102           0 :         t->userdata = userdata;
     103           0 :         t->bus = sd_bus_ref(bus);
     104             : 
     105           0 :         bus_track_add_to_queue(t);
     106             : 
     107           0 :         *track = t;
     108           0 :         return 0;
     109             : }
     110             : 
     111           0 : _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) {
     112           0 :         assert_return(track, NULL);
     113             : 
     114           0 :         assert(track->n_ref > 0);
     115             : 
     116           0 :         track->n_ref++;
     117             : 
     118           0 :         return track;
     119             : }
     120             : 
     121         170 : _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
     122             :         const char *n;
     123             : 
     124         170 :         if (!track)
     125         170 :                 return NULL;
     126             : 
     127           0 :         assert(track->n_ref > 0);
     128             : 
     129           0 :         if (track->n_ref > 1) {
     130           0 :                 track->n_ref --;
     131           0 :                 return NULL;
     132             :         }
     133             : 
     134           0 :         while ((n = hashmap_first_key(track->names)))
     135           0 :                 sd_bus_track_remove_name(track, n);
     136             : 
     137           0 :         bus_track_remove_from_queue(track);
     138           0 :         hashmap_free(track->names);
     139           0 :         sd_bus_unref(track->bus);
     140           0 :         free(track);
     141             : 
     142           0 :         return NULL;
     143             : }
     144             : 
     145           0 : static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     146           0 :         sd_bus_track *track = userdata;
     147             :         const char *name, *old, *new;
     148             :         int r;
     149             : 
     150           0 :         assert(message);
     151           0 :         assert(track);
     152             : 
     153           0 :         r = sd_bus_message_read(message, "sss", &name, &old, &new);
     154           0 :         if (r < 0)
     155           0 :                 return 0;
     156             : 
     157           0 :         sd_bus_track_remove_name(track, name);
     158           0 :         return 0;
     159             : }
     160             : 
     161           0 : _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
     162           0 :         _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
     163           0 :         _cleanup_free_ char *n = NULL;
     164             :         const char *match;
     165             :         int r;
     166             : 
     167           0 :         assert_return(track, -EINVAL);
     168           0 :         assert_return(service_name_is_valid(name), -EINVAL);
     169             : 
     170           0 :         r = hashmap_ensure_allocated(&track->names, &string_hash_ops);
     171           0 :         if (r < 0)
     172           0 :                 return r;
     173             : 
     174           0 :         n = strdup(name);
     175           0 :         if (!n)
     176           0 :                 return -ENOMEM;
     177             : 
     178             :         /* First, subscribe to this name */
     179           0 :         match = MATCH_FOR_NAME(n);
     180           0 :         r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
     181           0 :         if (r < 0)
     182           0 :                 return r;
     183             : 
     184           0 :         r = hashmap_put(track->names, n, slot);
     185           0 :         if (r == -EEXIST)
     186           0 :                 return 0;
     187           0 :         if (r < 0)
     188           0 :                 return r;
     189             : 
     190             :         /* Second, check if it is currently existing, or maybe
     191             :          * doesn't, or maybe disappeared already. */
     192           0 :         r = sd_bus_get_name_creds(track->bus, n, 0, NULL);
     193           0 :         if (r < 0) {
     194           0 :                 hashmap_remove(track->names, n);
     195           0 :                 return r;
     196             :         }
     197             : 
     198           0 :         n = NULL;
     199           0 :         slot = NULL;
     200             : 
     201           0 :         bus_track_remove_from_queue(track);
     202           0 :         track->modified = true;
     203             : 
     204           0 :         return 1;
     205             : }
     206             : 
     207           0 : _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
     208           0 :         _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
     209           0 :         _cleanup_free_ char *n = NULL;
     210             : 
     211           0 :         assert_return(name, -EINVAL);
     212             : 
     213           0 :         if (!track)
     214           0 :                 return 0;
     215             : 
     216           0 :         slot = hashmap_remove2(track->names, (char*) name, (void**) &n);
     217           0 :         if (!slot)
     218           0 :                 return 0;
     219             : 
     220           0 :         if (hashmap_isempty(track->names))
     221           0 :                 bus_track_add_to_queue(track);
     222             : 
     223           0 :         track->modified = true;
     224             : 
     225           0 :         return 1;
     226             : }
     227             : 
     228        4200 : _public_ unsigned sd_bus_track_count(sd_bus_track *track) {
     229        4200 :         if (!track)
     230        4200 :                 return 0;
     231             : 
     232           0 :         return hashmap_size(track->names);
     233             : }
     234             : 
     235           0 : _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
     236           0 :         assert_return(track, NULL);
     237           0 :         assert_return(name, NULL);
     238             : 
     239           0 :         return hashmap_get(track->names, (void*) name) ? name : NULL;
     240             : }
     241             : 
     242           0 : _public_ const char* sd_bus_track_first(sd_bus_track *track) {
     243           0 :         const char *n = NULL;
     244             : 
     245           0 :         if (!track)
     246           0 :                 return NULL;
     247             : 
     248           0 :         track->modified = false;
     249           0 :         track->iterator = ITERATOR_FIRST;
     250             : 
     251           0 :         hashmap_iterate(track->names, &track->iterator, NULL, (const void**) &n);
     252           0 :         return n;
     253             : }
     254             : 
     255           0 : _public_ const char* sd_bus_track_next(sd_bus_track *track) {
     256           0 :         const char *n = NULL;
     257             : 
     258           0 :         if (!track)
     259           0 :                 return NULL;
     260             : 
     261           0 :         if (track->modified)
     262           0 :                 return NULL;
     263             : 
     264           0 :         hashmap_iterate(track->names, &track->iterator, NULL, (const void**) &n);
     265           0 :         return n;
     266             : }
     267             : 
     268           0 : _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
     269             :         const char *sender;
     270             : 
     271           0 :         assert_return(track, -EINVAL);
     272           0 :         assert_return(m, -EINVAL);
     273             : 
     274           0 :         sender = sd_bus_message_get_sender(m);
     275           0 :         if (!sender)
     276           0 :                 return -EINVAL;
     277             : 
     278           0 :         return sd_bus_track_add_name(track, sender);
     279             : }
     280             : 
     281           0 : _public_ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) {
     282             :         const char *sender;
     283             : 
     284           0 :         assert_return(track, -EINVAL);
     285           0 :         assert_return(m, -EINVAL);
     286             : 
     287           0 :         sender = sd_bus_message_get_sender(m);
     288           0 :         if (!sender)
     289           0 :                 return -EINVAL;
     290             : 
     291           0 :         return sd_bus_track_remove_name(track, sender);
     292             : }
     293             : 
     294           0 : _public_ sd_bus* sd_bus_track_get_bus(sd_bus_track *track) {
     295           0 :         assert_return(track, NULL);
     296             : 
     297           0 :         return track->bus;
     298             : }
     299             : 
     300           0 : void bus_track_dispatch(sd_bus_track *track) {
     301             :         int r;
     302             : 
     303           0 :         assert(track);
     304           0 :         assert(track->in_queue);
     305           0 :         assert(track->handler);
     306             : 
     307           0 :         bus_track_remove_from_queue(track);
     308             : 
     309           0 :         sd_bus_track_ref(track);
     310             : 
     311           0 :         r = track->handler(track, track->userdata);
     312           0 :         if (r < 0)
     313           0 :                 log_debug_errno(r, "Failed to process track handler: %m");
     314           0 :         else if (r == 0)
     315           0 :                 bus_track_add_to_queue(track);
     316             : 
     317           0 :         sd_bus_track_unref(track);
     318           0 : }
     319             : 
     320           0 : _public_ void *sd_bus_track_get_userdata(sd_bus_track *track) {
     321           0 :         assert_return(track, NULL);
     322             : 
     323           0 :         return track->userdata;
     324             : }
     325             : 
     326           0 : _public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) {
     327             :         void *ret;
     328             : 
     329           0 :         assert_return(track, NULL);
     330             : 
     331           0 :         ret = track->userdata;
     332           0 :         track->userdata = userdata;
     333             : 
     334           0 :         return ret;
     335             : }

Generated by: LCOV version 1.11