chiark / gitweb /
bus: do kdbus only if this is enabled on the configure switch
[elogind.git] / src / libsystemd-bus / sd-bus.c
index a894af08512b74a4f43795db8bad9be5044407f2..1244ec2f6dd051df9d04a3e434b2e45e5f4fd7b4 100644 (file)
@@ -181,6 +181,7 @@ _public_ int sd_bus_new(sd_bus **ret) {
         r->n_ref = REFCNT_INIT;
         r->input_fd = r->output_fd = -1;
         r->message_version = 1;
+        r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
         r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
         r->attach_flags |= KDBUS_ATTACH_NAMES;
         r->original_pid = getpid();
@@ -290,7 +291,10 @@ _public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t mask) {
         assert_return(bus->state == BUS_UNSET, -EPERM);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
-        return kdbus_translate_attach_flags(mask, &bus->creds_mask);
+        /* The well knowns we need unconditionally, so that matches can work */
+        bus->creds_mask = mask | SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
+
+        return kdbus_translate_attach_flags(bus->creds_mask, &bus->creds_mask);
 }
 
 _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
@@ -986,15 +990,17 @@ _public_ int sd_bus_open_system(sd_bus **ret) {
                 return r;
 
         e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
-        if (e) {
+        if (e)
                 r = sd_bus_set_address(b, e);
-                if (r < 0)
-                        goto fail;
-        } else {
-                b->sockaddr.un.sun_family = AF_UNIX;
-                strncpy(b->sockaddr.un.sun_path, "/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
-                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/dbus/system_bus_socket") - 1;
-        }
+        else
+#ifdef ENABLE_KDBUS
+                r = sd_bus_set_address(b, "kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket");
+#else
+                r = sd_bus_set_address(b, "unix:path=/run/dbus/system_bus_socket");
+#endif
+
+        if (r < 0)
+                goto fail;
 
         b->bus_client = true;
 
@@ -1013,7 +1019,6 @@ fail:
 _public_ int sd_bus_open_user(sd_bus **ret) {
         const char *e;
         sd_bus *b;
-        size_t l;
         int r;
 
         assert_return(ret, -EINVAL);
@@ -1029,20 +1034,32 @@ _public_ int sd_bus_open_user(sd_bus **ret) {
                         goto fail;
         } else {
                 e = secure_getenv("XDG_RUNTIME_DIR");
-                if (!e) {
-                        r = -ENOENT;
-                        goto fail;
+                if (e) {
+                        _cleanup_free_ char *ee = NULL;
+
+                        ee = bus_address_escape(e);
+                        if (!ee) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+#ifdef ENABLE_KDBUS
+                        asprintf(&b->address, "kernel:path=/dev/kdbus/%lu-user/bus;unix:path=%s/bus", (unsigned long) getuid(), ee);
+#else
+                        b->address = strjoin("unix:path=", ee, "/bus", NULL);
+#endif
+                } else {
+#ifdef ENABLE_KDBUS
+                        asprintf(&b->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid());
+#else
+                        return -ECONNREFUSED;
+#endif
                 }
 
-                l = strlen(e);
-                if (l + 4 > sizeof(b->sockaddr.un.sun_path)) {
-                        r = -E2BIG;
+                if (!b->address) {
+                        r = -ENOMEM;
                         goto fail;
                 }
-
-                b->sockaddr.un.sun_family = AF_UNIX;
-                memcpy(mempcpy(b->sockaddr.un.sun_path, e, l), "/bus", 4);
-                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l + 4;
         }
 
         b->bus_client = true;
@@ -1153,9 +1170,8 @@ _public_ void sd_bus_close(sd_bus *bus) {
 
         /* We'll leave the fd open in case this is a kernel bus, since
          * there might still be memblocks around that reference this
-         * bus, and they might need to invoke the
-         * KDBUS_CMD_MSG_RELEASE ioctl on the fd when they are
-         * freed. */
+         * bus, and they might need to invoke the * KDBUS_CMD_FREE
+         * ioctl on the fd when they are freed. */
 }
 
 static void bus_enter_closing(sd_bus *bus) {
@@ -1231,7 +1247,8 @@ _public_ int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) {
         return 0;
 }
 
-int bus_seal_message(sd_bus *b, sd_bus_message *m) {
+static int bus_seal_message(sd_bus *b, sd_bus_message *m) {
+        assert(b);
         assert(m);
 
         if (m->header->version > b->message_version)
@@ -1248,6 +1265,24 @@ int bus_seal_message(sd_bus *b, sd_bus_message *m) {
         return bus_message_seal(m, ++b->serial);
 }
 
+int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
+        assert(b);
+        assert(m);
+
+        if (m->header->version > b->message_version)
+                return -EPERM;
+
+        /* The bus specification says the serial number cannot be 0,
+         * hence let's fill something in for synthetic messages. Since
+         * synthetic messages might have a fake sender and we don't
+         * want to interfere with the real sender's serial numbers we
+         * pick a fixed, artifical one. We use (uint32_t) -1 rather
+         * than (uint64_t) -1 since dbus1 only had 32bit identifiers,
+         * even though kdbus can do 64bit. */
+
+        return bus_message_seal(m, 0xFFFFFFFFULL);
+}
+
 static int bus_write_message(sd_bus *bus, sd_bus_message *message, size_t *idx) {
         int r;
 
@@ -1255,9 +1290,9 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *message, size_t *idx)
         assert(message);
 
         if (bus->is_kernel)
-                r = bus_kernel_write_message(bus, message);
+                return bus_kernel_write_message(bus, message);
         else
-                r = bus_socket_write_message(bus, message, idx);
+                return bus_socket_write_message(bus, message, idx);
 
         return r;
 }
@@ -1299,50 +1334,63 @@ static int dispatch_wqueue(sd_bus *bus) {
         return ret;
 }
 
-static int bus_read_message(sd_bus *bus, sd_bus_message **m) {
-        int r;
-
+static int bus_read_message(sd_bus *bus) {
         assert(bus);
-        assert(m);
 
         if (bus->is_kernel)
-                r = bus_kernel_read_message(bus, m);
+                return bus_kernel_read_message(bus);
         else
-                r = bus_socket_read_message(bus, m);
+                return bus_socket_read_message(bus);
+}
 
-        return r;
+int bus_rqueue_make_room(sd_bus *bus) {
+        sd_bus_message **q;
+        unsigned x;
+
+        x = bus->rqueue_size + 1;
+
+        if (bus->rqueue_allocated >= x)
+                return 0;
+
+        if (x > BUS_RQUEUE_MAX)
+                return -ENOBUFS;
+
+        q = realloc(bus->rqueue, x * sizeof(sd_bus_message*));
+        if (!q)
+                return -ENOMEM;
+
+        bus->rqueue = q;
+        bus->rqueue_allocated = x;
+
+        return 0;
 }
 
 static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
-        sd_bus_message *z = NULL;
         int r, ret = 0;
 
         assert(bus);
         assert(m);
         assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
 
-        if (bus->rqueue_size > 0) {
-                /* Dispatch a queued message */
+        for (;;) {
+                if (bus->rqueue_size > 0) {
+                        /* Dispatch a queued message */
 
-                *m = bus->rqueue[0];
-                bus->rqueue_size --;
-                memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
-                return 1;
-        }
+                        *m = bus->rqueue[0];
+                        bus->rqueue_size --;
+                        memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
+                        return 1;
+                }
 
-        /* Try to read a new message */
-        do {
-                r = bus_read_message(bus, &z);
+                /* Try to read a new message */
+                r = bus_read_message(bus);
                 if (r < 0)
                         return r;
                 if (r == 0)
                         return ret;
 
                 ret = 1;
-        } while (!z);
-
-        *m = z;
-        return ret;
+        }
 }
 
 _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
@@ -1379,9 +1427,12 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
                 size_t idx = 0;
 
                 r = bus_write_message(bus, m, &idx);
-                if (r < 0)
+                if (r < 0) {
+                        if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+                                bus_enter_closing(bus);
+
                         return r;
-                else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m))  {
+                else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m))  {
                         /* Wasn't fully written. So let's remember how
                          * much was written. Note that the first entry
                          * of the wqueue array is always allocated so
@@ -1578,10 +1629,10 @@ _public_ int sd_bus_call(
                 sd_bus_error *error,
                 sd_bus_message **reply) {
 
-        int r;
         usec_t timeout;
         uint64_t serial;
-        bool room = false;
+        unsigned i;
+        int r;
 
         assert_return(bus, -EINVAL);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
@@ -1595,6 +1646,8 @@ _public_ int sd_bus_call(
         if (r < 0)
                 return r;
 
+        i = bus->rqueue_size;
+
         r = sd_bus_send(bus, m, &serial);
         if (r < 0)
                 return r;
@@ -1603,34 +1656,18 @@ _public_ int sd_bus_call(
 
         for (;;) {
                 usec_t left;
-                sd_bus_message *incoming = NULL;
 
-                if (!room) {
-                        sd_bus_message **q;
+                while (i < bus->rqueue_size) {
+                        sd_bus_message *incoming = NULL;
 
-                        if (bus->rqueue_size >= BUS_RQUEUE_MAX)
-                                return -ENOBUFS;
-
-                        /* Make sure there's room for queuing this
-                         * locally, before we read the message */
-
-                        q = realloc(bus->rqueue, (bus->rqueue_size + 1) * sizeof(sd_bus_message*));
-                        if (!q)
-                                return -ENOMEM;
-
-                        bus->rqueue = q;
-                        room = true;
-                }
-
-                r = bus_read_message(bus, &incoming);
-                if (r < 0)
-                        return r;
-
-                if (incoming) {
+                        incoming = bus->rqueue[i];
 
                         if (incoming->reply_serial == serial) {
                                 /* Found a match! */
 
+                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+                                bus->rqueue_size--;
+
                                 if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
 
                                         if (reply)
@@ -1639,30 +1676,22 @@ _public_ int sd_bus_call(
                                                 sd_bus_message_unref(incoming);
 
                                         return 1;
-                                }
-
-                                if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
-                                        int k;
-
+                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
                                         r = sd_bus_error_copy(error, &incoming->error);
-                                        if (r < 0) {
-                                                sd_bus_message_unref(incoming);
-                                                return r;
-                                        }
-
-                                        k = sd_bus_error_get_errno(&incoming->error);
-                                        sd_bus_message_unref(incoming);
-                                        return -k;
-                                }
+                                else
+                                        r = -EIO;
 
                                 sd_bus_message_unref(incoming);
-                                return -EIO;
+                                return r;
 
                         } else if (incoming->header->serial == serial &&
                                    bus->unique_name &&
                                    incoming->sender &&
                                    streq(bus->unique_name, incoming->sender)) {
 
+                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+                                bus->rqueue_size--;
+
                                 /* Our own message? Somebody is trying
                                  * to send its own client a message,
                                  * let's not dead-lock, let's fail
@@ -1672,15 +1701,18 @@ _public_ int sd_bus_call(
                                 return -ELOOP;
                         }
 
-                        /* There's already guaranteed to be room for
-                         * this, so need to resize things here */
-                        bus->rqueue[bus->rqueue_size ++] = incoming;
-                        room = false;
-
                         /* Try to read more, right-away */
-                        continue;
+                        i++;
                 }
-                if (r != 0)
+
+                r = bus_read_message(bus);
+                if (r < 0) {
+                        if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+                                bus_enter_closing(bus);
+
+                        return r;
+                }
+                if (r > 0)
                         continue;
 
                 if (timeout > 0) {
@@ -1699,8 +1731,12 @@ _public_ int sd_bus_call(
                         return r;
 
                 r = dispatch_wqueue(bus);
-                if (r < 0)
+                if (r < 0) {
+                        if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+                                bus_enter_closing(bus);
+
                         return r;
+                }
         }
 }
 
@@ -1804,7 +1840,7 @@ static int process_timeout(sd_bus *bus) {
 
         m->sender = "org.freedesktop.DBus";
 
-        r = bus_seal_message(bus, m);
+        r = bus_seal_synthetic_message(bus, m);
         if (r < 0)
                 return r;
 
@@ -2096,7 +2132,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
                 if (r < 0)
                         return r;
 
-                r = bus_seal_message(bus, m);
+                r = bus_seal_synthetic_message(bus, m);
                 if (r < 0)
                         return r;
 
@@ -2127,7 +2163,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
 
         m->sender = "org.freedesktop.DBus.Local";
 
-        r = bus_seal_message(bus, m);
+        r = bus_seal_synthetic_message(bus, m);
         if (r < 0)
                 return r;
 
@@ -2179,7 +2215,7 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
 
         case BUS_OPENING:
                 r = bus_socket_process_opening(bus);
-                if (r == -ECONNRESET || r == -EPIPE) {
+                if (r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
                         bus_enter_closing(bus);
                         r = 1;
                 } else if (r < 0)
@@ -2190,7 +2226,7 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
 
         case BUS_AUTHENTICATING:
                 r = bus_socket_process_authenticating(bus);
-                if (r == -ECONNRESET || r == -EPIPE) {
+                if (r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
                         bus_enter_closing(bus);
                         r = 1;
                 } else if (r < 0)
@@ -2204,7 +2240,7 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
         case BUS_RUNNING:
         case BUS_HELLO:
                 r = process_running(bus, ret);
-                if (r == -ECONNRESET || r == -EPIPE) {
+                if (r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
                         bus_enter_closing(bus);
                         r = 1;
 
@@ -2315,8 +2351,12 @@ _public_ int sd_bus_flush(sd_bus *bus) {
 
         for (;;) {
                 r = dispatch_wqueue(bus);
-                if (r < 0)
+                if (r < 0) {
+                        if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+                                bus_enter_closing(bus);
+
                         return r;
+                }
 
                 if (bus->wqueue_size <= 0)
                         return 0;
@@ -2779,7 +2819,7 @@ _public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **re
                 c->uid = bus->ucred.uid;
                 c->gid = bus->ucred.gid;
 
-                c->mask |= ((SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask) & bus->creds_mask;
+                c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
         }
 
         if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
@@ -2789,7 +2829,7 @@ _public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **re
                         return -ENOMEM;
                 }
 
-                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT | bus->creds_mask;
+                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
         }
 
         r = bus_creds_add_more(c, mask, pid, 0);