1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
22 #include <sys/socket.h>
24 #include "sd-daemon.h"
30 #include "path-util.h"
35 #include "bus-error.h"
36 #include "bus-message.h"
38 #include "bus-internal.h"
40 static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
41 sd_event *e = userdata;
53 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
54 _cleanup_free_ char *match = NULL;
62 /* We unregister the name here and then wait for the
63 * NameOwnerChanged signal for this event to arrive before we
64 * quit. We do this in order to make sure that any queued
65 * requests are still processed before we really exit. */
67 r = sd_bus_get_unique_name(bus, &unique);
72 "sender='org.freedesktop.DBus',"
74 "interface='org.freedesktop.DBus',"
75 "member='NameOwnerChanged',"
76 "path='/org/freedesktop/DBus',"
79 "arg2=''", name, unique);
83 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
87 r = sd_bus_release_name(bus, name);
94 int bus_event_loop_with_idle(
99 check_idle_t check_idle,
101 bool exiting = false;
111 r = sd_event_get_state(e);
114 if (r == SD_EVENT_FINISHED)
118 idle = check_idle(userdata);
122 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
126 if (r == 0 && !exiting) {
128 r = sd_bus_try_close(bus);
132 /* Fallback for dbus1 connections: we
133 * unregister the name and wait for the
134 * response to come through for it */
137 /* Inform the service manager that we
138 * are going down, so that it will
139 * queue all further start requests,
140 * instead of assuming we are already
142 sd_notify(false, "STOPPING=1");
144 r = bus_async_unregister_and_exit(e, bus, name);
160 r = sd_event_get_exit_code(e, &code);
167 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
168 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
169 int r, has_owner = 0;
174 r = sd_bus_call_method(c,
175 "org.freedesktop.DBus",
176 "/org/freedesktop/dbus",
177 "org.freedesktop.DBus",
186 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
188 return sd_bus_error_set_errno(error, r);
193 int bus_verify_polkit(
194 sd_bus_message *call,
206 r = sd_bus_query_sender_privilege(call, capability);
213 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
214 int authorized = false, challenge = false, c;
217 sender = sd_bus_message_get_sender(call);
221 c = sd_bus_message_get_allow_interactive_authorization(call);
227 r = sd_bus_call_method(
229 "org.freedesktop.PolicyKit1",
230 "/org/freedesktop/PolicyKit1/Authority",
231 "org.freedesktop.PolicyKit1.Authority",
232 "CheckAuthorization",
236 "system-bus-name", 1, "name", "s", sender,
243 /* Treat no PK available as access denied */
244 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
245 sd_bus_error_free(e);
252 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
256 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
264 *_challenge = challenge;
275 typedef struct AsyncPolkitQuery {
276 sd_bus_message *request, *reply;
277 sd_bus_message_handler_t callback;
283 static void async_polkit_query_free(AsyncPolkitQuery *q) {
288 sd_bus_slot_unref(q->slot);
290 if (q->registry && q->request)
291 hashmap_remove(q->registry, q->request);
293 sd_bus_message_unref(q->request);
294 sd_bus_message_unref(q->reply);
299 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
300 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
301 AsyncPolkitQuery *q = userdata;
308 q->slot = sd_bus_slot_unref(q->slot);
309 q->reply = sd_bus_message_ref(reply);
311 r = sd_bus_message_rewind(q->request, true);
313 r = sd_bus_reply_method_errno(q->request, r, NULL);
317 r = q->callback(bus, q->request, q->userdata, &error_buffer);
318 r = bus_maybe_reply_error(q->request, r, &error_buffer);
321 async_polkit_query_free(q);
328 int bus_verify_polkit_async(
329 sd_bus_message *call,
334 sd_bus_error *error) {
337 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
340 sd_bus_message_handler_t callback;
351 q = hashmap_get(*registry, call);
353 int authorized, challenge;
355 /* This is the second invocation of this function, and
356 * there's already a response from polkit, let's
360 if (sd_bus_message_is_method_error(q->reply, NULL)) {
361 const sd_bus_error *e;
363 /* Copy error from polkit reply */
364 e = sd_bus_message_get_error(q->reply);
365 sd_bus_error_copy(error, e);
367 /* Treat no PK available as access denied */
368 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
371 return -sd_bus_error_get_errno(e);
374 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
376 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
385 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
391 r = sd_bus_query_sender_privilege(call, capability);
398 if (sd_bus_get_current_message(call->bus) != call)
401 callback = sd_bus_get_current_handler(call->bus);
405 userdata = sd_bus_get_current_userdata(call->bus);
407 sender = sd_bus_message_get_sender(call);
411 c = sd_bus_message_get_allow_interactive_authorization(call);
417 r = hashmap_ensure_allocated(registry, NULL);
421 r = sd_bus_message_new_method_call(
424 "org.freedesktop.PolicyKit1",
425 "/org/freedesktop/PolicyKit1/Authority",
426 "org.freedesktop.PolicyKit1.Authority",
427 "CheckAuthorization");
431 r = sd_bus_message_append(
434 "system-bus-name", 1, "name", "s", sender,
442 q = new0(AsyncPolkitQuery, 1);
446 q->request = sd_bus_message_ref(call);
447 q->callback = callback;
448 q->userdata = userdata;
450 r = hashmap_put(*registry, call, q);
452 async_polkit_query_free(q);
456 q->registry = *registry;
458 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
460 async_polkit_query_free(q);
470 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
474 while ((q = hashmap_steal_first(registry)))
475 async_polkit_query_free(q);
477 hashmap_free(registry);
481 int bus_check_peercred(sd_bus *c) {
488 fd = sd_bus_get_fd(c);
492 l = sizeof(struct ucred);
493 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
496 if (l != sizeof(struct ucred))
499 if (ucred.uid != 0 && ucred.uid != geteuid())
505 int bus_open_system_systemd(sd_bus **_bus) {
506 _cleanup_bus_unref_ sd_bus *bus = NULL;
512 return sd_bus_open_system(_bus);
514 /* If we are root and kdbus is not available, then let's talk
515 * directly to the system instance, instead of going via the
519 r = sd_bus_new(&bus);
523 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
527 bus->bus_client = true;
529 r = sd_bus_start(bus);
536 bus = sd_bus_unref(bus);
539 r = sd_bus_new(&bus);
543 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
547 r = sd_bus_start(bus);
549 return sd_bus_open_system(_bus);
551 r = bus_check_peercred(bus);
561 int bus_open_user_systemd(sd_bus **_bus) {
562 _cleanup_bus_unref_ sd_bus *bus = NULL;
563 _cleanup_free_ char *ee = NULL;
567 /* Try via kdbus first, and then directly */
572 r = sd_bus_new(&bus);
576 if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
579 bus->bus_client = true;
581 r = sd_bus_start(bus);
588 bus = sd_bus_unref(bus);
591 e = secure_getenv("XDG_RUNTIME_DIR");
593 return sd_bus_open_user(_bus);
595 ee = bus_address_escape(e);
599 r = sd_bus_new(&bus);
603 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
607 r = sd_bus_start(bus);
609 return sd_bus_open_user(_bus);
611 r = bus_check_peercred(bus);
621 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
623 const char *contents;
629 r = sd_bus_message_peek_type(property, &type, &contents);
635 case SD_BUS_TYPE_STRING: {
638 r = sd_bus_message_read_basic(property, type, &s);
642 if (all || !isempty(s)) {
643 _cleanup_free_ char *escaped = NULL;
645 escaped = xescape(s, "\n");
649 printf("%s=%s\n", name, escaped);
655 case SD_BUS_TYPE_BOOLEAN: {
658 r = sd_bus_message_read_basic(property, type, &b);
662 printf("%s=%s\n", name, yes_no(b));
667 case SD_BUS_TYPE_UINT64: {
670 r = sd_bus_message_read_basic(property, type, &u);
674 /* Yes, heuristics! But we can change this check
675 * should it turn out to not be sufficient */
677 if (endswith(name, "Timestamp")) {
678 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
680 t = format_timestamp(timestamp, sizeof(timestamp), u);
682 printf("%s=%s\n", name, strempty(t));
684 } else if (strstr(name, "USec")) {
685 char timespan[FORMAT_TIMESPAN_MAX];
687 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
689 printf("%s=%llu\n", name, (unsigned long long) u);
694 case SD_BUS_TYPE_UINT32: {
697 r = sd_bus_message_read_basic(property, type, &u);
701 if (strstr(name, "UMask") || strstr(name, "Mode"))
702 printf("%s=%04o\n", name, u);
704 printf("%s=%u\n", name, (unsigned) u);
709 case SD_BUS_TYPE_INT32: {
712 r = sd_bus_message_read_basic(property, type, &i);
716 printf("%s=%i\n", name, (int) i);
720 case SD_BUS_TYPE_DOUBLE: {
723 r = sd_bus_message_read_basic(property, type, &d);
727 printf("%s=%g\n", name, d);
731 case SD_BUS_TYPE_ARRAY:
732 if (streq(contents, "s")) {
736 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
740 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
741 _cleanup_free_ char *escaped = NULL;
746 escaped = xescape(str, "\n ");
750 printf("%s%s", first ? "" : " ", escaped);
762 r = sd_bus_message_exit_container(property);
768 } else if (streq(contents, "y")) {
772 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
781 for (i = 0; i < n; i++)
782 printf("%02x", u[i]);
789 } else if (streq(contents, "u")) {
793 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
802 for (i = 0; i < n; i++)
803 printf("%08x", u[i]);
817 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
818 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
819 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
825 r = sd_bus_call_method(bus,
828 "org.freedesktop.DBus.Properties",
836 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
840 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
842 const char *contents;
844 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
848 if (!filter || strv_find(filter, name)) {
849 r = sd_bus_message_peek_type(reply, NULL, &contents);
853 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
857 r = bus_print_property(name, reply, all);
862 printf("%s=[unprintable]\n", name);
863 /* skip what we didn't read */
864 r = sd_bus_message_skip(reply, contents);
869 r = sd_bus_message_exit_container(reply);
873 r = sd_bus_message_skip(reply, "v");
878 r = sd_bus_message_exit_container(reply);
885 r = sd_bus_message_exit_container(reply);
892 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
893 sd_id128_t *p = userdata;
898 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
905 memcpy((*p).bytes, v, n);
912 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
916 r = sd_bus_message_peek_type(m, &type, NULL);
921 case SD_BUS_TYPE_STRING: {
926 r = sd_bus_message_read_basic(m, type, &s);
944 case SD_BUS_TYPE_ARRAY: {
945 _cleanup_strv_free_ char **l = NULL;
946 char ***p = userdata;
948 r = bus_message_read_strv_extend(m, &l);
959 case SD_BUS_TYPE_BOOLEAN: {
963 r = sd_bus_message_read_basic(m, type, &b);
972 case SD_BUS_TYPE_UINT32: {
974 uint32_t *p = userdata;
976 r = sd_bus_message_read_basic(m, type, &u);
985 case SD_BUS_TYPE_UINT64: {
987 uint64_t *p = userdata;
989 r = sd_bus_message_read_basic(m, type, &t);
1005 int bus_message_map_all_properties(sd_bus *bus,
1007 const struct bus_properties_map *map,
1009 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1016 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1020 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1021 const struct bus_properties_map *prop;
1023 const char *contents;
1027 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1031 for (i = 0, prop = NULL; map[i].member; i++)
1032 if (streq(map[i].member, member)) {
1038 r = sd_bus_message_peek_type(m, NULL, &contents);
1042 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1046 v = (uint8_t *)userdata + prop->offset;
1048 r = prop->set(bus, member, m, &error, v);
1050 r = map_basic(bus, member, m, &error, v);
1054 r = sd_bus_message_exit_container(m);
1058 r = sd_bus_message_skip(m, "v");
1063 r = sd_bus_message_exit_container(m);
1068 return sd_bus_message_exit_container(m);
1071 int bus_message_map_properties_changed(sd_bus *bus,
1073 const struct bus_properties_map *map,
1076 int r, invalidated, i;
1082 r = bus_message_map_all_properties(bus, m, map, userdata);
1086 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1091 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1092 for (i = 0; map[i].member; i++)
1093 if (streq(map[i].member, member)) {
1098 r = sd_bus_message_exit_container(m);
1105 int bus_map_all_properties(sd_bus *bus,
1106 const char *destination,
1108 const struct bus_properties_map *map,
1110 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1111 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1115 assert(destination);
1119 r = sd_bus_call_method(
1123 "org.freedesktop.DBus.Properties",
1131 return bus_message_map_all_properties(bus, m, map, userdata);
1134 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1137 assert(transport >= 0);
1138 assert(transport < _BUS_TRANSPORT_MAX);
1141 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1142 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1144 switch (transport) {
1146 case BUS_TRANSPORT_LOCAL:
1148 r = sd_bus_default_user(bus);
1150 r = sd_bus_default_system(bus);
1154 case BUS_TRANSPORT_REMOTE:
1155 r = sd_bus_open_system_remote(bus, host);
1158 case BUS_TRANSPORT_MACHINE:
1159 r = sd_bus_open_system_machine(bus, host);
1163 assert_not_reached("Hmm, unknown transport type.");
1169 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1172 assert(transport >= 0);
1173 assert(transport < _BUS_TRANSPORT_MAX);
1176 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1177 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1179 switch (transport) {
1181 case BUS_TRANSPORT_LOCAL:
1183 r = bus_open_user_systemd(bus);
1185 r = bus_open_system_systemd(bus);
1189 case BUS_TRANSPORT_REMOTE:
1190 r = sd_bus_open_system_remote(bus, host);
1193 case BUS_TRANSPORT_MACHINE:
1194 r = sd_bus_open_system_machine(bus, host);
1198 assert_not_reached("Hmm, unknown transport type.");
1204 int bus_property_get_bool(
1207 const char *interface,
1208 const char *property,
1209 sd_bus_message *reply,
1211 sd_bus_error *error) {
1213 int b = *(bool*) userdata;
1215 return sd_bus_message_append_basic(reply, 'b', &b);
1218 #if __SIZEOF_SIZE_T__ != 8
1219 int bus_property_get_size(
1222 const char *interface,
1223 const char *property,
1224 sd_bus_message *reply,
1226 sd_bus_error *error) {
1228 uint64_t sz = *(size_t*) userdata;
1230 return sd_bus_message_append_basic(reply, 't', &sz);
1234 #if __SIZEOF_LONG__ != 8
1235 int bus_property_get_long(
1238 const char *interface,
1239 const char *property,
1240 sd_bus_message *reply,
1242 sd_bus_error *error) {
1244 int64_t l = *(long*) userdata;
1246 return sd_bus_message_append_basic(reply, 'x', &l);
1249 int bus_property_get_ulong(
1252 const char *interface,
1253 const char *property,
1254 sd_bus_message *reply,
1256 sd_bus_error *error) {
1258 uint64_t ul = *(unsigned long*) userdata;
1260 return sd_bus_message_append_basic(reply, 't', &ul);
1264 int bus_log_parse_error(int r) {
1265 return log_error_errno(r, "Failed to parse bus message: %m");
1268 int bus_log_create_error(int r) {
1269 return log_error_errno(r, "Failed to create bus message: %m");
1272 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1278 return sd_bus_message_read(
1293 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1297 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1298 sd_bus_reply_method_errno(m, r, error);
1300 } else if (sd_bus_error_is_set(error)) {
1301 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1302 sd_bus_reply_method_error(m, error);
1306 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1307 bus_message_type_to_string(m->header->type),
1310 strna(m->interface),
1312 strna(m->root_container.signature),
1313 bus_error_message(error, r));
1318 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1319 const char *eq, *field;
1325 eq = strchr(assignment, '=');
1327 log_error("Not an assignment: %s", assignment);
1331 field = strndupa(assignment, eq - assignment);
1334 if (streq(field, "CPUQuota")) {
1338 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1340 return bus_log_create_error(r);
1342 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1344 } else if (endswith(eq, "%")) {
1347 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1348 log_error("CPU quota '%s' invalid.", eq);
1352 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1354 return bus_log_create_error(r);
1356 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1358 log_error("CPU quota needs to be in percent.");
1363 return bus_log_create_error(r);
1368 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1370 return bus_log_create_error(r);
1372 if (STR_IN_SET(field,
1373 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1374 "SendSIGHUP", "SendSIGKILL",
1377 r = parse_boolean(eq);
1379 log_error("Failed to parse boolean assignment %s.", assignment);
1383 r = sd_bus_message_append(m, "v", "b", r);
1385 } else if (streq(field, "MemoryLimit")) {
1388 r = parse_size(eq, 1024, &bytes);
1390 log_error("Failed to parse bytes specification %s", assignment);
1394 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1396 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1399 r = safe_atou64(eq, &u);
1401 log_error("Failed to parse %s value %s.", field, eq);
1405 r = sd_bus_message_append(m, "v", "t", u);
1407 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1408 r = sd_bus_message_append(m, "v", "s", eq);
1410 else if (streq(field, "DeviceAllow")) {
1413 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1415 const char *path, *rwm, *e;
1417 e = strchr(eq, ' ');
1419 path = strndupa(eq, e - eq);
1426 if (!path_startswith(path, "/dev")) {
1427 log_error("%s is not a device file in /dev.", path);
1431 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1434 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1437 r = sd_bus_message_append(m, "v", "a(st)", 0);
1439 const char *path, *bandwidth, *e;
1442 e = strchr(eq, ' ');
1444 path = strndupa(eq, e - eq);
1447 log_error("Failed to parse %s value %s.", field, eq);
1451 if (!path_startswith(path, "/dev")) {
1452 log_error("%s is not a device file in /dev.", path);
1456 r = parse_size(bandwidth, 1000, &bytes);
1458 log_error("Failed to parse byte value %s.", bandwidth);
1462 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1465 } else if (streq(field, "BlockIODeviceWeight")) {
1468 r = sd_bus_message_append(m, "v", "a(st)", 0);
1470 const char *path, *weight, *e;
1473 e = strchr(eq, ' ');
1475 path = strndupa(eq, e - eq);
1478 log_error("Failed to parse %s value %s.", field, eq);
1482 if (!path_startswith(path, "/dev")) {
1483 log_error("%s is not a device file in /dev.", path);
1487 r = safe_atou64(weight, &u);
1489 log_error("Failed to parse %s value %s.", field, weight);
1492 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1495 } else if (rlimit_from_string(field) >= 0) {
1498 if (streq(eq, "infinity"))
1501 r = safe_atou64(eq, &rl);
1503 log_error("Invalid resource limit: %s", eq);
1508 r = sd_bus_message_append(m, "v", "t", rl);
1510 } else if (streq(field, "Nice")) {
1513 r = safe_atoi32(eq, &i);
1515 log_error("Failed to parse %s value %s.", field, eq);
1519 r = sd_bus_message_append(m, "v", "i", i);
1521 } else if (streq(field, "Environment")) {
1523 r = sd_bus_message_append(m, "v", "as", 1, eq);
1525 } else if (streq(field, "KillSignal")) {
1528 sig = signal_from_string_try_harder(eq);
1530 log_error("Failed to parse %s value %s.", field, eq);
1534 r = sd_bus_message_append(m, "v", "i", sig);
1536 } else if (streq(field, "AccuracySec")) {
1539 r = parse_sec(eq, &u);
1541 log_error("Failed to parse %s value %s", field, eq);
1545 r = sd_bus_message_append(m, "v", "t", u);
1548 log_error("Unknown assignment %s.", assignment);
1553 return bus_log_create_error(r);
1558 typedef struct BusWaitForJobs {
1565 sd_bus_slot *slot_job_removed;
1566 sd_bus_slot *slot_disconnected;
1569 static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1573 log_error("Warning! D-Bus connection terminated.");
1579 static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1580 const char *path, *unit, *result;
1581 BusWaitForJobs *d = userdata;
1590 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1592 bus_log_parse_error(r);
1596 found = set_remove(d->jobs, (char*) path);
1602 if (!isempty(result))
1603 d->result = strdup(result);
1606 d->name = strdup(unit);
1611 void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1615 set_free_free(d->jobs);
1617 sd_bus_slot_unref(d->slot_disconnected);
1618 sd_bus_slot_unref(d->slot_job_removed);
1620 sd_bus_unref(d->bus);
1628 int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1629 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1635 d = new0(BusWaitForJobs, 1);
1639 d->bus = sd_bus_ref(bus);
1641 /* When we are a bus client we match by sender. Direct
1642 * connections OTOH have no initialized sender field, and
1643 * hence we ignore the sender then */
1644 r = sd_bus_add_match(
1646 &d->slot_job_removed,
1649 "sender='org.freedesktop.systemd1',"
1650 "interface='org.freedesktop.systemd1.Manager',"
1651 "member='JobRemoved',"
1652 "path='/org/freedesktop/systemd1'" :
1654 "interface='org.freedesktop.systemd1.Manager',"
1655 "member='JobRemoved',"
1656 "path='/org/freedesktop/systemd1'",
1657 match_job_removed, d);
1661 r = sd_bus_add_match(
1663 &d->slot_disconnected,
1665 "sender='org.freedesktop.DBus.Local',"
1666 "interface='org.freedesktop.DBus.Local',"
1667 "member='Disconnected'",
1668 match_disconnected, d);
1678 static int bus_process_wait(sd_bus *bus) {
1682 r = sd_bus_process(bus, NULL);
1688 r = sd_bus_wait(bus, (uint64_t) -1);
1694 static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1700 if (streq(d->result, "canceled"))
1701 log_error("Job for %s canceled.", strna(d->name));
1702 else if (streq(d->result, "timeout"))
1703 log_error("Job for %s timed out.", strna(d->name));
1704 else if (streq(d->result, "dependency"))
1705 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1706 else if (streq(d->result, "invalid"))
1707 log_error("Job for %s invalid.", strna(d->name));
1708 else if (streq(d->result, "assert"))
1709 log_error("Assertion failed on job for %s.", strna(d->name));
1710 else if (streq(d->result, "unsupported"))
1711 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1712 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
1716 quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
1718 log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
1720 quotes ? "'" : "", d->name, quotes ? "'" : "");
1722 log_error("Job failed. See \"journalctl -xe\" for details.");
1726 if (streq(d->result, "canceled"))
1728 else if (streq(d->result, "timeout"))
1730 else if (streq(d->result, "dependency"))
1732 else if (streq(d->result, "invalid"))
1734 else if (streq(d->result, "assert"))
1736 else if (streq(d->result, "unsupported"))
1738 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1744 int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1749 while (!set_isempty(d->jobs)) {
1752 q = bus_process_wait(d->bus);
1754 return log_error_errno(q, "Failed to wait for response: %m");
1757 q = check_wait_response(d, quiet);
1758 /* Return the first error as it is most likely to be
1760 if (q < 0 && r == 0)
1764 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1777 int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1782 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1786 return set_put_strdup(d->jobs, path);
1789 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
1790 const char *type, *path, *source;
1793 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1795 return bus_log_parse_error(r);
1797 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1799 if (streq(type, "symlink"))
1800 log_info("Created symlink from %s to %s.", path, source);
1802 log_info("Removed symlink %s.", path);
1806 return bus_log_parse_error(r);
1808 r = sd_bus_message_exit_container(m);
1810 return bus_log_parse_error(r);