}
#endif /* WITH_GETPWUID_R */
+void
+virSubIDsFree(virSubID **uids, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ if ((*uids)[i].idstr)
+ g_free((*uids)[i].idstr);
+ }
+ g_clear_pointer(uids, g_free);
+}
+
+int
+virGetSubIDs(virSubID **retval, const char *file)
+{
+ g_autofree char *buf = NULL;
+ g_auto(GStrv) lines = NULL;
+ virSubID *entries = NULL;
+ size_t i = 0;
+ size_t len;
+ int ret = -1;
+
+ *retval = NULL;
+
+ if (virFileReadAll(file, BUFSIZ, &buf) < 0)
+ return -1;
+
+ lines = g_strsplit(buf, "\n", 0);
+ if (!lines)
+ return -1;
+
+ len = g_strv_length(lines);
+ entries = g_new0(virSubID, len);
+
+ for (i = 0; i < len; i++) {
+ g_auto(GStrv) fields = NULL;
+ unsigned long ulong_id;
+
+ fields = g_strsplit(lines[i], ":", 0);
+ if (!fields)
+ goto cleanup;
+
+ if (g_strv_length(fields) != 3)
+ break;
+
+ if (g_ascii_isdigit(fields[0][0])) {
+ if (virStrToLong_ul(fields[0], NULL, 10, &ulong_id) < 0)
+ goto cleanup;
+ entries[i].id = ulong_id;
+ } else {
+ entries[i].idstr = g_strdup(fields[0]);
+ }
+
+ if (virStrToLong_ul(fields[1], NULL, 10, &ulong_id) < 0)
+ goto cleanup;
+ entries[i].start = ulong_id;
+
+ if (virStrToLong_ul(fields[2], NULL, 10, &ulong_id) < 0)
+ goto cleanup;
+ entries[i].range = ulong_id;
+ }
+
+ *retval = g_steal_pointer(&entries);
+ ret = i;
+ cleanup:
+ if (entries)
+ virSubIDsFree(&entries, len);
+ return ret;
+}
+
#if WITH_CAPNG
/* Set the real and effective uid and gid to the given values, while
* maintaining the capabilities indicated by bits in @capBits. Return
char *virGetGroupName(gid_t gid) G_NO_INLINE;
int virGetGroupList(uid_t uid, gid_t group, gid_t **groups)
ATTRIBUTE_NONNULL(3);
+
+typedef struct _virSubID {
+ uid_t id;
+ char *idstr;
+ uid_t start;
+ uid_t range;
+} virSubID;
+
+int virGetSubIDs(virSubID **ret, const char *file);
+void virSubIDsFree(virSubID **uids, size_t n);
+
+
int virGetUserID(const char *name,
uid_t *uid) G_GNUC_WARN_UNUSED_RESULT;
int virGetGroupID(const char *name,
}
+static int
+testGetSubIDs(const void *data G_GNUC_UNUSED)
+{
+ g_autofree char *subuid_file = g_strdup_printf("%s/virutiltestdata/subuid", abs_srcdir);
+ virSubID *subids = NULL;
+ int len = 0;
+ int ret = -1;
+
+ if ((len = virGetSubIDs(&subids, subuid_file)) < 0) {
+ VIR_TEST_DEBUG("virGetSubIDs failed");
+ goto cleanup;
+ }
+
+ if (len != 4) {
+ VIR_TEST_DEBUG("virGetSubIDs returned %d (expected 4)", len);
+ goto cleanup;
+ }
+
+ if (STRNEQ(subids[0].idstr, "joe")) {
+ VIR_TEST_DEBUG("virGetSubIDs returned wrong name for entry 0: '%s'", NULLSTR(subids[0].idstr));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (len >= 0)
+ virSubIDsFree(&subids, len);
+ return ret;
+}
+
+
static int
mymain(void)
{
DO_TEST(OverflowCheckMacro);
DO_TEST(KernelCmdlineNextParam);
DO_TEST(KernelCmdlineMatchParam);
+ DO_TEST(GetSubIDs);
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}