LCOV - code coverage report
Current view: top level - shared - bus-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 52 988 5.3 %
Date: 2015-07-29 18:47:03 Functions: 5 43 11.6 %

          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 <sys/socket.h>
      23             : 
      24             : #include "sd-daemon.h"
      25             : #include "sd-event.h"
      26             : #include "util.h"
      27             : #include "strv.h"
      28             : #include "macro.h"
      29             : #include "def.h"
      30             : #include "path-util.h"
      31             : #include "missing.h"
      32             : #include "set.h"
      33             : #include "signal-util.h"
      34             : #include "unit-name.h"
      35             : 
      36             : #include "sd-bus.h"
      37             : #include "bus-error.h"
      38             : #include "bus-label.h"
      39             : #include "bus-message.h"
      40             : #include "bus-util.h"
      41             : #include "bus-internal.h"
      42             : 
      43           0 : static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
      44           0 :         sd_event *e = userdata;
      45             : 
      46           0 :         assert(m);
      47           0 :         assert(e);
      48             : 
      49           0 :         sd_bus_close(sd_bus_message_get_bus(m));
      50           0 :         sd_event_exit(e, 0);
      51             : 
      52           0 :         return 1;
      53             : }
      54             : 
      55           0 : int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
      56           0 :         _cleanup_free_ char *match = NULL;
      57             :         const char *unique;
      58             :         int r;
      59             : 
      60           0 :         assert(e);
      61           0 :         assert(bus);
      62           0 :         assert(name);
      63             : 
      64             :         /* We unregister the name here and then wait for the
      65             :          * NameOwnerChanged signal for this event to arrive before we
      66             :          * quit. We do this in order to make sure that any queued
      67             :          * requests are still processed before we really exit. */
      68             : 
      69           0 :         r = sd_bus_get_unique_name(bus, &unique);
      70           0 :         if (r < 0)
      71           0 :                 return r;
      72             : 
      73           0 :         r = asprintf(&match,
      74             :                      "sender='org.freedesktop.DBus',"
      75             :                      "type='signal',"
      76             :                      "interface='org.freedesktop.DBus',"
      77             :                      "member='NameOwnerChanged',"
      78             :                      "path='/org/freedesktop/DBus',"
      79             :                      "arg0='%s',"
      80             :                      "arg1='%s',"
      81             :                      "arg2=''", name, unique);
      82           0 :         if (r < 0)
      83           0 :                 return -ENOMEM;
      84             : 
      85           0 :         r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
      86           0 :         if (r < 0)
      87           0 :                 return r;
      88             : 
      89           0 :         r = sd_bus_release_name(bus, name);
      90           0 :         if (r < 0)
      91           0 :                 return r;
      92             : 
      93           0 :         return 0;
      94             : }
      95             : 
      96           0 : int bus_event_loop_with_idle(
      97             :                 sd_event *e,
      98             :                 sd_bus *bus,
      99             :                 const char *name,
     100             :                 usec_t timeout,
     101             :                 check_idle_t check_idle,
     102             :                 void *userdata) {
     103           0 :         bool exiting = false;
     104             :         int r, code;
     105             : 
     106           0 :         assert(e);
     107           0 :         assert(bus);
     108           0 :         assert(name);
     109             : 
     110             :         for (;;) {
     111             :                 bool idle;
     112             : 
     113           0 :                 r = sd_event_get_state(e);
     114           0 :                 if (r < 0)
     115           0 :                         return r;
     116           0 :                 if (r == SD_EVENT_FINISHED)
     117           0 :                         break;
     118             : 
     119           0 :                 if (check_idle)
     120           0 :                         idle = check_idle(userdata);
     121             :                 else
     122           0 :                         idle = true;
     123             : 
     124           0 :                 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
     125           0 :                 if (r < 0)
     126           0 :                         return r;
     127             : 
     128           0 :                 if (r == 0 && !exiting && idle) {
     129             : 
     130           0 :                         r = sd_bus_try_close(bus);
     131           0 :                         if (r == -EBUSY)
     132           0 :                                 continue;
     133             : 
     134             :                         /* Fallback for dbus1 connections: we
     135             :                          * unregister the name and wait for the
     136             :                          * response to come through for it */
     137           0 :                         if (r == -EOPNOTSUPP) {
     138             : 
     139             :                                 /* Inform the service manager that we
     140             :                                  * are going down, so that it will
     141             :                                  * queue all further start requests,
     142             :                                  * instead of assuming we are already
     143             :                                  * running. */
     144           0 :                                 sd_notify(false, "STOPPING=1");
     145             : 
     146           0 :                                 r = bus_async_unregister_and_exit(e, bus, name);
     147           0 :                                 if (r < 0)
     148           0 :                                         return r;
     149             : 
     150           0 :                                 exiting = true;
     151           0 :                                 continue;
     152             :                         }
     153             : 
     154           0 :                         if (r < 0)
     155           0 :                                 return r;
     156             : 
     157           0 :                         sd_event_exit(e, 0);
     158           0 :                         break;
     159             :                 }
     160           0 :         }
     161             : 
     162           0 :         r = sd_event_get_exit_code(e, &code);
     163           0 :         if (r < 0)
     164           0 :                 return r;
     165             : 
     166           0 :         return code;
     167             : }
     168             : 
     169           0 : int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
     170           0 :         _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
     171           0 :         int r, has_owner = 0;
     172             : 
     173           0 :         assert(c);
     174           0 :         assert(name);
     175             : 
     176           0 :         r = sd_bus_call_method(c,
     177             :                                "org.freedesktop.DBus",
     178             :                                "/org/freedesktop/dbus",
     179             :                                "org.freedesktop.DBus",
     180             :                                "NameHasOwner",
     181             :                                error,
     182             :                                &rep,
     183             :                                "s",
     184             :                                name);
     185           0 :         if (r < 0)
     186           0 :                 return r;
     187             : 
     188           0 :         r = sd_bus_message_read_basic(rep, 'b', &has_owner);
     189           0 :         if (r < 0)
     190           0 :                 return sd_bus_error_set_errno(error, r);
     191             : 
     192           0 :         return has_owner;
     193             : }
     194             : 
     195           0 : static int check_good_user(sd_bus_message *m, uid_t good_user) {
     196           0 :         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
     197             :         uid_t sender_uid;
     198             :         int r;
     199             : 
     200           0 :         assert(m);
     201             : 
     202           0 :         if (good_user == UID_INVALID)
     203           0 :                 return 0;
     204             : 
     205           0 :         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
     206           0 :         if (r < 0)
     207           0 :                 return r;
     208             : 
     209             :         /* Don't trust augmented credentials for authorization */
     210           0 :         assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
     211             : 
     212           0 :         r = sd_bus_creds_get_euid(creds, &sender_uid);
     213           0 :         if (r < 0)
     214           0 :                 return r;
     215             : 
     216           0 :         return sender_uid == good_user;
     217             : }
     218             : 
     219           0 : int bus_test_polkit(
     220             :                 sd_bus_message *call,
     221             :                 int capability,
     222             :                 const char *action,
     223             :                 uid_t good_user,
     224             :                 bool *_challenge,
     225             :                 sd_bus_error *e) {
     226             : 
     227             :         int r;
     228             : 
     229           0 :         assert(call);
     230           0 :         assert(action);
     231             : 
     232             :         /* Tests non-interactively! */
     233             : 
     234           0 :         r = check_good_user(call, good_user);
     235           0 :         if (r != 0)
     236           0 :                 return r;
     237             : 
     238           0 :         r = sd_bus_query_sender_privilege(call, capability);
     239           0 :         if (r < 0)
     240           0 :                 return r;
     241           0 :         else if (r > 0)
     242           0 :                 return 1;
     243             : #ifdef ENABLE_POLKIT
     244             :         else {
     245           0 :                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     246           0 :                 int authorized = false, challenge = false;
     247             :                 const char *sender;
     248             : 
     249           0 :                 sender = sd_bus_message_get_sender(call);
     250           0 :                 if (!sender)
     251           0 :                         return -EBADMSG;
     252             : 
     253           0 :                 r = sd_bus_call_method(
     254             :                                 call->bus,
     255             :                                 "org.freedesktop.PolicyKit1",
     256             :                                 "/org/freedesktop/PolicyKit1/Authority",
     257             :                                 "org.freedesktop.PolicyKit1.Authority",
     258             :                                 "CheckAuthorization",
     259             :                                 e,
     260             :                                 &reply,
     261             :                                 "(sa{sv})sa{ss}us",
     262             :                                 "system-bus-name", 1, "name", "s", sender,
     263             :                                 action,
     264             :                                 0,
     265             :                                 0,
     266             :                                 "");
     267             : 
     268           0 :                 if (r < 0) {
     269             :                         /* Treat no PK available as access denied */
     270           0 :                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
     271           0 :                                 sd_bus_error_free(e);
     272           0 :                                 return -EACCES;
     273             :                         }
     274             : 
     275           0 :                         return r;
     276             :                 }
     277             : 
     278           0 :                 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
     279           0 :                 if (r < 0)
     280           0 :                         return r;
     281             : 
     282           0 :                 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
     283           0 :                 if (r < 0)
     284           0 :                         return r;
     285             : 
     286           0 :                 if (authorized)
     287           0 :                         return 1;
     288             : 
     289           0 :                 if (_challenge) {
     290           0 :                         *_challenge = challenge;
     291           0 :                         return 0;
     292             :                 }
     293             :         }
     294             : #endif
     295             : 
     296           0 :         return -EACCES;
     297             : }
     298             : 
     299             : #ifdef ENABLE_POLKIT
     300             : 
     301             : typedef struct AsyncPolkitQuery {
     302             :         sd_bus_message *request, *reply;
     303             :         sd_bus_message_handler_t callback;
     304             :         void *userdata;
     305             :         sd_bus_slot *slot;
     306             :         Hashmap *registry;
     307             : } AsyncPolkitQuery;
     308             : 
     309           0 : static void async_polkit_query_free(AsyncPolkitQuery *q) {
     310             : 
     311           0 :         if (!q)
     312           0 :                 return;
     313             : 
     314           0 :         sd_bus_slot_unref(q->slot);
     315             : 
     316           0 :         if (q->registry && q->request)
     317           0 :                 hashmap_remove(q->registry, q->request);
     318             : 
     319           0 :         sd_bus_message_unref(q->request);
     320           0 :         sd_bus_message_unref(q->reply);
     321             : 
     322           0 :         free(q);
     323             : }
     324             : 
     325           0 : static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
     326           0 :         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
     327           0 :         AsyncPolkitQuery *q = userdata;
     328             :         int r;
     329             : 
     330           0 :         assert(reply);
     331           0 :         assert(q);
     332             : 
     333           0 :         q->slot = sd_bus_slot_unref(q->slot);
     334           0 :         q->reply = sd_bus_message_ref(reply);
     335             : 
     336           0 :         r = sd_bus_message_rewind(q->request, true);
     337           0 :         if (r < 0) {
     338           0 :                 r = sd_bus_reply_method_errno(q->request, r, NULL);
     339           0 :                 goto finish;
     340             :         }
     341             : 
     342           0 :         r = q->callback(q->request, q->userdata, &error_buffer);
     343           0 :         r = bus_maybe_reply_error(q->request, r, &error_buffer);
     344             : 
     345             : finish:
     346           0 :         async_polkit_query_free(q);
     347             : 
     348           0 :         return r;
     349             : }
     350             : 
     351             : #endif
     352             : 
     353           0 : int bus_verify_polkit_async(
     354             :                 sd_bus_message *call,
     355             :                 int capability,
     356             :                 const char *action,
     357             :                 bool interactive,
     358             :                 uid_t good_user,
     359             :                 Hashmap **registry,
     360             :                 sd_bus_error *error) {
     361             : 
     362             : #ifdef ENABLE_POLKIT
     363           0 :         _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
     364             :         AsyncPolkitQuery *q;
     365             :         const char *sender;
     366             :         sd_bus_message_handler_t callback;
     367             :         void *userdata;
     368             :         int c;
     369             : #endif
     370             :         int r;
     371             : 
     372           0 :         assert(call);
     373           0 :         assert(action);
     374           0 :         assert(registry);
     375             : 
     376           0 :         r = check_good_user(call, good_user);
     377           0 :         if (r != 0)
     378           0 :                 return r;
     379             : 
     380             : #ifdef ENABLE_POLKIT
     381           0 :         q = hashmap_get(*registry, call);
     382           0 :         if (q) {
     383             :                 int authorized, challenge;
     384             : 
     385             :                 /* This is the second invocation of this function, and
     386             :                  * there's already a response from polkit, let's
     387             :                  * process it */
     388           0 :                 assert(q->reply);
     389             : 
     390           0 :                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
     391             :                         const sd_bus_error *e;
     392             : 
     393             :                         /* Copy error from polkit reply */
     394           0 :                         e = sd_bus_message_get_error(q->reply);
     395           0 :                         sd_bus_error_copy(error, e);
     396             : 
     397             :                         /* Treat no PK available as access denied */
     398           0 :                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
     399           0 :                                 return -EACCES;
     400             : 
     401           0 :                         return -sd_bus_error_get_errno(e);
     402             :                 }
     403             : 
     404           0 :                 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
     405           0 :                 if (r >= 0)
     406           0 :                         r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
     407             : 
     408           0 :                 if (r < 0)
     409           0 :                         return r;
     410             : 
     411           0 :                 if (authorized)
     412           0 :                         return 1;
     413             : 
     414           0 :                 if (challenge)
     415           0 :                         return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
     416             : 
     417           0 :                 return -EACCES;
     418             :         }
     419             : #endif
     420             : 
     421           0 :         r = sd_bus_query_sender_privilege(call, capability);
     422           0 :         if (r < 0)
     423           0 :                 return r;
     424           0 :         else if (r > 0)
     425           0 :                 return 1;
     426             : 
     427             : #ifdef ENABLE_POLKIT
     428           0 :         if (sd_bus_get_current_message(call->bus) != call)
     429           0 :                 return -EINVAL;
     430             : 
     431           0 :         callback = sd_bus_get_current_handler(call->bus);
     432           0 :         if (!callback)
     433           0 :                 return -EINVAL;
     434             : 
     435           0 :         userdata = sd_bus_get_current_userdata(call->bus);
     436             : 
     437           0 :         sender = sd_bus_message_get_sender(call);
     438           0 :         if (!sender)
     439           0 :                 return -EBADMSG;
     440             : 
     441           0 :         c = sd_bus_message_get_allow_interactive_authorization(call);
     442           0 :         if (c < 0)
     443           0 :                 return c;
     444           0 :         if (c > 0)
     445           0 :                 interactive = true;
     446             : 
     447           0 :         r = hashmap_ensure_allocated(registry, NULL);
     448           0 :         if (r < 0)
     449           0 :                 return r;
     450             : 
     451           0 :         r = sd_bus_message_new_method_call(
     452             :                         call->bus,
     453             :                         &pk,
     454             :                         "org.freedesktop.PolicyKit1",
     455             :                         "/org/freedesktop/PolicyKit1/Authority",
     456             :                         "org.freedesktop.PolicyKit1.Authority",
     457             :                         "CheckAuthorization");
     458           0 :         if (r < 0)
     459           0 :                 return r;
     460             : 
     461           0 :         r = sd_bus_message_append(
     462             :                         pk,
     463             :                         "(sa{sv})sa{ss}us",
     464             :                         "system-bus-name", 1, "name", "s", sender,
     465             :                         action,
     466             :                         0,
     467             :                         !!interactive,
     468             :                         NULL);
     469           0 :         if (r < 0)
     470           0 :                 return r;
     471             : 
     472           0 :         q = new0(AsyncPolkitQuery, 1);
     473           0 :         if (!q)
     474           0 :                 return -ENOMEM;
     475             : 
     476           0 :         q->request = sd_bus_message_ref(call);
     477           0 :         q->callback = callback;
     478           0 :         q->userdata = userdata;
     479             : 
     480           0 :         r = hashmap_put(*registry, call, q);
     481           0 :         if (r < 0) {
     482           0 :                 async_polkit_query_free(q);
     483           0 :                 return r;
     484             :         }
     485             : 
     486           0 :         q->registry = *registry;
     487             : 
     488           0 :         r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
     489           0 :         if (r < 0) {
     490           0 :                 async_polkit_query_free(q);
     491           0 :                 return r;
     492             :         }
     493             : 
     494           0 :         return 0;
     495             : #endif
     496             : 
     497             :         return -EACCES;
     498             : }
     499             : 
     500          11 : void bus_verify_polkit_async_registry_free(Hashmap *registry) {
     501             : #ifdef ENABLE_POLKIT
     502             :         AsyncPolkitQuery *q;
     503             : 
     504          22 :         while ((q = hashmap_steal_first(registry)))
     505           0 :                 async_polkit_query_free(q);
     506             : 
     507          11 :         hashmap_free(registry);
     508             : #endif
     509          11 : }
     510             : 
     511           0 : int bus_check_peercred(sd_bus *c) {
     512             :         struct ucred ucred;
     513             :         socklen_t l;
     514             :         int fd;
     515             : 
     516           0 :         assert(c);
     517             : 
     518           0 :         fd = sd_bus_get_fd(c);
     519           0 :         if (fd < 0)
     520           0 :                 return fd;
     521             : 
     522           0 :         l = sizeof(struct ucred);
     523           0 :         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
     524           0 :                 return -errno;
     525             : 
     526           0 :         if (l != sizeof(struct ucred))
     527           0 :                 return -E2BIG;
     528             : 
     529           0 :         if (ucred.uid != 0 && ucred.uid != geteuid())
     530           0 :                 return -EPERM;
     531             : 
     532           0 :         return 1;
     533             : }
     534             : 
     535           0 : int bus_open_system_systemd(sd_bus **_bus) {
     536           0 :         _cleanup_bus_unref_ sd_bus *bus = NULL;
     537             :         int r;
     538             : 
     539           0 :         assert(_bus);
     540             : 
     541           0 :         if (geteuid() != 0)
     542           0 :                 return sd_bus_open_system(_bus);
     543             : 
     544             :         /* If we are root and kdbus is not available, then let's talk
     545             :          * directly to the system instance, instead of going via the
     546             :          * bus */
     547             : 
     548           0 :         r = sd_bus_new(&bus);
     549           0 :         if (r < 0)
     550           0 :                 return r;
     551             : 
     552           0 :         r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
     553           0 :         if (r < 0)
     554           0 :                 return r;
     555             : 
     556           0 :         bus->bus_client = true;
     557             : 
     558           0 :         r = sd_bus_start(bus);
     559           0 :         if (r >= 0) {
     560           0 :                 *_bus = bus;
     561           0 :                 bus = NULL;
     562           0 :                 return 0;
     563             :         }
     564             : 
     565           0 :         bus = sd_bus_unref(bus);
     566             : 
     567           0 :         r = sd_bus_new(&bus);
     568           0 :         if (r < 0)
     569           0 :                 return r;
     570             : 
     571           0 :         r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
     572           0 :         if (r < 0)
     573           0 :                 return r;
     574             : 
     575           0 :         r = sd_bus_start(bus);
     576           0 :         if (r < 0)
     577           0 :                 return sd_bus_open_system(_bus);
     578             : 
     579           0 :         r = bus_check_peercred(bus);
     580           0 :         if (r < 0)
     581           0 :                 return r;
     582             : 
     583           0 :         *_bus = bus;
     584           0 :         bus = NULL;
     585             : 
     586           0 :         return 0;
     587             : }
     588             : 
     589           0 : int bus_open_user_systemd(sd_bus **_bus) {
     590           0 :         _cleanup_bus_unref_ sd_bus *bus = NULL;
     591           0 :         _cleanup_free_ char *ee = NULL;
     592             :         const char *e;
     593             :         int r;
     594             : 
     595             :         /* Try via kdbus first, and then directly */
     596             : 
     597           0 :         assert(_bus);
     598             : 
     599           0 :         r = sd_bus_new(&bus);
     600           0 :         if (r < 0)
     601           0 :                 return r;
     602             : 
     603           0 :         if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
     604           0 :                 return -ENOMEM;
     605             : 
     606           0 :         bus->bus_client = true;
     607             : 
     608           0 :         r = sd_bus_start(bus);
     609           0 :         if (r >= 0) {
     610           0 :                 *_bus = bus;
     611           0 :                 bus = NULL;
     612           0 :                 return 0;
     613             :         }
     614             : 
     615           0 :         bus = sd_bus_unref(bus);
     616             : 
     617           0 :         e = secure_getenv("XDG_RUNTIME_DIR");
     618           0 :         if (!e)
     619           0 :                 return sd_bus_open_user(_bus);
     620             : 
     621           0 :         ee = bus_address_escape(e);
     622           0 :         if (!ee)
     623           0 :                 return -ENOMEM;
     624             : 
     625           0 :         r = sd_bus_new(&bus);
     626           0 :         if (r < 0)
     627           0 :                 return r;
     628             : 
     629           0 :         bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
     630           0 :         if (!bus->address)
     631           0 :                 return -ENOMEM;
     632             : 
     633           0 :         r = sd_bus_start(bus);
     634           0 :         if (r < 0)
     635           0 :                 return sd_bus_open_user(_bus);
     636             : 
     637           0 :         r = bus_check_peercred(bus);
     638           0 :         if (r < 0)
     639           0 :                 return r;
     640             : 
     641           0 :         *_bus = bus;
     642           0 :         bus = NULL;
     643             : 
     644           0 :         return 0;
     645             : }
     646             : 
     647           0 : int bus_print_property(const char *name, sd_bus_message *property, bool all) {
     648             :         char type;
     649             :         const char *contents;
     650             :         int r;
     651             : 
     652           0 :         assert(name);
     653           0 :         assert(property);
     654             : 
     655           0 :         r = sd_bus_message_peek_type(property, &type, &contents);
     656           0 :         if (r < 0)
     657           0 :                 return r;
     658             : 
     659           0 :         switch (type) {
     660             : 
     661             :         case SD_BUS_TYPE_STRING: {
     662             :                 const char *s;
     663             : 
     664           0 :                 r = sd_bus_message_read_basic(property, type, &s);
     665           0 :                 if (r < 0)
     666           0 :                         return r;
     667             : 
     668           0 :                 if (all || !isempty(s)) {
     669           0 :                         _cleanup_free_ char *escaped = NULL;
     670             : 
     671           0 :                         escaped = xescape(s, "\n");
     672           0 :                         if (!escaped)
     673           0 :                                 return -ENOMEM;
     674             : 
     675           0 :                         printf("%s=%s\n", name, escaped);
     676             :                 }
     677             : 
     678           0 :                 return 1;
     679             :         }
     680             : 
     681             :         case SD_BUS_TYPE_BOOLEAN: {
     682             :                 int b;
     683             : 
     684           0 :                 r = sd_bus_message_read_basic(property, type, &b);
     685           0 :                 if (r < 0)
     686           0 :                         return r;
     687             : 
     688           0 :                 printf("%s=%s\n", name, yes_no(b));
     689             : 
     690           0 :                 return 1;
     691             :         }
     692             : 
     693             :         case SD_BUS_TYPE_UINT64: {
     694             :                 uint64_t u;
     695             : 
     696           0 :                 r = sd_bus_message_read_basic(property, type, &u);
     697           0 :                 if (r < 0)
     698           0 :                         return r;
     699             : 
     700             :                 /* Yes, heuristics! But we can change this check
     701             :                  * should it turn out to not be sufficient */
     702             : 
     703           0 :                 if (endswith(name, "Timestamp")) {
     704             :                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
     705             : 
     706           0 :                         t = format_timestamp(timestamp, sizeof(timestamp), u);
     707           0 :                         if (t || all)
     708           0 :                                 printf("%s=%s\n", name, strempty(t));
     709             : 
     710           0 :                 } else if (strstr(name, "USec")) {
     711             :                         char timespan[FORMAT_TIMESPAN_MAX];
     712             : 
     713           0 :                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
     714             :                 } else
     715           0 :                         printf("%s=%llu\n", name, (unsigned long long) u);
     716             : 
     717           0 :                 return 1;
     718             :         }
     719             : 
     720             :         case SD_BUS_TYPE_INT64: {
     721             :                 int64_t i;
     722             : 
     723           0 :                 r = sd_bus_message_read_basic(property, type, &i);
     724           0 :                 if (r < 0)
     725           0 :                         return r;
     726             : 
     727           0 :                 printf("%s=%lld\n", name, (long long) i);
     728             : 
     729           0 :                 return 1;
     730             :         }
     731             : 
     732             :         case SD_BUS_TYPE_UINT32: {
     733             :                 uint32_t u;
     734             : 
     735           0 :                 r = sd_bus_message_read_basic(property, type, &u);
     736           0 :                 if (r < 0)
     737           0 :                         return r;
     738             : 
     739           0 :                 if (strstr(name, "UMask") || strstr(name, "Mode"))
     740           0 :                         printf("%s=%04o\n", name, u);
     741             :                 else
     742           0 :                         printf("%s=%u\n", name, (unsigned) u);
     743             : 
     744           0 :                 return 1;
     745             :         }
     746             : 
     747             :         case SD_BUS_TYPE_INT32: {
     748             :                 int32_t i;
     749             : 
     750           0 :                 r = sd_bus_message_read_basic(property, type, &i);
     751           0 :                 if (r < 0)
     752           0 :                         return r;
     753             : 
     754           0 :                 printf("%s=%i\n", name, (int) i);
     755           0 :                 return 1;
     756             :         }
     757             : 
     758             :         case SD_BUS_TYPE_DOUBLE: {
     759             :                 double d;
     760             : 
     761           0 :                 r = sd_bus_message_read_basic(property, type, &d);
     762           0 :                 if (r < 0)
     763           0 :                         return r;
     764             : 
     765           0 :                 printf("%s=%g\n", name, d);
     766           0 :                 return 1;
     767             :         }
     768             : 
     769             :         case SD_BUS_TYPE_ARRAY:
     770           0 :                 if (streq(contents, "s")) {
     771           0 :                         bool first = true;
     772             :                         const char *str;
     773             : 
     774           0 :                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
     775           0 :                         if (r < 0)
     776           0 :                                 return r;
     777             : 
     778           0 :                         while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
     779           0 :                                 _cleanup_free_ char *escaped = NULL;
     780             : 
     781           0 :                                 if (first)
     782           0 :                                         printf("%s=", name);
     783             : 
     784           0 :                                 escaped = xescape(str, "\n ");
     785           0 :                                 if (!escaped)
     786           0 :                                         return -ENOMEM;
     787             : 
     788           0 :                                 printf("%s%s", first ? "" : " ", escaped);
     789             : 
     790           0 :                                 first = false;
     791             :                         }
     792           0 :                         if (r < 0)
     793           0 :                                 return r;
     794             : 
     795           0 :                         if (first && all)
     796           0 :                                 printf("%s=", name);
     797           0 :                         if (!first || all)
     798           0 :                                 puts("");
     799             : 
     800           0 :                         r = sd_bus_message_exit_container(property);
     801           0 :                         if (r < 0)
     802           0 :                                 return r;
     803             : 
     804           0 :                         return 1;
     805             : 
     806           0 :                 } else if (streq(contents, "y")) {
     807             :                         const uint8_t *u;
     808             :                         size_t n;
     809             : 
     810           0 :                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
     811           0 :                         if (r < 0)
     812           0 :                                 return r;
     813             : 
     814           0 :                         if (all || n > 0) {
     815             :                                 unsigned int i;
     816             : 
     817           0 :                                 printf("%s=", name);
     818             : 
     819           0 :                                 for (i = 0; i < n; i++)
     820           0 :                                         printf("%02x", u[i]);
     821             : 
     822           0 :                                 puts("");
     823             :                         }
     824             : 
     825           0 :                         return 1;
     826             : 
     827           0 :                 } else if (streq(contents, "u")) {
     828             :                         uint32_t *u;
     829             :                         size_t n;
     830             : 
     831           0 :                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
     832           0 :                         if (r < 0)
     833           0 :                                 return r;
     834             : 
     835           0 :                         if (all || n > 0) {
     836             :                                 unsigned int i;
     837             : 
     838           0 :                                 printf("%s=", name);
     839             : 
     840           0 :                                 for (i = 0; i < n; i++)
     841           0 :                                         printf("%08x", u[i]);
     842             : 
     843           0 :                                 puts("");
     844             :                         }
     845             : 
     846           0 :                         return 1;
     847             :                 }
     848             : 
     849           0 :                 break;
     850             :         }
     851             : 
     852           0 :         return 0;
     853             : }
     854             : 
     855           0 : int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
     856           0 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     857           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     858             :         int r;
     859             : 
     860           0 :         assert(bus);
     861           0 :         assert(path);
     862             : 
     863           0 :         r = sd_bus_call_method(bus,
     864             :                         dest,
     865             :                         path,
     866             :                         "org.freedesktop.DBus.Properties",
     867             :                         "GetAll",
     868             :                         &error,
     869             :                         &reply,
     870             :                         "s", "");
     871           0 :         if (r < 0)
     872           0 :                 return r;
     873             : 
     874           0 :         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
     875           0 :         if (r < 0)
     876           0 :                 return r;
     877             : 
     878           0 :         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
     879             :                 const char *name;
     880             :                 const char *contents;
     881             : 
     882           0 :                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
     883           0 :                 if (r < 0)
     884           0 :                         return r;
     885             : 
     886           0 :                 if (!filter || strv_find(filter, name)) {
     887           0 :                         r = sd_bus_message_peek_type(reply, NULL, &contents);
     888           0 :                         if (r < 0)
     889           0 :                                 return r;
     890             : 
     891           0 :                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
     892           0 :                         if (r < 0)
     893           0 :                                 return r;
     894             : 
     895           0 :                         r = bus_print_property(name, reply, all);
     896           0 :                         if (r < 0)
     897           0 :                                 return r;
     898           0 :                         if (r == 0) {
     899           0 :                                 if (all)
     900           0 :                                         printf("%s=[unprintable]\n", name);
     901             :                                 /* skip what we didn't read */
     902           0 :                                 r = sd_bus_message_skip(reply, contents);
     903           0 :                                 if (r < 0)
     904           0 :                                         return r;
     905             :                         }
     906             : 
     907           0 :                         r = sd_bus_message_exit_container(reply);
     908           0 :                         if (r < 0)
     909           0 :                                 return r;
     910             :                 } else {
     911           0 :                         r = sd_bus_message_skip(reply, "v");
     912           0 :                         if (r < 0)
     913           0 :                                 return r;
     914             :                 }
     915             : 
     916           0 :                 r = sd_bus_message_exit_container(reply);
     917           0 :                 if (r < 0)
     918           0 :                         return r;
     919             :         }
     920           0 :         if (r < 0)
     921           0 :                 return r;
     922             : 
     923           0 :         r = sd_bus_message_exit_container(reply);
     924           0 :         if (r < 0)
     925           0 :                 return r;
     926             : 
     927           0 :         return 0;
     928             : }
     929             : 
     930           0 : int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
     931           0 :         sd_id128_t *p = userdata;
     932             :         const void *v;
     933             :         size_t n;
     934             :         int r;
     935             : 
     936           0 :         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
     937           0 :         if (r < 0)
     938           0 :                 return r;
     939             : 
     940           0 :         if (n == 0)
     941           0 :                 *p = SD_ID128_NULL;
     942           0 :         else if (n == 16)
     943           0 :                 memcpy((*p).bytes, v, n);
     944             :         else
     945           0 :                 return -EINVAL;
     946             : 
     947           0 :         return 0;
     948             : }
     949             : 
     950           0 : static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
     951             :         char type;
     952             :         int r;
     953             : 
     954           0 :         r = sd_bus_message_peek_type(m, &type, NULL);
     955           0 :         if (r < 0)
     956           0 :                 return r;
     957             : 
     958           0 :         switch (type) {
     959             :         case SD_BUS_TYPE_STRING: {
     960             :                 const char *s;
     961           0 :                 char **p = userdata;
     962             : 
     963           0 :                 r = sd_bus_message_read_basic(m, type, &s);
     964           0 :                 if (r < 0)
     965           0 :                         break;
     966             : 
     967           0 :                 if (isempty(s))
     968           0 :                         break;
     969             : 
     970           0 :                 r = free_and_strdup(p, s);
     971           0 :                 break;
     972             :         }
     973             : 
     974             :         case SD_BUS_TYPE_ARRAY: {
     975           0 :                _cleanup_strv_free_ char **l = NULL;
     976           0 :                char ***p = userdata;
     977             : 
     978           0 :                 r = bus_message_read_strv_extend(m, &l);
     979           0 :                 if (r < 0)
     980           0 :                         break;
     981             : 
     982           0 :                 strv_free(*p);
     983           0 :                 *p = l;
     984           0 :                 l = NULL;
     985             : 
     986           0 :                 break;
     987             :         }
     988             : 
     989             :         case SD_BUS_TYPE_BOOLEAN: {
     990             :                 unsigned b;
     991           0 :                 bool *p = userdata;
     992             : 
     993           0 :                 r = sd_bus_message_read_basic(m, type, &b);
     994           0 :                 if (r < 0)
     995           0 :                         break;
     996             : 
     997           0 :                 *p = b;
     998             : 
     999           0 :                 break;
    1000             :         }
    1001             : 
    1002             :         case SD_BUS_TYPE_UINT32: {
    1003             :                 uint64_t u;
    1004           0 :                 uint32_t *p = userdata;
    1005             : 
    1006           0 :                 r = sd_bus_message_read_basic(m, type, &u);
    1007           0 :                 if (r < 0)
    1008           0 :                         break;
    1009             : 
    1010           0 :                 *p = u;
    1011             : 
    1012           0 :                 break;
    1013             :         }
    1014             : 
    1015             :         case SD_BUS_TYPE_UINT64: {
    1016             :                 uint64_t t;
    1017           0 :                 uint64_t *p = userdata;
    1018             : 
    1019           0 :                 r = sd_bus_message_read_basic(m, type, &t);
    1020           0 :                 if (r < 0)
    1021           0 :                         break;
    1022             : 
    1023           0 :                 *p = t;
    1024             : 
    1025           0 :                 break;
    1026             :         }
    1027             : 
    1028             :         default:
    1029           0 :                 break;
    1030             :         }
    1031             : 
    1032           0 :         return r;
    1033             : }
    1034             : 
    1035           0 : int bus_message_map_all_properties(
    1036             :                 sd_bus_message *m,
    1037             :                 const struct bus_properties_map *map,
    1038             :                 void *userdata) {
    1039             : 
    1040           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1041             :         int r;
    1042             : 
    1043           0 :         assert(m);
    1044           0 :         assert(map);
    1045             : 
    1046           0 :         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
    1047           0 :         if (r < 0)
    1048           0 :                 return r;
    1049             : 
    1050           0 :         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
    1051             :                 const struct bus_properties_map *prop;
    1052             :                 const char *member;
    1053             :                 const char *contents;
    1054             :                 void *v;
    1055             :                 unsigned i;
    1056             : 
    1057           0 :                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
    1058           0 :                 if (r < 0)
    1059           0 :                         return r;
    1060             : 
    1061           0 :                 for (i = 0, prop = NULL; map[i].member; i++)
    1062           0 :                         if (streq(map[i].member, member)) {
    1063           0 :                                 prop = &map[i];
    1064           0 :                                 break;
    1065             :                         }
    1066             : 
    1067           0 :                 if (prop) {
    1068           0 :                         r = sd_bus_message_peek_type(m, NULL, &contents);
    1069           0 :                         if (r < 0)
    1070           0 :                                 return r;
    1071             : 
    1072           0 :                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
    1073           0 :                         if (r < 0)
    1074           0 :                                 return r;
    1075             : 
    1076           0 :                         v = (uint8_t *)userdata + prop->offset;
    1077           0 :                         if (map[i].set)
    1078           0 :                                 r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v);
    1079             :                         else
    1080           0 :                                 r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v);
    1081           0 :                         if (r < 0)
    1082           0 :                                 return r;
    1083             : 
    1084           0 :                         r = sd_bus_message_exit_container(m);
    1085           0 :                         if (r < 0)
    1086           0 :                                 return r;
    1087             :                 } else {
    1088           0 :                         r = sd_bus_message_skip(m, "v");
    1089           0 :                         if (r < 0)
    1090           0 :                                 return r;
    1091             :                 }
    1092             : 
    1093           0 :                 r = sd_bus_message_exit_container(m);
    1094           0 :                 if (r < 0)
    1095           0 :                         return r;
    1096             :         }
    1097           0 :         if (r < 0)
    1098           0 :                 return r;
    1099             : 
    1100           0 :         return sd_bus_message_exit_container(m);
    1101             : }
    1102             : 
    1103           0 : int bus_message_map_properties_changed(
    1104             :                 sd_bus_message *m,
    1105             :                 const struct bus_properties_map *map,
    1106             :                 void *userdata) {
    1107             : 
    1108             :         const char *member;
    1109             :         int r, invalidated, i;
    1110             : 
    1111           0 :         assert(m);
    1112           0 :         assert(map);
    1113             : 
    1114           0 :         r = bus_message_map_all_properties(m, map, userdata);
    1115           0 :         if (r < 0)
    1116           0 :                 return r;
    1117             : 
    1118           0 :         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
    1119           0 :         if (r < 0)
    1120           0 :                 return r;
    1121             : 
    1122           0 :         invalidated = 0;
    1123           0 :         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
    1124           0 :                 for (i = 0; map[i].member; i++)
    1125           0 :                         if (streq(map[i].member, member)) {
    1126           0 :                                 ++invalidated;
    1127           0 :                                 break;
    1128             :                         }
    1129           0 :         if (r < 0)
    1130           0 :                 return r;
    1131             : 
    1132           0 :         r = sd_bus_message_exit_container(m);
    1133           0 :         if (r < 0)
    1134           0 :                 return r;
    1135             : 
    1136           0 :         return invalidated;
    1137             : }
    1138             : 
    1139           0 : int bus_map_all_properties(
    1140             :                 sd_bus *bus,
    1141             :                 const char *destination,
    1142             :                 const char *path,
    1143             :                 const struct bus_properties_map *map,
    1144             :                 void *userdata) {
    1145             : 
    1146           0 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
    1147           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1148             :         int r;
    1149             : 
    1150           0 :         assert(bus);
    1151           0 :         assert(destination);
    1152           0 :         assert(path);
    1153           0 :         assert(map);
    1154             : 
    1155           0 :         r = sd_bus_call_method(
    1156             :                         bus,
    1157             :                         destination,
    1158             :                         path,
    1159             :                         "org.freedesktop.DBus.Properties",
    1160             :                         "GetAll",
    1161             :                         &error,
    1162             :                         &m,
    1163             :                         "s", "");
    1164           0 :         if (r < 0)
    1165           0 :                 return r;
    1166             : 
    1167           0 :         return bus_message_map_all_properties(m, map, userdata);
    1168             : }
    1169             : 
    1170           0 : int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
    1171             :         int r;
    1172             : 
    1173           0 :         assert(transport >= 0);
    1174           0 :         assert(transport < _BUS_TRANSPORT_MAX);
    1175           0 :         assert(bus);
    1176             : 
    1177           0 :         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
    1178           0 :         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
    1179             : 
    1180           0 :         switch (transport) {
    1181             : 
    1182             :         case BUS_TRANSPORT_LOCAL:
    1183           0 :                 if (user)
    1184           0 :                         r = sd_bus_default_user(bus);
    1185             :                 else
    1186           0 :                         r = sd_bus_default_system(bus);
    1187             : 
    1188           0 :                 break;
    1189             : 
    1190             :         case BUS_TRANSPORT_REMOTE:
    1191           0 :                 r = sd_bus_open_system_remote(bus, host);
    1192           0 :                 break;
    1193             : 
    1194             :         case BUS_TRANSPORT_MACHINE:
    1195           0 :                 r = sd_bus_open_system_machine(bus, host);
    1196           0 :                 break;
    1197             : 
    1198             :         default:
    1199           0 :                 assert_not_reached("Hmm, unknown transport type.");
    1200             :         }
    1201             : 
    1202           0 :         return r;
    1203             : }
    1204             : 
    1205           0 : int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
    1206             :         int r;
    1207             : 
    1208           0 :         assert(transport >= 0);
    1209           0 :         assert(transport < _BUS_TRANSPORT_MAX);
    1210           0 :         assert(bus);
    1211             : 
    1212           0 :         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
    1213           0 :         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
    1214             : 
    1215           0 :         switch (transport) {
    1216             : 
    1217             :         case BUS_TRANSPORT_LOCAL:
    1218           0 :                 if (user)
    1219           0 :                         r = bus_open_user_systemd(bus);
    1220             :                 else
    1221           0 :                         r = bus_open_system_systemd(bus);
    1222             : 
    1223           0 :                 break;
    1224             : 
    1225             :         case BUS_TRANSPORT_REMOTE:
    1226           0 :                 r = sd_bus_open_system_remote(bus, host);
    1227           0 :                 break;
    1228             : 
    1229             :         case BUS_TRANSPORT_MACHINE:
    1230           0 :                 r = sd_bus_open_system_machine(bus, host);
    1231           0 :                 break;
    1232             : 
    1233             :         default:
    1234           0 :                 assert_not_reached("Hmm, unknown transport type.");
    1235             :         }
    1236             : 
    1237           0 :         return r;
    1238             : }
    1239             : 
    1240           0 : int bus_property_get_bool(
    1241             :                 sd_bus *bus,
    1242             :                 const char *path,
    1243             :                 const char *interface,
    1244             :                 const char *property,
    1245             :                 sd_bus_message *reply,
    1246             :                 void *userdata,
    1247             :                 sd_bus_error *error) {
    1248             : 
    1249           0 :         int b = *(bool*) userdata;
    1250             : 
    1251           0 :         return sd_bus_message_append_basic(reply, 'b', &b);
    1252             : }
    1253             : 
    1254             : #if __SIZEOF_SIZE_T__ != 8
    1255             : int bus_property_get_size(
    1256             :                 sd_bus *bus,
    1257             :                 const char *path,
    1258             :                 const char *interface,
    1259             :                 const char *property,
    1260             :                 sd_bus_message *reply,
    1261             :                 void *userdata,
    1262             :                 sd_bus_error *error) {
    1263             : 
    1264             :         uint64_t sz = *(size_t*) userdata;
    1265             : 
    1266             :         return sd_bus_message_append_basic(reply, 't', &sz);
    1267             : }
    1268             : #endif
    1269             : 
    1270             : #if __SIZEOF_LONG__ != 8
    1271             : int bus_property_get_long(
    1272             :                 sd_bus *bus,
    1273             :                 const char *path,
    1274             :                 const char *interface,
    1275             :                 const char *property,
    1276             :                 sd_bus_message *reply,
    1277             :                 void *userdata,
    1278             :                 sd_bus_error *error) {
    1279             : 
    1280             :         int64_t l = *(long*) userdata;
    1281             : 
    1282             :         return sd_bus_message_append_basic(reply, 'x', &l);
    1283             : }
    1284             : 
    1285             : int bus_property_get_ulong(
    1286             :                 sd_bus *bus,
    1287             :                 const char *path,
    1288             :                 const char *interface,
    1289             :                 const char *property,
    1290             :                 sd_bus_message *reply,
    1291             :                 void *userdata,
    1292             :                 sd_bus_error *error) {
    1293             : 
    1294             :         uint64_t ul = *(unsigned long*) userdata;
    1295             : 
    1296             :         return sd_bus_message_append_basic(reply, 't', &ul);
    1297             : }
    1298             : #endif
    1299             : 
    1300           0 : int bus_log_parse_error(int r) {
    1301           0 :         return log_error_errno(r, "Failed to parse bus message: %m");
    1302             : }
    1303             : 
    1304           0 : int bus_log_create_error(int r) {
    1305           0 :         return log_error_errno(r, "Failed to create bus message: %m");
    1306             : }
    1307             : 
    1308           0 : int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
    1309           0 :         assert(message);
    1310           0 :         assert(u);
    1311             : 
    1312           0 :         u->machine = NULL;
    1313             : 
    1314           0 :         return sd_bus_message_read(
    1315             :                         message,
    1316             :                         "(ssssssouso)",
    1317             :                         &u->id,
    1318             :                         &u->description,
    1319             :                         &u->load_state,
    1320             :                         &u->active_state,
    1321             :                         &u->sub_state,
    1322             :                         &u->following,
    1323             :                         &u->unit_path,
    1324             :                         &u->job_id,
    1325             :                         &u->job_type,
    1326             :                         &u->job_path);
    1327             : }
    1328             : 
    1329           0 : int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
    1330             :         const char *eq, *field;
    1331             :         int r;
    1332             : 
    1333           0 :         assert(m);
    1334           0 :         assert(assignment);
    1335             : 
    1336           0 :         eq = strchr(assignment, '=');
    1337           0 :         if (!eq) {
    1338           0 :                 log_error("Not an assignment: %s", assignment);
    1339           0 :                 return -EINVAL;
    1340             :         }
    1341             : 
    1342           0 :         field = strndupa(assignment, eq - assignment);
    1343           0 :         eq ++;
    1344             : 
    1345           0 :         if (streq(field, "CPUQuota")) {
    1346             : 
    1347           0 :                 if (isempty(eq)) {
    1348             : 
    1349           0 :                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
    1350           0 :                         if (r < 0)
    1351           0 :                                 return bus_log_create_error(r);
    1352             : 
    1353           0 :                         r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
    1354             : 
    1355           0 :                 } else if (endswith(eq, "%")) {
    1356             :                         double percent;
    1357             : 
    1358           0 :                         if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
    1359           0 :                                 log_error("CPU quota '%s' invalid.", eq);
    1360           0 :                                 return -EINVAL;
    1361             :                         }
    1362             : 
    1363           0 :                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
    1364           0 :                         if (r < 0)
    1365           0 :                                 return bus_log_create_error(r);
    1366             : 
    1367           0 :                         r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
    1368             :                 } else {
    1369           0 :                         log_error("CPU quota needs to be in percent.");
    1370           0 :                         return -EINVAL;
    1371             :                 }
    1372             : 
    1373           0 :                 if (r < 0)
    1374           0 :                         return bus_log_create_error(r);
    1375             : 
    1376           0 :                 return 0;
    1377             :         }
    1378             : 
    1379           0 :         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
    1380           0 :         if (r < 0)
    1381           0 :                 return bus_log_create_error(r);
    1382             : 
    1383           0 :         if (STR_IN_SET(field,
    1384             :                        "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
    1385             :                        "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies")) {
    1386             : 
    1387           0 :                 r = parse_boolean(eq);
    1388           0 :                 if (r < 0) {
    1389           0 :                         log_error("Failed to parse boolean assignment %s.", assignment);
    1390           0 :                         return -EINVAL;
    1391             :                 }
    1392             : 
    1393           0 :                 r = sd_bus_message_append(m, "v", "b", r);
    1394             : 
    1395           0 :         } else if (streq(field, "MemoryLimit")) {
    1396             :                 off_t bytes;
    1397             : 
    1398           0 :                 r = parse_size(eq, 1024, &bytes);
    1399           0 :                 if (r < 0) {
    1400           0 :                         log_error("Failed to parse bytes specification %s", assignment);
    1401           0 :                         return -EINVAL;
    1402             :                 }
    1403             : 
    1404           0 :                 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
    1405             : 
    1406           0 :         } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
    1407             :                 uint64_t u;
    1408             : 
    1409           0 :                 r = safe_atou64(eq, &u);
    1410           0 :                 if (r < 0) {
    1411           0 :                         log_error("Failed to parse %s value %s.", field, eq);
    1412           0 :                         return -EINVAL;
    1413             :                 }
    1414             : 
    1415           0 :                 r = sd_bus_message_append(m, "v", "t", u);
    1416             : 
    1417           0 :         } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
    1418           0 :                 r = sd_bus_message_append(m, "v", "s", eq);
    1419             : 
    1420           0 :         else if (streq(field, "DeviceAllow")) {
    1421             : 
    1422           0 :                 if (isempty(eq))
    1423           0 :                         r = sd_bus_message_append(m, "v", "a(ss)", 0);
    1424             :                 else {
    1425             :                         const char *path, *rwm, *e;
    1426             : 
    1427           0 :                         e = strchr(eq, ' ');
    1428           0 :                         if (e) {
    1429           0 :                                 path = strndupa(eq, e - eq);
    1430           0 :                                 rwm = e+1;
    1431             :                         } else {
    1432           0 :                                 path = eq;
    1433           0 :                                 rwm = "";
    1434             :                         }
    1435             : 
    1436           0 :                         if (!path_startswith(path, "/dev")) {
    1437           0 :                                 log_error("%s is not a device file in /dev.", path);
    1438           0 :                                 return -EINVAL;
    1439             :                         }
    1440             : 
    1441           0 :                         r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
    1442             :                 }
    1443             : 
    1444           0 :         } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
    1445             : 
    1446           0 :                 if (isempty(eq))
    1447           0 :                         r = sd_bus_message_append(m, "v", "a(st)", 0);
    1448             :                 else {
    1449             :                         const char *path, *bandwidth, *e;
    1450             :                         off_t bytes;
    1451             : 
    1452           0 :                         e = strchr(eq, ' ');
    1453           0 :                         if (e) {
    1454           0 :                                 path = strndupa(eq, e - eq);
    1455           0 :                                 bandwidth = e+1;
    1456             :                         } else {
    1457           0 :                                 log_error("Failed to parse %s value %s.", field, eq);
    1458           0 :                                 return -EINVAL;
    1459             :                         }
    1460             : 
    1461           0 :                         if (!path_startswith(path, "/dev")) {
    1462           0 :                                 log_error("%s is not a device file in /dev.", path);
    1463           0 :                                 return -EINVAL;
    1464             :                         }
    1465             : 
    1466           0 :                         r = parse_size(bandwidth, 1000, &bytes);
    1467           0 :                         if (r < 0) {
    1468           0 :                                 log_error("Failed to parse byte value %s.", bandwidth);
    1469           0 :                                 return -EINVAL;
    1470             :                         }
    1471             : 
    1472           0 :                         r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
    1473             :                 }
    1474             : 
    1475           0 :         } else if (streq(field, "BlockIODeviceWeight")) {
    1476             : 
    1477           0 :                 if (isempty(eq))
    1478           0 :                         r = sd_bus_message_append(m, "v", "a(st)", 0);
    1479             :                 else {
    1480             :                         const char *path, *weight, *e;
    1481             :                         uint64_t u;
    1482             : 
    1483           0 :                         e = strchr(eq, ' ');
    1484           0 :                         if (e) {
    1485           0 :                                 path = strndupa(eq, e - eq);
    1486           0 :                                 weight = e+1;
    1487             :                         } else {
    1488           0 :                                 log_error("Failed to parse %s value %s.", field, eq);
    1489           0 :                                 return -EINVAL;
    1490             :                         }
    1491             : 
    1492           0 :                         if (!path_startswith(path, "/dev")) {
    1493           0 :                                 log_error("%s is not a device file in /dev.", path);
    1494           0 :                                 return -EINVAL;
    1495             :                         }
    1496             : 
    1497           0 :                         r = safe_atou64(weight, &u);
    1498           0 :                         if (r < 0) {
    1499           0 :                                 log_error("Failed to parse %s value %s.", field, weight);
    1500           0 :                                 return -EINVAL;
    1501             :                         }
    1502           0 :                         r = sd_bus_message_append(m, "v", "a(st)", path, u);
    1503             :                 }
    1504             : 
    1505           0 :         } else if (rlimit_from_string(field) >= 0) {
    1506             :                 uint64_t rl;
    1507             : 
    1508           0 :                 if (streq(eq, "infinity"))
    1509           0 :                         rl = (uint64_t) -1;
    1510             :                 else {
    1511           0 :                         r = safe_atou64(eq, &rl);
    1512           0 :                         if (r < 0) {
    1513           0 :                                 log_error("Invalid resource limit: %s", eq);
    1514           0 :                                 return -EINVAL;
    1515             :                         }
    1516             :                 }
    1517             : 
    1518           0 :                 r = sd_bus_message_append(m, "v", "t", rl);
    1519             : 
    1520           0 :         } else if (streq(field, "Nice")) {
    1521             :                 int32_t i;
    1522             : 
    1523           0 :                 r = safe_atoi32(eq, &i);
    1524           0 :                 if (r < 0) {
    1525           0 :                         log_error("Failed to parse %s value %s.", field, eq);
    1526           0 :                         return -EINVAL;
    1527             :                 }
    1528             : 
    1529           0 :                 r = sd_bus_message_append(m, "v", "i", i);
    1530             : 
    1531           0 :         } else if (streq(field, "Environment")) {
    1532             : 
    1533           0 :                 r = sd_bus_message_append(m, "v", "as", 1, eq);
    1534             : 
    1535           0 :         } else if (streq(field, "KillSignal")) {
    1536             :                 int sig;
    1537             : 
    1538           0 :                 sig = signal_from_string_try_harder(eq);
    1539           0 :                 if (sig < 0) {
    1540           0 :                         log_error("Failed to parse %s value %s.", field, eq);
    1541           0 :                         return -EINVAL;
    1542             :                 }
    1543             : 
    1544           0 :                 r = sd_bus_message_append(m, "v", "i", sig);
    1545             : 
    1546           0 :         } else if (streq(field, "AccuracySec")) {
    1547             :                 usec_t u;
    1548             : 
    1549           0 :                 r = parse_sec(eq, &u);
    1550           0 :                 if (r < 0) {
    1551           0 :                         log_error("Failed to parse %s value %s", field, eq);
    1552           0 :                         return -EINVAL;
    1553             :                 }
    1554             : 
    1555           0 :                 r = sd_bus_message_append(m, "v", "t", u);
    1556             : 
    1557             :         } else {
    1558           0 :                 log_error("Unknown assignment %s.", assignment);
    1559           0 :                 return -EINVAL;
    1560             :         }
    1561             : 
    1562           0 :         if (r < 0)
    1563           0 :                 return bus_log_create_error(r);
    1564             : 
    1565           0 :         return 0;
    1566             : }
    1567             : 
    1568             : typedef struct BusWaitForJobs {
    1569             :         sd_bus *bus;
    1570             :         Set *jobs;
    1571             : 
    1572             :         char *name;
    1573             :         char *result;
    1574             : 
    1575             :         sd_bus_slot *slot_job_removed;
    1576             :         sd_bus_slot *slot_disconnected;
    1577             : } BusWaitForJobs;
    1578             : 
    1579           0 : static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
    1580           0 :         assert(m);
    1581             : 
    1582           0 :         log_error("Warning! D-Bus connection terminated.");
    1583           0 :         sd_bus_close(sd_bus_message_get_bus(m));
    1584             : 
    1585           0 :         return 0;
    1586             : }
    1587             : 
    1588           0 : static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
    1589             :         const char *path, *unit, *result;
    1590           0 :         BusWaitForJobs *d = userdata;
    1591             :         uint32_t id;
    1592             :         char *found;
    1593             :         int r;
    1594             : 
    1595           0 :         assert(m);
    1596           0 :         assert(d);
    1597             : 
    1598           0 :         r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
    1599           0 :         if (r < 0) {
    1600           0 :                 bus_log_parse_error(r);
    1601           0 :                 return 0;
    1602             :         }
    1603             : 
    1604           0 :         found = set_remove(d->jobs, (char*) path);
    1605           0 :         if (!found)
    1606           0 :                 return 0;
    1607             : 
    1608           0 :         free(found);
    1609             : 
    1610           0 :         if (!isempty(result))
    1611           0 :                 d->result = strdup(result);
    1612             : 
    1613           0 :         if (!isempty(unit))
    1614           0 :                 d->name = strdup(unit);
    1615             : 
    1616           0 :         return 0;
    1617             : }
    1618             : 
    1619           0 : void bus_wait_for_jobs_free(BusWaitForJobs *d) {
    1620           0 :         if (!d)
    1621           0 :                 return;
    1622             : 
    1623           0 :         set_free_free(d->jobs);
    1624             : 
    1625           0 :         sd_bus_slot_unref(d->slot_disconnected);
    1626           0 :         sd_bus_slot_unref(d->slot_job_removed);
    1627             : 
    1628           0 :         sd_bus_unref(d->bus);
    1629             : 
    1630           0 :         free(d->name);
    1631           0 :         free(d->result);
    1632             : 
    1633           0 :         free(d);
    1634             : }
    1635             : 
    1636           0 : int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
    1637           0 :         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
    1638             :         int r;
    1639             : 
    1640           0 :         assert(bus);
    1641           0 :         assert(ret);
    1642             : 
    1643           0 :         d = new0(BusWaitForJobs, 1);
    1644           0 :         if (!d)
    1645           0 :                 return -ENOMEM;
    1646             : 
    1647           0 :         d->bus = sd_bus_ref(bus);
    1648             : 
    1649             :         /* When we are a bus client we match by sender. Direct
    1650             :          * connections OTOH have no initialized sender field, and
    1651             :          * hence we ignore the sender then */
    1652           0 :         r = sd_bus_add_match(
    1653             :                         bus,
    1654           0 :                         &d->slot_job_removed,
    1655           0 :                         bus->bus_client ?
    1656             :                         "type='signal',"
    1657             :                         "sender='org.freedesktop.systemd1',"
    1658             :                         "interface='org.freedesktop.systemd1.Manager',"
    1659             :                         "member='JobRemoved',"
    1660             :                         "path='/org/freedesktop/systemd1'" :
    1661             :                         "type='signal',"
    1662             :                         "interface='org.freedesktop.systemd1.Manager',"
    1663             :                         "member='JobRemoved',"
    1664             :                         "path='/org/freedesktop/systemd1'",
    1665             :                         match_job_removed, d);
    1666           0 :         if (r < 0)
    1667           0 :                 return r;
    1668             : 
    1669           0 :         r = sd_bus_add_match(
    1670             :                         bus,
    1671           0 :                         &d->slot_disconnected,
    1672             :                         "type='signal',"
    1673             :                         "sender='org.freedesktop.DBus.Local',"
    1674             :                         "interface='org.freedesktop.DBus.Local',"
    1675             :                         "member='Disconnected'",
    1676             :                         match_disconnected, d);
    1677           0 :         if (r < 0)
    1678           0 :                 return r;
    1679             : 
    1680           0 :         *ret = d;
    1681           0 :         d = NULL;
    1682             : 
    1683           0 :         return 0;
    1684             : }
    1685             : 
    1686           0 : static int bus_process_wait(sd_bus *bus) {
    1687             :         int r;
    1688             : 
    1689             :         for (;;) {
    1690           0 :                 r = sd_bus_process(bus, NULL);
    1691           0 :                 if (r < 0)
    1692           0 :                         return r;
    1693           0 :                 if (r > 0)
    1694           0 :                         return 0;
    1695             : 
    1696           0 :                 r = sd_bus_wait(bus, (uint64_t) -1);
    1697           0 :                 if (r < 0)
    1698           0 :                         return r;
    1699           0 :         }
    1700             : }
    1701             : 
    1702           0 : static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
    1703           0 :         _cleanup_free_ char *dbus_path = NULL;
    1704             : 
    1705           0 :         assert(d);
    1706           0 :         assert(d->name);
    1707           0 :         assert(result);
    1708             : 
    1709           0 :         dbus_path = unit_dbus_path_from_name(d->name);
    1710           0 :         if (!dbus_path)
    1711           0 :                 return -ENOMEM;
    1712             : 
    1713           0 :         return sd_bus_get_property_string(d->bus,
    1714             :                                           "org.freedesktop.systemd1",
    1715             :                                           dbus_path,
    1716             :                                           "org.freedesktop.systemd1.Service",
    1717             :                                           "Result",
    1718             :                                           NULL,
    1719             :                                           result);
    1720             : }
    1721             : 
    1722             : static const struct {
    1723             :         const char *result, *explanation;
    1724             : } explanations [] = {
    1725             :         { "resources",   "a configured resource limit was exceeded" },
    1726             :         { "timeout",     "a timeout was exceeded" },
    1727             :         { "exit-code",   "the control process exited with error code" },
    1728             :         { "signal",      "a fatal signal was delivered to the control process" },
    1729             :         { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
    1730             :         { "watchdog",    "the service failed to send watchdog ping" },
    1731             :         { "start-limit", "start of the service was attempted too often" }
    1732             : };
    1733             : 
    1734           0 : static void log_job_error_with_service_result(const char* service, const char *result) {
    1735           0 :         _cleanup_free_ char *service_shell_quoted = NULL;
    1736             : 
    1737           0 :         assert(service);
    1738             : 
    1739           0 :         service_shell_quoted = shell_maybe_quote(service);
    1740             : 
    1741           0 :         if (!isempty(result)) {
    1742             :                 unsigned i;
    1743             : 
    1744           0 :                 for (i = 0; i < ELEMENTSOF(explanations); ++i)
    1745           0 :                         if (streq(result, explanations[i].result))
    1746           0 :                                 break;
    1747             : 
    1748           0 :                 if (i < ELEMENTSOF(explanations)) {
    1749           0 :                         log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
    1750             :                                   service,
    1751             :                                   explanations[i].explanation,
    1752             :                                   strna(service_shell_quoted));
    1753             : 
    1754           0 :                         goto finish;
    1755             :                 }
    1756             :         }
    1757             : 
    1758           0 :         log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
    1759             :                   service,
    1760             :                   strna(service_shell_quoted));
    1761             : 
    1762             : finish:
    1763             :         /* For some results maybe additional explanation is required */
    1764           0 :         if (streq_ptr(result, "start-limit"))
    1765           0 :                 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
    1766             :                          strna(service_shell_quoted));
    1767           0 : }
    1768             : 
    1769           0 : static int check_wait_response(BusWaitForJobs *d, bool quiet) {
    1770           0 :         int r = 0;
    1771             : 
    1772           0 :         assert(d->result);
    1773             : 
    1774           0 :         if (!quiet) {
    1775           0 :                 if (streq(d->result, "canceled"))
    1776           0 :                         log_error("Job for %s canceled.", strna(d->name));
    1777           0 :                 else if (streq(d->result, "timeout"))
    1778           0 :                         log_error("Job for %s timed out.", strna(d->name));
    1779           0 :                 else if (streq(d->result, "dependency"))
    1780           0 :                         log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
    1781           0 :                 else if (streq(d->result, "invalid"))
    1782           0 :                         log_error("Job for %s invalid.", strna(d->name));
    1783           0 :                 else if (streq(d->result, "assert"))
    1784           0 :                         log_error("Assertion failed on job for %s.", strna(d->name));
    1785           0 :                 else if (streq(d->result, "unsupported"))
    1786           0 :                         log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
    1787           0 :                 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
    1788           0 :                         if (d->name) {
    1789             :                                 int q;
    1790           0 :                                 _cleanup_free_ char *result = NULL;
    1791             : 
    1792           0 :                                 q = bus_job_get_service_result(d, &result);
    1793           0 :                                 if (q < 0)
    1794           0 :                                         log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
    1795             : 
    1796           0 :                                 log_job_error_with_service_result(d->name, result);
    1797             :                         } else
    1798           0 :                                 log_error("Job failed. See \"journalctl -xe\" for details.");
    1799             :                 }
    1800             :         }
    1801             : 
    1802           0 :         if (streq(d->result, "canceled"))
    1803           0 :                 r = -ECANCELED;
    1804           0 :         else if (streq(d->result, "timeout"))
    1805           0 :                 r = -ETIME;
    1806           0 :         else if (streq(d->result, "dependency"))
    1807           0 :                 r = -EIO;
    1808           0 :         else if (streq(d->result, "invalid"))
    1809           0 :                 r = -ENOEXEC;
    1810           0 :         else if (streq(d->result, "assert"))
    1811           0 :                 r = -EPROTO;
    1812           0 :         else if (streq(d->result, "unsupported"))
    1813           0 :                 r = -EOPNOTSUPP;
    1814           0 :         else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
    1815           0 :                 r = -EIO;
    1816             : 
    1817           0 :         return r;
    1818             : }
    1819             : 
    1820           0 : int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
    1821           0 :         int r = 0;
    1822             : 
    1823           0 :         assert(d);
    1824             : 
    1825           0 :         while (!set_isempty(d->jobs)) {
    1826             :                 int q;
    1827             : 
    1828           0 :                 q = bus_process_wait(d->bus);
    1829           0 :                 if (q < 0)
    1830           0 :                         return log_error_errno(q, "Failed to wait for response: %m");
    1831             : 
    1832           0 :                 if (d->result) {
    1833           0 :                         q = check_wait_response(d, quiet);
    1834             :                         /* Return the first error as it is most likely to be
    1835             :                          * meaningful. */
    1836           0 :                         if (q < 0 && r == 0)
    1837           0 :                                 r = q;
    1838             : 
    1839           0 :                         log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
    1840             :                 }
    1841             : 
    1842           0 :                 free(d->name);
    1843           0 :                 d->name = NULL;
    1844             : 
    1845           0 :                 free(d->result);
    1846           0 :                 d->result = NULL;
    1847             :         }
    1848             : 
    1849           0 :         return r;
    1850             : }
    1851             : 
    1852           0 : int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
    1853             :         int r;
    1854             : 
    1855           0 :         assert(d);
    1856             : 
    1857           0 :         r = set_ensure_allocated(&d->jobs, &string_hash_ops);
    1858           0 :         if (r < 0)
    1859           0 :                 return r;
    1860             : 
    1861           0 :         return set_put_strdup(d->jobs, path);
    1862             : }
    1863             : 
    1864           0 : int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
    1865             :         int r;
    1866             : 
    1867           0 :         r = bus_wait_for_jobs_add(d, path);
    1868           0 :         if (r < 0)
    1869           0 :                 return log_oom();
    1870             : 
    1871           0 :         return bus_wait_for_jobs(d, quiet);
    1872             : }
    1873             : 
    1874           0 : int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
    1875             :         const char *type, *path, *source;
    1876             :         int r;
    1877             : 
    1878           0 :         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
    1879           0 :         if (r < 0)
    1880           0 :                 return bus_log_parse_error(r);
    1881             : 
    1882           0 :         while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
    1883           0 :                 if (!quiet) {
    1884           0 :                         if (streq(type, "symlink"))
    1885           0 :                                 log_info("Created symlink from %s to %s.", path, source);
    1886             :                         else
    1887           0 :                                 log_info("Removed symlink %s.", path);
    1888             :                 }
    1889             : 
    1890           0 :                 r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
    1891           0 :                 if (r < 0)
    1892           0 :                         return r;
    1893             :         }
    1894           0 :         if (r < 0)
    1895           0 :                 return bus_log_parse_error(r);
    1896             : 
    1897           0 :         r = sd_bus_message_exit_container(m);
    1898           0 :         if (r < 0)
    1899           0 :                 return bus_log_parse_error(r);
    1900             : 
    1901           0 :         return 0;
    1902             : }
    1903             : 
    1904             : /**
    1905             :  * bus_path_encode_unique() - encode unique object path
    1906             :  * @b: bus connection or NULL
    1907             :  * @prefix: object path prefix
    1908             :  * @sender_id: unique-name of client, or NULL
    1909             :  * @external_id: external ID to be chosen by client, or NULL
    1910             :  * @ret_path: storage for encoded object path pointer
    1911             :  *
    1912             :  * Whenever we provide a bus API that allows clients to create and manage
    1913             :  * server-side objects, we need to provide a unique name for these objects. If
    1914             :  * we let the server choose the name, we suffer from a race condition: If a
    1915             :  * client creates an object asynchronously, it cannot destroy that object until
    1916             :  * it received the method reply. It cannot know the name of the new object,
    1917             :  * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
    1918             :  *
    1919             :  * Therefore, many APIs allow the client to choose the unique name for newly
    1920             :  * created objects. There're two problems to solve, though:
    1921             :  *    1) Object names are usually defined via dbus object paths, which are
    1922             :  *       usually globally namespaced. Therefore, multiple clients must be able
    1923             :  *       to choose unique object names without interference.
    1924             :  *    2) If multiple libraries share the same bus connection, they must be
    1925             :  *       able to choose unique object names without interference.
    1926             :  * The first problem is solved easily by prefixing a name with the
    1927             :  * unique-bus-name of a connection. The server side must enforce this and
    1928             :  * reject any other name. The second problem is solved by providing unique
    1929             :  * suffixes from within sd-bus.
    1930             :  *
    1931             :  * This helper allows clients to create unique object-paths. It uses the
    1932             :  * template '/prefix/sender_id/external_id' and returns the new path in
    1933             :  * @ret_path (must be freed by the caller).
    1934             :  * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
    1935             :  * NULL, this function allocates a unique suffix via @b (by requesting a new
    1936             :  * cookie). If both @sender_id and @external_id are given, @b can be passed as
    1937             :  * NULL.
    1938             :  *
    1939             :  * Returns: 0 on success, negative error code on failure.
    1940             :  */
    1941           1 : int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
    1942           2 :         _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
    1943             :         char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
    1944             :         int r;
    1945             : 
    1946           1 :         assert_return(b || (sender_id && external_id), -EINVAL);
    1947           1 :         assert_return(object_path_is_valid(prefix), -EINVAL);
    1948           1 :         assert_return(ret_path, -EINVAL);
    1949             : 
    1950           1 :         if (!sender_id) {
    1951           0 :                 r = sd_bus_get_unique_name(b, &sender_id);
    1952           0 :                 if (r < 0)
    1953           0 :                         return r;
    1954             :         }
    1955             : 
    1956           1 :         if (!external_id) {
    1957           0 :                 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
    1958           0 :                 external_id = external_buf;
    1959             :         }
    1960             : 
    1961           1 :         sender_label = bus_label_escape(sender_id);
    1962           1 :         if (!sender_label)
    1963           0 :                 return -ENOMEM;
    1964             : 
    1965           1 :         external_label = bus_label_escape(external_id);
    1966           1 :         if (!external_label)
    1967           0 :                 return -ENOMEM;
    1968             : 
    1969           1 :         p = strjoin(prefix, "/", sender_label, "/", external_label, NULL);
    1970           1 :         if (!p)
    1971           0 :                 return -ENOMEM;
    1972             : 
    1973           1 :         *ret_path = p;
    1974           1 :         return 0;
    1975             : }
    1976             : 
    1977             : /**
    1978             :  * bus_path_decode_unique() - decode unique object path
    1979             :  * @path: object path to decode
    1980             :  * @prefix: object path prefix
    1981             :  * @ret_sender: output parameter for sender-id label
    1982             :  * @ret_external: output parameter for external-id label
    1983             :  *
    1984             :  * This does the reverse of bus_path_encode_unique() (see its description for
    1985             :  * details). Both trailing labels, sender-id and external-id, are unescaped and
    1986             :  * returned in the given output parameters (the caller must free them).
    1987             :  *
    1988             :  * Note that this function returns 0 if the path does not match the template
    1989             :  * (see bus_path_encode_unique()), 1 if it matched.
    1990             :  *
    1991             :  * Returns: Negative error code on failure, 0 if the given object path does not
    1992             :  *          match the template (return parameters are set to NULL), 1 if it was
    1993             :  *          parsed successfully (return parameters contain allocated labels).
    1994             :  */
    1995           4 : int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
    1996             :         const char *p, *q;
    1997             :         char *sender, *external;
    1998             : 
    1999           4 :         assert(object_path_is_valid(path));
    2000           4 :         assert(object_path_is_valid(prefix));
    2001           4 :         assert(ret_sender);
    2002           4 :         assert(ret_external);
    2003             : 
    2004           4 :         p = object_path_startswith(path, prefix);
    2005           4 :         if (!p) {
    2006           1 :                 *ret_sender = NULL;
    2007           1 :                 *ret_external = NULL;
    2008           1 :                 return 0;
    2009             :         }
    2010             : 
    2011           3 :         q = strchr(p, '/');
    2012           3 :         if (!q) {
    2013           1 :                 *ret_sender = NULL;
    2014           1 :                 *ret_external = NULL;
    2015           1 :                 return 0;
    2016             :         }
    2017             : 
    2018           2 :         sender = bus_label_unescape_n(p, q - p);
    2019           2 :         external = bus_label_unescape(q + 1);
    2020           2 :         if (!sender || !external) {
    2021           0 :                 free(sender);
    2022           0 :                 free(external);
    2023           0 :                 return -ENOMEM;
    2024             :         }
    2025             : 
    2026           2 :         *ret_sender = sender;
    2027           2 :         *ret_external = external;
    2028           2 :         return 1;
    2029             : }
    2030             : 
    2031           4 : bool is_kdbus_wanted(void) {
    2032           8 :         _cleanup_free_ char *value = NULL;
    2033             : #ifdef ENABLE_KDBUS
    2034           4 :         const bool configured = true;
    2035             : #else
    2036             :         const bool configured = false;
    2037             : #endif
    2038             : 
    2039             :         int r;
    2040             : 
    2041           4 :         if (get_proc_cmdline_key("kdbus", NULL) > 0)
    2042           4 :                 return true;
    2043             : 
    2044           0 :         r = get_proc_cmdline_key("kdbus=", &value);
    2045           0 :         if (r <= 0)
    2046           0 :                 return configured;
    2047             : 
    2048           0 :         return parse_boolean(value) == 1;
    2049             : }
    2050             : 
    2051           4 : bool is_kdbus_available(void) {
    2052           8 :         _cleanup_close_ int fd = -1;
    2053           4 :         struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE };
    2054             : 
    2055           4 :         if (!is_kdbus_wanted())
    2056           0 :                 return false;
    2057             : 
    2058           4 :         fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
    2059           4 :         if (fd < 0)
    2060           0 :                 return false;
    2061             : 
    2062           4 :         return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
    2063             : }

Generated by: LCOV version 1.11