]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tree-wide: Migrate to varlink_set_sentinel()
authorDaan De Meyer <daan@amutable.com>
Tue, 3 Feb 2026 11:51:46 +0000 (12:51 +0100)
committerDaan De Meyer <daan@amutable.com>
Wed, 11 Feb 2026 13:25:36 +0000 (14:25 +0100)
13 files changed:
src/bootctl/bootctl-status.c
src/core/varlink-dynamic-user.c
src/core/varlink-manager.c
src/core/varlink-unit.c
src/home/homed-varlink.c
src/import/importd.c
src/machine/machined-varlink.c
src/pcrlock/pcrlock.c
src/repart/repart.c
src/shared/metrics.c
src/shared/metrics.h
src/sysext/sysext.c
src/userdb/userwork.c

index 044d581dcd08d030dbc231c70f5d1205b4c12b38..9c53522594a506bf0f55b176fa2feb6fa6c20e22 100644 (file)
@@ -22,6 +22,7 @@
 #include "pretty-print.h"
 #include "string-util.h"
 #include "tpm2-util.h"
+#include "varlink-util.h"
 
 static int status_entries(
                 const BootConfig *config,
@@ -674,23 +675,21 @@ int vl_method_list_boot_entries(sd_varlink *link, sd_json_variant *parameters, s
         if (r < 0)
                 return r;
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *previous = NULL;
+        r = varlink_set_sentinel(link, "io.systemd.BootControl.NoSuchBootEntry");
+        if (r < 0)
+                return r;
+
         for (size_t i = 0; i < config.n_entries; i++) {
-                if (previous) {
-                        r = sd_varlink_notifybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", previous));
-                        if (r < 0)
-                                return r;
+                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
 
-                        previous = sd_json_variant_unref(previous);
-                }
+                r = boot_entry_to_json(&config, i, &v);
+                if (r < 0)
+                        return r;
 
-                r = boot_entry_to_json(&config, i, &previous);
+                r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", v));
                 if (r < 0)
                         return r;
         }
 
-        if (!previous)
-                return sd_varlink_error(link, "io.systemd.BootControl.NoSuchBootEntry", NULL);
-
-        return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", previous));
+        return 0;
 }
index e200e16fcfc93d8b1cb2845bf7d9773ec849db58..3f27a1f89140fd209469f51980e08750850b080b 100644 (file)
@@ -10,6 +10,7 @@
 #include "uid-classification.h"
 #include "user-util.h"
 #include "varlink-dynamic-user.h"
+#include "varlink-util.h"
 
 typedef struct LookupParameters {
         const char *user_name;
@@ -59,7 +60,6 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
                 {}
         };
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         LookupParameters p = {
                 .uid = UID_INVALID,
         };
@@ -78,6 +78,10 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
         if (!streq_ptr(p.service, "io.systemd.DynamicUser"))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (uid_is_valid(p.uid))
                 r = dynamic_user_lookup_uid(m, p.uid, &found_name);
         else if (p.user_name)
@@ -98,26 +102,20 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
                         if (!user_match_lookup_parameters(&p, d->name, uid))
                                 continue;
 
-                        if (v) {
-                                r = sd_varlink_notify(link, v);
-                                if (r < 0)
-                                        return r;
-
-                                v = sd_json_variant_unref(v);
-                        }
-
+                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
                         r = build_user_json(d->name, uid, &v);
                         if (r < 0)
                                 return r;
-                }
 
-                if (!v)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        r = sd_varlink_reply(link, v);
+                        if (r < 0)
+                                return r;
+                }
 
-                return sd_varlink_reply(link, v);
+                return 0;
         }
         if (r == -ESRCH)
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
         if (r < 0)
                 return r;
 
@@ -127,6 +125,7 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
         if (!user_match_lookup_parameters(&p, un, uid))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
 
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         r = build_user_json(un, uid, &v);
         if (r < 0)
                 return r;
@@ -168,7 +167,6 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
                 {}
         };
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         LookupParameters p = {
                 .gid = GID_INVALID,
         };
@@ -184,6 +182,10 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
         if (r != 0)
                 return r;
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (!streq_ptr(p.service, "io.systemd.DynamicUser"))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
 
@@ -209,26 +211,20 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
                         if (!group_match_lookup_parameters(&p, d->name, (gid_t) uid))
                                 continue;
 
-                        if (v) {
-                                r = sd_varlink_notify(link, v);
-                                if (r < 0)
-                                        return r;
-
-                                v = sd_json_variant_unref(v);
-                        }
-
+                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
                         r = build_group_json(d->name, (gid_t) uid, &v);
                         if (r < 0)
                                 return r;
-                }
 
-                if (!v)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        r = sd_varlink_reply(link, v);
+                        if (r < 0)
+                                return r;
+                }
 
-                return sd_varlink_reply(link, v);
+                return 0;
         }
         if (r == -ESRCH)
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
         if (r < 0)
                 return r;
 
@@ -238,6 +234,7 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
         if (!group_match_lookup_parameters(&p, gn, gid))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
 
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         r = build_group_json(gn, gid, &v);
         if (r < 0)
                 return r;
index 9eeeed42ccf9e573740d296a6e9c64a68404c3c1..dbe97f20c9bcd73f6306e76954bc78fe2c76d016 100644 (file)
@@ -330,6 +330,10 @@ int vl_method_enqueue_marked_jobs_manager(sd_varlink *link, sd_json_variant *par
         if (r <= 0)
                 return r;
 
+        r = varlink_set_sentinel(link, NULL);
+        if (r < 0)
+                return r;
+
         log_info("Queuing reload/restart jobs for marked units%s", glyph(GLYPH_ELLIPSIS));
 
         Unit *u;
@@ -373,20 +377,17 @@ int vl_method_enqueue_marked_jobs_manager(sd_varlink *link, sd_json_variant *par
 
                         const char *error_msg = bus_error.message ?: error_id ? NULL : STRERROR(r);
 
-                        r = sd_varlink_notifybo(link,
-                                                SD_JSON_BUILD_PAIR_STRING("unitID", u->id),
-                                                JSON_BUILD_PAIR_STRING_NON_EMPTY("error", error_id),
-                                                JSON_BUILD_PAIR_STRING_NON_EMPTY("errorMessage", error_msg));
+                        r = sd_varlink_replybo(link,
+                                               SD_JSON_BUILD_PAIR_STRING("unitID", u->id),
+                                               JSON_BUILD_PAIR_STRING_NON_EMPTY("error", error_id),
+                                               JSON_BUILD_PAIR_STRING_NON_EMPTY("errorMessage", error_msg));
                 } else
-                        r = sd_varlink_notifybo(link,
-                                                SD_JSON_BUILD_PAIR_STRING("unitID", u->id),
-                                                SD_JSON_BUILD_PAIR_INTEGER("jobID", job_id));
+                        r = sd_varlink_replybo(link,
+                                               SD_JSON_BUILD_PAIR_STRING("unitID", u->id),
+                                               SD_JSON_BUILD_PAIR_INTEGER("jobID", job_id));
                 if (r < 0)
                         return r;
         }
 
-        if (ret < 0)
-                return ret;
-
-        return sd_varlink_reply(link, NULL);
+        return ret;
 }
index 11a807d3a469edc1e113be0b4dd8f0cc53dc6792..aa9a8fb0ede9603382447e27983943e2d2357d4f 100644 (file)
@@ -311,27 +311,16 @@ static int unit_runtime_build_json(sd_json_variant **ret, const char *name, void
                         JSON_BUILD_PAIR_CALLBACK_NON_NULL("CGroup", unit_cgroup_runtime_build_json, u));
 }
 
-static int list_unit_one(sd_varlink *link, Unit *unit, bool more) {
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
-        int r;
-
+static int list_unit_one(sd_varlink *link, Unit *unit) {
         assert(link);
         assert(unit);
 
-        r = sd_json_buildo(
-                &v,
-                SD_JSON_BUILD_PAIR_CALLBACK("context", unit_context_build_json, unit),
-                SD_JSON_BUILD_PAIR_CALLBACK("runtime", unit_runtime_build_json, unit));
-        if (r < 0)
-                return r;
-
-        if (more)
-                return sd_varlink_notify(link, v);
-
-        return sd_varlink_reply(link, v);
+        return sd_varlink_replybo(link,
+                        SD_JSON_BUILD_PAIR_CALLBACK("context", unit_context_build_json, unit),
+                        SD_JSON_BUILD_PAIR_CALLBACK("runtime", unit_runtime_build_json, unit));
 }
 
-static int list_unit_one_with_selinux_access_check(sd_varlink *link, Unit *unit, bool more) {
+static int list_unit_one_with_selinux_access_check(sd_varlink *link, Unit *unit) {
         int r;
 
         assert(link);
@@ -343,7 +332,7 @@ static int list_unit_one_with_selinux_access_check(sd_varlink *link, Unit *unit,
                  * it means that SELinux enforce is on. It also does all the logging(). */
                 return sd_varlink_error(link, SD_VARLINK_ERROR_PERMISSION_DENIED, NULL);
 
-        return list_unit_one(link, unit, more);
+        return list_unit_one(link, unit);
 }
 
 static int lookup_unit_by_pidref(sd_varlink *link, Manager *manager, PidRef *pidref, Unit **ret_unit) {
@@ -456,7 +445,7 @@ static int lookup_unit_by_parameters(
         }
 
         *ret = unit;
-        return 0;
+        return !!unit;
 }
 
 int vl_method_list_units(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
@@ -472,7 +461,7 @@ int vl_method_list_units(sd_varlink *link, sd_json_variant *parameters, sd_varli
          _cleanup_(unit_lookup_parameters_done) UnitLookupParameters p = {
                  .pidref = PIDREF_NULL,
         };
-        Unit *unit, *previous = NULL;
+        Unit *unit;
         const char *k;
         int r;
 
@@ -487,29 +476,26 @@ int vl_method_list_units(sd_varlink *link, sd_json_variant *parameters, sd_varli
         if (r < 0)
                 return r;
         if (r > 0)
-                return list_unit_one_with_selinux_access_check(link, unit, /* more= */ false);
+                return list_unit_one_with_selinux_access_check(link, unit);
 
         if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
                 return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
 
+        r = varlink_set_sentinel(link, "io.systemd.Manager.NoSuchUnit");
+        if (r < 0)
+                return r;
+
         HASHMAP_FOREACH_KEY(unit, k, manager->units) {
                 /* ignore aliases */
                 if (k != unit->id)
                         continue;
 
-                if (previous) {
-                        r = list_unit_one(link, previous, /* more= */ true);
-                        if (r < 0)
-                                return r;
-                }
-
-                previous = unit;
+                r = list_unit_one(link, unit);
+                if (r < 0)
+                        return r;
         }
 
-        if (previous)
-                return list_unit_one(link, previous, /* more= */ false);
-
-        return sd_varlink_error(link, "io.systemd.Manager.NoSuchUnit", NULL);
+        return 0;
 }
 
 int varlink_unit_queue_job_one(
index d4015de622e9b37ca99e933d5f853eff7577d911..fb23dc9cde290a0050307648341db41beeec978c 100644 (file)
@@ -14,6 +14,7 @@
 #include "user-record.h"
 #include "user-record-util.h"
 #include "user-util.h"
+#include "varlink-util.h"
 
 typedef struct LookupParameters {
         const char *user_name;
@@ -86,7 +87,6 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
                 {}
         };
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         LookupParameters p = {
                 .uid = UID_INVALID,
         };
@@ -104,6 +104,10 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
         if (!streq_ptr(p.service, m->userdb_service))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (uid_is_valid(p.uid))
                 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(p.uid));
         else if (p.user_name) {
@@ -112,45 +116,36 @@ int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_
                         return r;
         } else {
 
-                /* If neither UID nor name was specified, then dump all homes. Do so with varlink_notify()
-                 * for all entries but the last, so that clients can stream the results, and easily process
-                 * them piecemeal. */
+                /* If neither UID nor name was specified, then dump all homes. */
 
                 HASHMAP_FOREACH(h, m->homes_by_uid) {
-
                         if (!home_user_match_lookup_parameters(&p, h))
                                 continue;
 
-                        if (v) {
-                                /* An entry set from the previous iteration? Then send it now */
-                                r = sd_varlink_notify(link, v);
-                                if (r < 0)
-                                        return r;
-
-                                v = sd_json_variant_unref(v);
-                        }
-
                         trusted = client_is_trusted(link, h);
 
+                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
                         r = build_user_json(h, trusted, &v);
                         if (r < 0)
                                 return r;
-                }
 
-                if (!v)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        r = sd_varlink_reply(link, v);
+                        if (r < 0)
+                                return r;
+                }
 
-                return sd_varlink_reply(link, v);
+                return 0;
         }
 
         if (!h)
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
 
         if (!home_user_match_lookup_parameters(&p, h))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
 
         trusted = client_is_trusted(link, h);
 
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         r = build_user_json(h, trusted, &v);
         if (r < 0)
                 return r;
@@ -201,7 +196,6 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
                 {}
         };
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         LookupParameters p = {
                 .gid = GID_INVALID,
         };
@@ -218,6 +212,10 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
         if (!streq_ptr(p.service, m->userdb_service))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (gid_is_valid(p.gid))
                 h = hashmap_get(m->homes_by_uid, UID_TO_PTR((uid_t) p.gid));
         else if (p.group_name) {
@@ -225,37 +223,30 @@ int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd
                 if (r < 0)
                         return r;
         } else {
-
                 HASHMAP_FOREACH(h, m->homes_by_uid) {
-
                         if (!home_group_match_lookup_parameters(&p, h))
                                 continue;
 
-                        if (v) {
-                                r = sd_varlink_notify(link, v);
-                                if (r < 0)
-                                        return r;
-
-                                v = sd_json_variant_unref(v);
-                        }
-
+                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
                         r = build_group_json(h, &v);
                         if (r < 0)
                                 return r;
-                }
 
-                if (!v)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        r = sd_varlink_reply(link, v);
+                        if (r < 0)
+                                return r;
+                }
 
-                return sd_varlink_reply(link, v);
+                return 0;
         }
 
         if (!h)
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
 
         if (!home_group_match_lookup_parameters(&p, h))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
 
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         r = build_group_json(h, &v);
         if (r < 0)
                 return r;
@@ -286,17 +277,21 @@ int vl_method_get_memberships(sd_varlink *link, sd_json_variant *parameters, sd_
         if (!streq_ptr(p.service, m->userdb_service))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (p.user_name) {
                 r = manager_get_home_by_name(m, p.user_name, &h);
                 if (r < 0)
                         return r;
                 if (!h)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        return 0;
 
                 if (p.group_name) {
                         if (!strv_contains(h->record->member_of, p.group_name) &&
                             !user_record_matches_user_name(h->record, p.group_name))
-                                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                                return 0;
 
                         return sd_varlink_replybo(
                                         link,
@@ -305,7 +300,7 @@ int vl_method_get_memberships(sd_varlink *link, sd_json_variant *parameters, sd_
                 }
 
                 STRV_FOREACH(i, h->record->member_of) {
-                        r = sd_varlink_notifybo(
+                        r = sd_varlink_replybo(
                                         link,
                                         SD_JSON_BUILD_PAIR_STRING("userName", h->user_name),
                                         SD_JSON_BUILD_PAIR_STRING("groupName", *i));
@@ -319,64 +314,37 @@ int vl_method_get_memberships(sd_varlink *link, sd_json_variant *parameters, sd_
                                 SD_JSON_BUILD_PAIR_STRING("groupName", h->user_name));
 
         } else if (p.group_name) {
-                const char *last = NULL;
-
                 HASHMAP_FOREACH(h, m->homes_by_uid) {
-
                         if (!strv_contains(h->record->member_of, p.group_name) &&
                             !user_record_matches_user_name(h->record, p.group_name))
                                 continue;
 
-                        if (last) {
-                                r = sd_varlink_notifybo(
-                                                link,
-                                                SD_JSON_BUILD_PAIR_STRING("userName", last),
-                                                SD_JSON_BUILD_PAIR_STRING("groupName", p.group_name));
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        last = h->user_name;
-                }
-
-                if (last)
-                        return sd_varlink_replybo(
+                        r = sd_varlink_replybo(
                                         link,
-                                        SD_JSON_BUILD_PAIR_STRING("userName", last),
+                                        SD_JSON_BUILD_PAIR_STRING("userName", h->user_name),
                                         SD_JSON_BUILD_PAIR_STRING("groupName", p.group_name));
+                        if (r < 0)
+                                return r;
+                }
         } else {
-                const char *last = NULL;
-
                 HASHMAP_FOREACH(h, m->homes_by_uid) {
+                        r = sd_varlink_replybo(
+                                        link,
+                                        SD_JSON_BUILD_PAIR_STRING("userName", h->user_name),
+                                        SD_JSON_BUILD_PAIR_STRING("groupName", h->user_name));
+                        if (r < 0)
+                                return r;
+
                         STRV_FOREACH(j, h->record->member_of) {
-                                if (last) {
-                                        r = sd_varlink_notifybo(
-                                                        link,
-                                                        SD_JSON_BUILD_PAIR_STRING("userName", last),
-                                                        SD_JSON_BUILD_PAIR_STRING("groupName", last));
-                                        if (r < 0)
-                                                return r;
-
-                                        last = NULL;
-                                }
-
-                                r = sd_varlink_notifybo(
+                                r = sd_varlink_replybo(
                                                 link,
                                                 SD_JSON_BUILD_PAIR_STRING("userName", h->user_name),
                                                 SD_JSON_BUILD_PAIR_STRING("groupName", *j));
                                 if (r < 0)
                                         return r;
                         }
-
-                        last = h->user_name;
                 }
-
-                if (last)
-                        return sd_varlink_replybo(
-                                        link,
-                                        SD_JSON_BUILD_PAIR_STRING("userName", last),
-                                        SD_JSON_BUILD_PAIR_STRING("groupName", last));
         }
 
-        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+        return 0;
 }
index dea63e36e2573ed483fc55e1076cd4fc0646e627..549bbe712f8ff053f040514d12b3b3028c91febb 100644 (file)
@@ -1801,38 +1801,26 @@ static int vl_method_list_transfers(sd_varlink *link, sd_json_variant *parameter
         if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
                 return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
 
-        Transfer *previous = NULL, *t;
-        HASHMAP_FOREACH(t, m->transfers) {
+        r = varlink_set_sentinel(link, "io.systemd.Import.NoTransfers");
+        if (r < 0)
+                return r;
 
+        Transfer *t;
+        HASHMAP_FOREACH(t, m->transfers) {
                 if (p.class >= 0 && p.class != t->class)
                         continue;
 
-                if (previous) {
-                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
-
-                        r = make_transfer_json(previous, &v);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_varlink_notify(link, v);
-                        if (r < 0)
-                                return r;
-                }
-
-                previous = t;
-        }
-
-        if (previous) {
                 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
-
-                r = make_transfer_json(previous, &v);
+                r = make_transfer_json(t, &v);
                 if (r < 0)
                         return r;
 
-                return sd_varlink_reply(link, v);
+                r = sd_varlink_reply(link, v);
+                if (r < 0)
+                        return r;
         }
 
-        return sd_varlink_error(link, "io.systemd.Import.NoTransfers", NULL);
+        return 0;
 }
 
 static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_import_verify, ImportVerify, import_verify_from_string);
index 2697a87b6dd4a912c715a510bc2f33c1c3b117ac..543e4c8ee7f9d0064337dd0f8381283a06f12854 100644 (file)
@@ -426,7 +426,7 @@ static int json_build_local_addresses(const struct local_address *addresses, siz
         return 0;
 }
 
-static int list_machine_one_and_maybe_read_metadata(sd_varlink *link, Machine *m, bool more, AcquireMetadata am) {
+static int list_machine_one_and_maybe_read_metadata(sd_varlink *link, Machine *m, AcquireMetadata am) {
         _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *addr_array = NULL;
         _cleanup_strv_free_ char **os_release = NULL;
         uid_t shift = UID_INVALID;
@@ -496,9 +496,6 @@ static int list_machine_one_and_maybe_read_metadata(sd_varlink *link, Machine *m
         if (r < 0)
                 return r;
 
-        if (more)
-                return sd_varlink_notify(link, v);
-
         return sd_varlink_reply(link, v);
 }
 
@@ -528,8 +525,6 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
         _cleanup_(machine_lookup_parameters_done) MachineLookupParameters p = {
                 .pidref = PIDREF_NULL,
         };
-
-        Machine *machine;
         int r;
 
         assert(link);
@@ -539,34 +534,32 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
         if (r != 0)
                 return r;
 
+        r = varlink_set_sentinel(link, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE);
+        if (r < 0)
+                return r;
+
         if (p.name || pidref_is_set(&p.pidref) || pidref_is_automatic(&p.pidref)) {
+                Machine *machine;
                 r = lookup_machine_by_name_or_pidref(link, m, p.name, &p.pidref, &machine);
                 if (r == -ESRCH)
-                        return sd_varlink_error(link, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE, NULL);
+                        return 0;
                 if (r < 0)
                         return r;
 
-                return list_machine_one_and_maybe_read_metadata(link, machine, /* more= */ false, p.acquire_metadata);
+                return list_machine_one_and_maybe_read_metadata(link, machine, p.acquire_metadata);
         }
 
         if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
                 return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
 
-        Machine *previous = NULL, *i;
-        HASHMAP_FOREACH(i, m->machines) {
-                if (previous) {
-                        r = list_machine_one_and_maybe_read_metadata(link, previous, /* more= */ true, p.acquire_metadata);
-                        if (r < 0)
-                                return r;
-                }
-
-                previous = i;
+        Machine *machine;
+        HASHMAP_FOREACH(machine, m->machines) {
+                r = list_machine_one_and_maybe_read_metadata(link, machine, p.acquire_metadata);
+                if (r < 0)
+                        return r;
         }
 
-        if (previous)
-                return list_machine_one_and_maybe_read_metadata(link, previous, /* more= */ false, p.acquire_metadata);
-
-        return sd_varlink_error(link, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE, NULL);
+        return 0;
 }
 
 static int lookup_machine_and_call_method(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata, sd_varlink_method_t method) {
@@ -619,7 +612,7 @@ static int vl_method_open_root_directory(sd_varlink *link, sd_json_variant *para
         return lookup_machine_and_call_method(link, parameters, flags, userdata, vl_method_open_root_directory_internal);
 }
 
-static int list_image_one_and_maybe_read_metadata(Manager *m, sd_varlink *link, Image *image, bool more, AcquireMetadata am) {
+static int list_image_one_and_maybe_read_metadata(Manager *m, sd_varlink *link, Image *image, AcquireMetadata am) {
         int r;
 
         assert(m);
@@ -663,9 +656,6 @@ static int list_image_one_and_maybe_read_metadata(Manager *m, sd_varlink *link,
                         return r;
         }
 
-        if (more)
-                return sd_varlink_notify(link, v);
-
         return sd_varlink_reply(link, v);
 }
 
@@ -691,6 +681,10 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
         if (r != 0)
                 return r;
 
+        r = varlink_set_sentinel(link, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE);
+        if (r < 0)
+                return r;
+
         if (p.image_name) {
                 _cleanup_(image_unrefp) Image *found = NULL;
 
@@ -699,11 +693,11 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
 
                 r = image_find(m->runtime_scope, IMAGE_MACHINE, p.image_name, /* root= */ NULL, &found);
                 if (r == -ENOENT)
-                        return sd_varlink_error(link, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE, NULL);
+                        return 0;
                 if (r < 0)
                         return log_debug_errno(r, "Failed to find image: %m");
 
-                return list_image_one_and_maybe_read_metadata(m, link, found, /* more= */ false, p.acquire_metadata);
+                return list_image_one_and_maybe_read_metadata(m, link, found, p.acquire_metadata);
         }
 
         if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
@@ -714,21 +708,14 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
         if (r < 0)
                 return log_debug_errno(r, "Failed to discover images: %m");
 
-        Image *image, *previous = NULL;
+        Image *image;
         HASHMAP_FOREACH(image, images) {
-                if (previous) {
-                        r = list_image_one_and_maybe_read_metadata(m, link, previous, /* more= */ true, p.acquire_metadata);
-                        if (r < 0)
-                                return r;
-                }
-
-                previous = image;
+                r = list_image_one_and_maybe_read_metadata(m, link, image, p.acquire_metadata);
+                if (r < 0)
+                        return r;
         }
 
-        if (previous)
-                return list_image_one_and_maybe_read_metadata(m, link, previous, /* more= */ false, p.acquire_metadata);
-
-        return sd_varlink_error(link, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE, NULL);
+        return 0;
 }
 
 static int manager_varlink_init_userdb(Manager *m) {
index 65fbce1de5e40879547504c221ba456262855f0e..396785280c33f5fda3a8881c58f756ff7eb89a79 100644 (file)
@@ -5417,24 +5417,23 @@ static int vl_method_read_event_log(sd_varlink *link, sd_json_variant *parameter
         if (r < 0)
                 return r;
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *rec_cel = NULL;
+        // FIXME: We can't use a NULL sentinel here because the output fields in the IDL are non-nullable.
+        r = varlink_set_sentinel(link, NULL);
+        if (r < 0)
+                return r;
 
         FOREACH_ARRAY(rr, el->records, el->n_records) {
-
-                if (rec_cel) {
-                        r = sd_varlink_notifybo(link, SD_JSON_BUILD_PAIR_VARIANT("record", rec_cel));
-                        if (r < 0)
-                                return r;
-
-                        rec_cel = sd_json_variant_unref(rec_cel);
-                }
-
+                _cleanup_(sd_json_variant_unrefp) sd_json_variant *rec_cel = NULL;
                 r = event_log_record_to_cel(*rr, &recnum, &rec_cel);
                 if (r < 0)
                         return r;
+
+                r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("record", rec_cel));
+                if (r < 0)
+                        return r;
         }
 
-        return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_CONDITION(!!rec_cel, "record", SD_JSON_BUILD_VARIANT(rec_cel)));
+        return 0;
 }
 
 typedef struct MethodMakePolicyParameters {
index e59288221b38feeee5908492e446618e70c14d93..c91f21ae75da562461f8bdad74e1aa394e915d9f 100644 (file)
@@ -10346,21 +10346,12 @@ static int vl_method_list_candidate_devices(
         if (r < 0)
                 return r;
 
-        if (n == 0)
-                return sd_varlink_error(link, "io.systemd.Repart.NoCandidateDevices", NULL);
+        r = varlink_set_sentinel(link, "io.systemd.Repart.NoCandidateDevices");
+        if (r < 0)
+                return r;
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         FOREACH_ARRAY(d, l, n) {
-                if (v) {
-                        r = sd_varlink_notify(link, v);
-                        if (r < 0)
-                                return r;
-
-                        v = sd_json_variant_unref(v);
-                }
-
-                r = sd_json_buildo(
-                                &v,
+                r = sd_varlink_replybo(link,
                                 SD_JSON_BUILD_PAIR_STRING("node", d->node),
                                 JSON_BUILD_PAIR_STRV_NON_EMPTY("symlinks", d->symlinks),
                                 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("diskseq", d->diskseq, UINT64_MAX),
@@ -10372,8 +10363,7 @@ static int vl_method_list_candidate_devices(
                         return r;
         }
 
-        assert(v);
-        return sd_varlink_reply(link, v);
+        return 0;
 }
 
 static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_empty_mode, EmptyMode, empty_mode_from_string);
index 0ce406b7f5c4b1fa353bf771f12882886a4b7bf3..9c70f1129bceb0074619cbdb9a7c095fc450a4b4 100644 (file)
@@ -7,12 +7,6 @@
 #include "varlink-io.systemd.Metrics.h"
 #include "varlink-util.h"
 
-static void metric_family_context_done(MetricFamilyContext *ctx) {
-        assert(ctx);
-
-        sd_json_variant_unref(ctx->previous);
-}
-
 int metrics_setup_varlink_server(
                 sd_varlink_server **server, /* in and out param */
                 sd_varlink_server_flags_t flags,
@@ -68,25 +62,14 @@ static const char * const metric_family_type_table[_METRIC_FAMILY_TYPE_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(metric_family_type, MetricFamilyType);
 
-static int metric_family_build_send(sd_varlink *link, const MetricFamily *mf, bool more) {
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
-        int r;
-
-        assert(link);
+static int metric_family_build_json(const MetricFamily *mf, sd_json_variant **ret) {
         assert(mf);
 
-        r = sd_json_buildo(
-                        &v,
+        return sd_json_buildo(
+                        ret,
                         SD_JSON_BUILD_PAIR_STRING("name", mf->name),
                         SD_JSON_BUILD_PAIR_STRING("description", mf->description),
                         SD_JSON_BUILD_PAIR_STRING("type", metric_family_type_to_string(mf->type)));
-        if (r < 0)
-                return r;
-
-        if (more)
-                return sd_varlink_notify(link, v);
-
-        return sd_varlink_reply(link, v);
 }
 
 int metrics_method_describe(
@@ -109,24 +92,21 @@ int metrics_method_describe(
         if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
                 return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
 
-        const MetricFamily *previous = NULL;
+        r = varlink_set_sentinel(link, "io.systemd.Metrics.NoSuchMetric");
+        if (r < 0)
+                return r;
+
         for (const MetricFamily *mf = metric_family_table; mf && mf->name; mf++) {
-                if (previous) {
-                        r = metric_family_build_send(link, previous, /* more= */ true);
-                        if (r < 0)
-                                return log_debug_errno(
-                                                r, "Failed to describe metric family '%s': %m", previous->name);
-                }
-
-                previous = mf;
-        }
+                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
 
-        if (!previous)
-                return sd_varlink_error(link, "io.systemd.Metrics.NoSuchMetric", NULL);
+                r = metric_family_build_json(mf, &v);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to describe metric family '%s': %m", mf->name);
 
-        r = metric_family_build_send(link, previous, /* more= */ false);
-        if (r < 0)
-                return log_debug_errno(r, "Failed to describe metric family '%s': %m", previous->name);
+                r = sd_varlink_reply(link, v);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to send varlink reply: %m");
+        }
 
         return 0;
 }
@@ -151,7 +131,11 @@ int metrics_method_list(
         if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
                 return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
 
-        _cleanup_(metric_family_context_done) MetricFamilyContext ctx = { .link = link };
+        r = varlink_set_sentinel(link, "io.systemd.Metrics.NoSuchMetric");
+        if (r < 0)
+                return r;
+
+        MetricFamilyContext ctx = { .link = link };
         for (const MetricFamily *mf = metric_family_table; mf && mf->name; mf++) {
                 assert(mf->generate);
 
@@ -162,17 +146,10 @@ int metrics_method_list(
                                         r, "Failed to list metrics for metric family '%s': %m", mf->name);
         }
 
-        if (!ctx.previous)
-                return sd_varlink_error(link, "io.systemd.Metrics.NoSuchMetric", NULL);
-
-        /* produce the last metric */
-        return sd_varlink_reply(link, ctx.previous);
+        return 0;
 }
 
 static int metric_build_send(MetricFamilyContext *context, const char *object, sd_json_variant *value, sd_json_variant *fields) {
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
-        int r;
-
         assert(context);
         assert(value);
         assert(context->link);
@@ -187,26 +164,11 @@ static int metric_build_send(MetricFamilyContext *context, const char *object, s
                         assert(sd_json_variant_is_string(e));
         }
 
-        r = sd_json_buildo(
-                        &v,
+        return sd_varlink_replybo(context->link,
                         SD_JSON_BUILD_PAIR_STRING("name", context->metric_family->name),
                         JSON_BUILD_PAIR_STRING_NON_EMPTY("object", object),
                         SD_JSON_BUILD_PAIR("value", SD_JSON_BUILD_VARIANT(value)),
                         JSON_BUILD_PAIR_VARIANT_NON_NULL("fields", fields));
-        if (r < 0)
-                return r;
-
-        if (context->previous) {
-                r = sd_varlink_notify(context->link, context->previous);
-                if (r < 0)
-                        return r;
-
-                context->previous = sd_json_variant_unref(context->previous);
-        }
-
-        context->previous = TAKE_PTR(v);
-
-        return 0;
 }
 
 int metric_build_send_string(MetricFamilyContext *context, const char *object, const char *value, sd_json_variant *fields) {
index 18eb5cdad42088c7788a980bdd3325ce38307447..cec0153e6806647a27e5ca14dcf3fee7a872cad4 100644 (file)
@@ -16,7 +16,6 @@ typedef struct MetricFamily MetricFamily;
 typedef struct MetricFamilyContext {
         const MetricFamily* metric_family;
         sd_varlink *link;
-        sd_json_variant *previous;
 } MetricFamilyContext;
 
 typedef int (*metric_family_generate_func_t) (MetricFamilyContext *mfc, void *userdata);
index 92431262f33c8300db3fd0f8f256ba9c79361e3a..5e16ace9f99faa23b6e8210e763e48acff0cec49 100644 (file)
@@ -2745,7 +2745,6 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
                 VARLINK_DISPATCH_POLKIT_FIELD,
                 {}
         };
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         Hashmap **polkit_registry = ASSERT_PTR(userdata);
         int r;
 
@@ -2775,26 +2774,23 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
         if (r < 0)
                 return r;
 
+        r = varlink_set_sentinel(link, "io.systemd.sysext.NoImagesFound");
+        if (r < 0)
+                return r;
+
         Image *img;
         HASHMAP_FOREACH(img, images) {
-                if (v) {
-                        /* Send previous item with more=true */
-                        r = sd_varlink_notify(link, v);
-                        if (r < 0)
-                                return r;
-                }
-
-                v = sd_json_variant_unref(v);
-
+                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
                 r = image_to_json(img, &v);
                 if (r < 0)
                         return r;
-        }
 
-        if (v)  /* Send final item with more=false */
-                return sd_varlink_reply(link, v);
+                r = sd_varlink_reply(link, v);
+                if (r < 0)
+                        return r;
+        }
 
-        return sd_varlink_error(link, "io.systemd.sysext.NoImagesFound", NULL);
+        return 0;
 }
 
 static int verb_help(int argc, char **argv, void *userdata) {
index ae927bb52870254a9048f8d07dfe3bcbd993c644..a57447ca85f94df9023bb3ccc84d61b67f6832ce 100644 (file)
@@ -153,7 +153,6 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
                 {}
         };
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
         _cleanup_(lookup_parameters_done) LookupParameters p = {
                 .uid = UID_INVALID,
@@ -173,13 +172,16 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
                      * we are done'; == 0 means 'not processed, caller should process now' */
                 return r;
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (uid_is_valid(p.uid))
                 r = userdb_by_uid(p.uid, &p.match, userdb_flags, &hr);
         else if (p.name)
                 r = userdb_by_name(p.name, &p.match, userdb_flags, &hr);
         else {
                 _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
-                _cleanup_(sd_json_variant_unrefp) sd_json_variant *last = NULL;
 
                 r = userdb_all(&p.match, userdb_flags, &iterator);
                 if (IN_SET(r, -ESRCH, -ENOLINK))
@@ -189,7 +191,7 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
                          * implementation detail and always return NoRecordFound in this case, since from a
                          * client's perspective it's irrelevant if there was no entry at all or just not on
                          * the service that the query was limited to. */
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        return 0;
                 if (r < 0)
                         return r;
 
@@ -202,26 +204,20 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
                         if (r < 0)
                                 return r;
 
-                        if (last) {
-                                r = sd_varlink_notify(link, last);
-                                if (r < 0)
-                                        return r;
-
-                                last = sd_json_variant_unref(last);
-                        }
+                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+                        r = build_user_json(link, z, &v);
+                        if (r < 0)
+                                return r;
 
-                        r = build_user_json(link, z, &last);
+                        r = sd_varlink_reply(link, v);
                         if (r < 0)
                                 return r;
                 }
 
-                if (!last)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
-
-                return sd_varlink_reply(link, last);
+                return 0;
         }
         if (r == -ESRCH)
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
         if (r == -ENOEXEC)
                 return sd_varlink_error(link, "io.systemd.UserDatabase.NonMatchingRecordFound", NULL);
         if (r < 0) {
@@ -233,6 +229,7 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
             (p.name && !user_record_matches_user_name(hr, p.name)))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
 
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         r = build_user_json(link, hr, &v);
         if (r < 0)
                 return r;
@@ -298,7 +295,6 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
                 {}
         };
 
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         _cleanup_(group_record_unrefp) GroupRecord *g = NULL;
         _cleanup_(lookup_parameters_done) LookupParameters p = {
                 .gid = GID_INVALID,
@@ -317,17 +313,20 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
         if (r != 0)
                 return r;
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (gid_is_valid(p.gid))
                 r = groupdb_by_gid(p.gid, &p.match, userdb_flags, &g);
         else if (p.name)
                 r = groupdb_by_name(p.name, &p.match, userdb_flags, &g);
         else {
                 _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
-                _cleanup_(sd_json_variant_unrefp) sd_json_variant *last = NULL;
 
                 r = groupdb_all(&p.match, userdb_flags, &iterator);
                 if (IN_SET(r, -ESRCH, -ENOLINK))
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                        return 0;
                 if (r < 0)
                         return r;
 
@@ -340,26 +339,20 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
                         if (r < 0)
                                 return r;
 
-                        if (last) {
-                                r = sd_varlink_notify(link, last);
-                                if (r < 0)
-                                        return r;
-
-                                last = sd_json_variant_unref(last);
-                        }
+                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+                        r = build_group_json(link, z, &v);
+                        if (r < 0)
+                                return r;
 
-                        r = build_group_json(link, z, &last);
+                        r = sd_varlink_reply(link, v);
                         if (r < 0)
                                 return r;
                 }
 
-                if (!last)
-                        return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
-
-                return sd_varlink_reply(link, last);
+                return 0;
         }
         if (r == -ESRCH)
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
         if (r == -ENOEXEC)
                 return sd_varlink_error(link, "io.systemd.UserDatabase.NonMatchingRecordFound", NULL);
         if (r < 0) {
@@ -371,6 +364,7 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
             (p.name && !group_record_matches_group_name(g, p.name)))
                 return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
 
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         r = build_group_json(link, g, &v);
         if (r < 0)
                 return r;
@@ -392,7 +386,6 @@ static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *paramete
                 {}
         };
 
-        _cleanup_free_ char *last_user_name = NULL, *last_group_name = NULL;
         _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
         MembershipLookupParameters p = {};
         UserDBFlags userdb_flags;
@@ -408,6 +401,10 @@ static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *paramete
         if (r != 0)
                 return r;
 
+        r = varlink_set_sentinel(link, "io.systemd.UserDatabase.NoRecordFound");
+        if (r < 0)
+                return r;
+
         if (p.group_name)
                 r = membershipdb_by_group(p.group_name, userdb_flags, &iterator);
         else if (p.user_name)
@@ -415,7 +412,7 @@ static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *paramete
         else
                 r = membershipdb_all(userdb_flags, &iterator);
         if (IN_SET(r, -ESRCH, -ENOLINK))
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                return 0;
         if (r < 0)
                 return r;
 
@@ -432,32 +429,15 @@ static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *paramete
                 if (p.group_name && p.user_name && !streq(group_name, p.group_name))
                         continue;
 
-                if (last_user_name) {
-                        assert(last_group_name);
-
-                        r = sd_varlink_notifybo(
-                                        link,
-                                        SD_JSON_BUILD_PAIR_STRING("userName", last_user_name),
-                                        SD_JSON_BUILD_PAIR_STRING("groupName", last_group_name));
-                        if (r < 0)
-                                return r;
-                }
-
-                free_and_replace(last_user_name, user_name);
-                free_and_replace(last_group_name, group_name);
-        }
-
-        if (!last_user_name) {
-                assert(!last_group_name);
-                return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
+                r = sd_varlink_replybo(
+                                link,
+                                SD_JSON_BUILD_PAIR_STRING("userName", user_name),
+                                SD_JSON_BUILD_PAIR_STRING("groupName", group_name));
+                if (r < 0)
+                        return r;
         }
 
-        assert(last_group_name);
-
-        return sd_varlink_replybo(
-                        link,
-                        SD_JSON_BUILD_PAIR_STRING("userName", last_user_name),
-                        SD_JSON_BUILD_PAIR_STRING("groupName", last_group_name));
+        return 0;
 }
 
 static int process_connection(sd_varlink_server *server, int _fd) {