+ if (!isempty(old_owner)) {
+ r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
+ if (r < 0)
+ return 0;
+ if (r == 0)
+ return 0;
+ if (is_name_id > 0 && old_owner_id != name_id)
+ return 0;
+ } else
+ old_owner_id = KDBUS_MATCH_ID_ANY;
+
+ if (!isempty(new_owner)) {
+ r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 0;
+ if (is_name_id > 0 && new_owner_id != name_id)
+ return 0;
+ } else
+ new_owner_id = KDBUS_MATCH_ID_ANY;
+
+ if (is_name_id <= 0) {
+ struct kdbus_cmd_match *m;
+ size_t sz, l;
+
+ /* If the name argument is missing or is a well-known
+ * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
+ * matches for it */
+
+ l = name ? strlen(name) + 1 : 0;
+
+ sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
+ offsetof(struct kdbus_item, name_change) +
+ offsetof(struct kdbus_notify_name_change, name) +
+ l);
+
+ m = alloca0(sz);
+ m->size = sz;
+ m->cookie = cookie;
+
+ item = m->items;
+ item->size =
+ offsetof(struct kdbus_item, name_change) +
+ offsetof(struct kdbus_notify_name_change, name) +
+ l;
+
+ item->name_change.old.id = old_owner_id;
+ item->name_change.new.id = new_owner_id;
+
+ if (name)
+ memcpy(item->name_change.name, name, l);
+
+ /* If the old name is unset or empty, then
+ * this can match against added names */
+ if (!old_owner || old_owner[0] == 0) {
+ item->type = KDBUS_ITEM_NAME_ADD;
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+ if (r < 0)
+ return -errno;
+ }
+
+ /* If the new name is unset or empty, then
+ * this can match against removed names */
+ if (!new_owner || new_owner[0] == 0) {
+ item->type = KDBUS_ITEM_NAME_REMOVE;
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+ if (r < 0)
+ return -errno;
+ }
+
+ /* The CHANGE match we need in either case, because
+ * what is reported as a name change by the kernel
+ * might just be an owner change between starter and
+ * normal clients. For userspace such a change should
+ * be considered a removal/addition, hence let's
+ * subscribe to this unconditionally. */
+ item->type = KDBUS_ITEM_NAME_CHANGE;
+ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+ if (r < 0)
+ return -errno;
+ }
+
+ if (is_name_id != 0) {
+ struct kdbus_cmd_match *m;
+ uint64_t sz;
+
+ /* If the name argument is missing or is a unique
+ * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
+ * for it */
+
+ sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
+ offsetof(struct kdbus_item, id_change) +
+ sizeof(struct kdbus_notify_id_change));
+
+ m = alloca0(sz);
+ m->size = sz;
+ m->cookie = cookie;
+
+ item = m->items;
+ item->size =
+ offsetof(struct kdbus_item, id_change) +
+ sizeof(struct kdbus_notify_id_change);
+ item->id_change.id = name_id;
+
+ /* If the old name is unset or empty, then this can
+ * match against added ids */
+ if (!old_owner || old_owner[0] == 0) {
+ item->type = KDBUS_ITEM_ID_ADD;
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+ if (r < 0)
+ return -errno;
+ }
+
+ /* If thew new name is unset or empty, then this can
+ * match against removed ids */
+ if (!new_owner || new_owner[0] == 0) {
+ item->type = KDBUS_ITEM_ID_REMOVE;
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+ if (r < 0)
+ return -errno;
+ }