Commit Diff


commit - f024663dea0dea05a0d4c17d2314f38f73e85bc6
commit + bd3d9e54cb422cb58d52b267c6a8afc3376842d2
blob - /dev/null
blob + 436c3e0854074e30dfdfca92ce23d908e5c94bbf (mode 644)
--- /dev/null
+++ lib/gitproto.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
+ * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "got_error.h"
+#include "got_path.h"
+
+#include "got_lib_gitproto.h"
+
+#ifndef nitems
+#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+static const struct got_error *
+tokenize_refline(char **tokens, char *line, int len, int maxtokens)
+{
+	const struct got_error *err = NULL;
+	char *p;
+	size_t i, n = 0;
+
+	for (i = 0; i < maxtokens; i++)
+		tokens[i] = NULL;
+
+	for (i = 0; n < len && i < maxtokens; i++) {
+		while (isspace(*line)) {
+			line++;
+			n++;
+		}
+		p = line;
+		while (*line != '\0' && n < len &&
+		    (!isspace(*line) || i == maxtokens - 1)) {
+			line++;
+			n++;
+		}
+		tokens[i] = strndup(p, line - p);
+		if (tokens[i] == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		/* Skip \0 field-delimiter at end of token. */
+		while (line[0] == '\0' && n < len) {
+			line++;
+			n++;
+		}
+	}
+	if (i <= 2)
+		err = got_error(GOT_ERR_BAD_PACKET);
+done:
+	if (err) {
+		int j;
+		for (j = 0; j < i; j++) {
+			free(tokens[j]);
+			tokens[j] = NULL;
+		}
+	}
+	return err;
+}
+
+const struct got_error *
+got_gitproto_parse_refline(char **id_str, char **refname,
+    char **server_capabilities, char *line, int len)
+{
+	const struct got_error *err = NULL;
+	char *tokens[3];
+
+	err = tokenize_refline(tokens, line, len, nitems(tokens));
+	if (err)
+		return err;
+
+	if (tokens[0])
+		*id_str = tokens[0];
+	if (tokens[1])
+		*refname = tokens[1];
+	if (tokens[2]) {
+		char *p;
+		*server_capabilities = tokens[2];
+		p = strrchr(*server_capabilities, '\n');
+		if (p)
+			*p = '\0';
+	}
+
+	return NULL;
+}
+
+static const struct got_error *
+match_capability(char **my_capabilities, const char *capa,
+    const struct got_capability *mycapa)
+{
+	char *equalsign;
+	char *s;
+
+	equalsign = strchr(capa, '=');
+	if (equalsign) {
+		if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
+			return NULL;
+	} else {
+		if (strcmp(capa, mycapa->key) != 0)
+			return NULL;
+	}
+
+	if (asprintf(&s, "%s %s%s%s",
+	    *my_capabilities != NULL ? *my_capabilities : "",
+	    mycapa->key,
+	    mycapa->value != NULL ? "=" : "",
+	    mycapa->value != NULL? mycapa->value : "") == -1)
+		return got_error_from_errno("asprintf");
+
+	free(*my_capabilities);
+	*my_capabilities = s;
+	return NULL;
+}
+
+static const struct got_error *
+add_symref(struct got_pathlist_head *symrefs, char *capa)
+{
+	const struct got_error *err = NULL;
+	char *colon, *name = NULL, *target = NULL;
+
+	/* Need at least "A:B" */
+	if (strlen(capa) < 3)
+		return NULL;
+
+	colon = strchr(capa, ':');
+	if (colon == NULL)
+		return NULL;
+
+	*colon = '\0';
+	name = strdup(capa);
+	if (name == NULL)
+		return got_error_from_errno("strdup");
+
+	target = strdup(colon + 1);
+	if (target == NULL) {
+		err = got_error_from_errno("strdup");
+		goto done;
+	}
+
+	/* We can't validate the ref itself here. The main process will. */
+	err = got_pathlist_append(symrefs, name, target);
+done:
+	if (err) {
+		free(name);
+		free(target);
+	}
+	return err;
+}
+
+const struct got_error *
+got_gitproto_match_capabilities(char **common_capabilities,
+    struct got_pathlist_head *symrefs, char *server_capabilities,
+    const struct got_capability my_capabilities[], size_t ncapa)
+{
+	const struct got_error *err = NULL;
+	char *capa, *equalsign;
+	size_t i;
+
+	*common_capabilities = NULL;
+	do {
+		capa = strsep(&server_capabilities, " ");
+		if (capa == NULL)
+			return NULL;
+
+		equalsign = strchr(capa, '=');
+		if (equalsign != NULL && symrefs != NULL &&
+		    strncmp(capa, "symref", equalsign - capa) == 0) {
+			err = add_symref(symrefs, equalsign + 1);
+			if (err)
+				break;
+			continue;
+		}
+
+		for (i = 0; i < ncapa; i++) {
+			err = match_capability(common_capabilities,
+			    capa, &my_capabilities[i]);
+			if (err)
+				break;
+		}
+	} while (capa);
+
+	if (*common_capabilities == NULL) {
+		*common_capabilities = strdup("");
+		if (*common_capabilities == NULL)
+			err = got_error_from_errno("strdup");
+	}
+	return err;
+}
blob - /dev/null
blob + cffe349e03b4a8a0cd9126b511ed9198af1c3c57 (mode 644)
--- /dev/null
+++ lib/got_lib_gitproto.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
+ * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define GOT_CAPA_AGENT			"agent"
+#define GOT_CAPA_OFS_DELTA		"ofs-delta"
+#define GOT_CAPA_SIDE_BAND_64K		"side-band-64k"
+#define GOT_CAPA_REPORT_STATUS		"report-status"
+#define GOT_CAPA_DELETE_REFS		"delete-refs"
+
+#define GOT_SIDEBAND_PACKFILE_DATA	1
+#define GOT_SIDEBAND_PROGRESS_INFO	2
+#define GOT_SIDEBAND_ERROR_INFO		3
+
+struct got_capability {
+	const char *key;
+	const char *value;
+};
+
+struct got_pathlist_head;
+
+const struct got_error *got_gitproto_parse_refline(char **id_str,
+    char **refname, char **server_capabilities, char *line, int len);
+const struct got_error *got_gitproto_match_capabilities(
+    char **common_capabilities,
+    struct got_pathlist_head *symrefs, char *server_capabilities,
+    const struct got_capability my_capabilities[], size_t ncapa);
blob - 322eb5182bf517fe519edba355c7eb691286ed23
blob + 7df6b00656bdfc711605a13a29e30f4b21aa2f3a
--- libexec/got-fetch-pack/Makefile
+++ libexec/got-fetch-pack/Makefile
@@ -4,7 +4,7 @@
 
 PROG=		got-fetch-pack
 SRCS=		got-fetch-pack.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pkt.c
+		path.c privsep.c sha1.c pkt.c gitproto.c
 
 CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
 LDADD = -lutil -lz
blob - 1b1a71e4dc4357b0153e9ebfa2b776af69bf006b
blob + 42a19bfb5390548d4249bd5c2f9432a6a853b121
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
@@ -49,6 +49,7 @@
 #include "got_lib_privsep.h"
 #include "got_lib_pack.h"
 #include "got_lib_pkt.h"
+#include "got_lib_gitproto.h"
 
 #ifndef nitems
 #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
@@ -58,6 +59,12 @@ struct got_object *indexed;
 static int chattygot;
 static struct got_object_id zhash = {.sha1={0}};
 
+static const struct got_capability got_capabilities[] = {
+	{ GOT_CAPA_AGENT, "got/" GOT_VERSION_STR },
+	{ GOT_CAPA_OFS_DELTA, NULL },
+	{ GOT_CAPA_SIDE_BAND_64K, NULL },
+};
+
 static void
 match_remote_ref(struct got_pathlist_head *have_refs,
     struct got_object_id *my_id, char *refname)
@@ -114,201 +121,9 @@ match_wanted_ref(const char *refname, const char *want
 
 	/* Allow exact match. */
 	return (strcmp(refname, wanted_ref) == 0);
-}
-
-static const struct got_error *
-tokenize_refline(char **tokens, char *line, int len, int maxtokens)
-{
-	const struct got_error *err = NULL;
-	char *p;
-	size_t i, n = 0;
-
-	for (i = 0; i < maxtokens; i++)
-		tokens[i] = NULL;
-
-	for (i = 0; n < len && i < maxtokens; i++) {
-		while (isspace(*line)) {
-			line++;
-			n++;
-		}
-		p = line;
-		while (*line != '\0' && n < len &&
-		    (!isspace(*line) || i == maxtokens - 1)) {
-			line++;
-			n++;
-		}
-		tokens[i] = strndup(p, line - p);
-		if (tokens[i] == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		/* Skip \0 field-delimiter at end of token. */
-		while (line[0] == '\0' && n < len) {
-			line++;
-			n++;
-		}
-	}
-	if (i <= 2)
-		err = got_error(GOT_ERR_BAD_PACKET);
-done:
-	if (err) {
-		int j;
-		for (j = 0; j < i; j++) {
-			free(tokens[j]);
-			tokens[j] = NULL;
-		}
-	}
-	return err;
-}
-
-static const struct got_error *
-parse_refline(char **id_str, char **refname, char **server_capabilities,
-    char *line, int len)
-{
-	const struct got_error *err = NULL;
-	char *tokens[3];
-
-	err = tokenize_refline(tokens, line, len, nitems(tokens));
-	if (err)
-		return err;
-
-	if (tokens[0])
-		*id_str = tokens[0];
-	if (tokens[1])
-		*refname = tokens[1];
-	if (tokens[2]) {
-		char *p;
-		*server_capabilities = tokens[2];
-		p = strrchr(*server_capabilities, '\n');
-		if (p)
-			*p = '\0';
-	}
-
-	return NULL;
-}
-
-#define GOT_CAPA_AGENT			"agent"
-#define GOT_CAPA_OFS_DELTA		"ofs-delta"
-#define GOT_CAPA_SIDE_BAND_64K		"side-band-64k"
-
-#define GOT_SIDEBAND_PACKFILE_DATA	1
-#define GOT_SIDEBAND_PROGRESS_INFO	2
-#define GOT_SIDEBAND_ERROR_INFO		3
-
-
-struct got_capability {
-	const char *key;
-	const char *value;
-};
-static const struct got_capability got_capabilities[] = {
-	{ GOT_CAPA_AGENT, "got/" GOT_VERSION_STR },
-	{ GOT_CAPA_OFS_DELTA, NULL },
-	{ GOT_CAPA_SIDE_BAND_64K, NULL },
-};
-
-static const struct got_error *
-match_capability(char **my_capabilities, const char *capa,
-    const struct got_capability *mycapa)
-{
-	char *equalsign;
-	char *s;
-
-	equalsign = strchr(capa, '=');
-	if (equalsign) {
-		if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
-			return NULL;
-	} else {
-		if (strcmp(capa, mycapa->key) != 0)
-			return NULL;
-	}
-
-	if (asprintf(&s, "%s %s%s%s",
-	    *my_capabilities != NULL ? *my_capabilities : "",
-	    mycapa->key,
-	    mycapa->value != NULL ? "=" : "",
-	    mycapa->value != NULL? mycapa->value : "") == -1)
-		return got_error_from_errno("asprintf");
-
-	free(*my_capabilities);
-	*my_capabilities = s;
-	return NULL;
-}
-
-static const struct got_error *
-add_symref(struct got_pathlist_head *symrefs, char *capa)
-{
-	const struct got_error *err = NULL;
-	char *colon, *name = NULL, *target = NULL;
-
-	/* Need at least "A:B" */
-	if (strlen(capa) < 3)
-		return NULL;
-
-	colon = strchr(capa, ':');
-	if (colon == NULL)
-		return NULL;
-
-	*colon = '\0';
-	name = strdup(capa);
-	if (name == NULL)
-		return got_error_from_errno("strdup");
-
-	target = strdup(colon + 1);
-	if (target == NULL) {
-		err = got_error_from_errno("strdup");
-		goto done;
-	}
-
-	/* We can't validate the ref itself here. The main process will. */
-	err = got_pathlist_append(symrefs, name, target);
-done:
-	if (err) {
-		free(name);
-		free(target);
-	}
-	return err;
 }
 
 static const struct got_error *
-match_capabilities(char **my_capabilities, struct got_pathlist_head *symrefs,
-    char *server_capabilities)
-{
-	const struct got_error *err = NULL;
-	char *capa, *equalsign;
-	size_t i;
-
-	*my_capabilities = NULL;
-	do {
-		capa = strsep(&server_capabilities, " ");
-		if (capa == NULL)
-			return NULL;
-
-		equalsign = strchr(capa, '=');
-		if (equalsign != NULL &&
-		    strncmp(capa, "symref", equalsign - capa) == 0) {
-			err = add_symref(symrefs, equalsign + 1);
-			if (err)
-				break;
-			continue;
-		}
-
-		for (i = 0; i < nitems(got_capabilities); i++) {
-			err = match_capability(my_capabilities,
-			    capa, &got_capabilities[i]);
-			if (err)
-				break;
-		}
-	} while (capa);
-
-	if (*my_capabilities == NULL) {
-		*my_capabilities = strdup("");
-		if (*my_capabilities == NULL)
-			err = got_error_from_errno("strdup");
-	}
-	return err;
-}
-
-static const struct got_error *
 send_fetch_server_progress(struct imsgbuf *ibuf, const char *msg, size_t msglen)
 {
 	if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
@@ -345,8 +160,6 @@ send_fetch_done(struct imsgbuf *ibuf, uint8_t *pack_sh
 	return got_privsep_flush_imsg(ibuf);
 }
 
-
-
 static const struct got_error *
 fetch_progress(struct imsgbuf *ibuf, const char *buf, size_t len)
 {
@@ -534,16 +347,17 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 			err = fetch_error(&buf[4], n - 4);
 			goto done;
 		}
-		err = parse_refline(&id_str, &refname, &server_capabilities,
-		    buf, n);
+		err = got_gitproto_parse_refline(&id_str, &refname,
+		    &server_capabilities, buf, n);
 		if (err)
 			goto done;
 		if (is_firstpkt) {
 			if (chattygot && server_capabilities[0] != '\0')
 				fprintf(stderr, "%s: server capabilities: %s\n",
 				    getprogname(), server_capabilities);
-			err = match_capabilities(&my_capabilities, &symrefs,
-			    server_capabilities);
+			err = got_gitproto_match_capabilities(&my_capabilities,
+			    &symrefs, server_capabilities,
+			    got_capabilities, nitems(got_capabilities));
 			if (err)
 				goto done;
 			if (chattygot)
blob - ddc73e59aea2891c17b777b954fffa3a0bec90c6
blob + c4d5d83a73cd53d7437213cdf349daaec168facd
--- libexec/got-send-pack/Makefile
+++ libexec/got-send-pack/Makefile
@@ -4,7 +4,7 @@
 
 PROG=		got-send-pack
 SRCS=		got-send-pack.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pkt.c
+		path.c privsep.c sha1.c pkt.c gitproto.c
 
 CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
 LDADD = -lutil -lz
blob - 059def3f0aaec687446cd952534fdb52768ea4d8
blob + fc22714cab99aae6b98600a9b4c3bfdb0815c41c
--- libexec/got-send-pack/got-send-pack.c
+++ libexec/got-send-pack/got-send-pack.c
@@ -50,6 +50,7 @@
 #include "got_lib_privsep.h"
 #include "got_lib_pack.h"
 #include "got_lib_pkt.h"
+#include "got_lib_gitproto.h"
 
 #ifndef nitems
 #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
@@ -58,92 +59,6 @@
 struct got_object *indexed;
 static int chattygot;
 
-static const struct got_error *
-tokenize_refline(char **tokens, char *line, int len, int maxtokens)
-{
-	const struct got_error *err = NULL;
-	char *p;
-	size_t i, n = 0;
-
-	for (i = 0; i < maxtokens; i++)
-		tokens[i] = NULL;
-
-	for (i = 0; n < len && i < maxtokens; i++) {
-		while (isspace(*line)) {
-			line++;
-			n++;
-		}
-		p = line;
-		while (*line != '\0' && n < len &&
-		    (!isspace(*line) || i == maxtokens - 1)) {
-			line++;
-			n++;
-		}
-		tokens[i] = strndup(p, line - p);
-		if (tokens[i] == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		/* Skip \0 field-delimiter at end of token. */
-		while (line[0] == '\0' && n < len) {
-			line++;
-			n++;
-		}
-	}
-	if (i <= 2)
-		err = got_error(GOT_ERR_NOT_REF);
-done:
-	if (err) {
-		int j;
-		for (j = 0; j < i; j++) {
-			free(tokens[j]);
-			tokens[j] = NULL;
-		}
-	}
-	return err;
-}
-
-static const struct got_error *
-parse_refline(char **id_str, char **refname, char **server_capabilities,
-    char *line, int len)
-{
-	const struct got_error *err = NULL;
-	char *tokens[3];
-
-	err = tokenize_refline(tokens, line, len, nitems(tokens));
-	if (err)
-		return err;
-
-	if (tokens[0])
-		*id_str = tokens[0];
-	if (tokens[1])
-		*refname = tokens[1];
-	if (tokens[2]) {
-		char *p;
-		*server_capabilities = tokens[2];
-		p = strrchr(*server_capabilities, '\n');
-		if (p)
-			*p = '\0';
-	}
-
-	return NULL;
-}
-
-#define GOT_CAPA_AGENT			"agent"
-#define GOT_CAPA_OFS_DELTA		"ofs-delta"
-#define GOT_CAPA_SIDE_BAND_64K		"side-band-64k"
-#define GOT_CAPA_REPORT_STATUS		"report-status"
-#define GOT_CAPA_DELETE_REFS		"delete-refs"
-
-#define GOT_SIDEBAND_PACKFILE_DATA	1
-#define GOT_SIDEBAND_PROGRESS_INFO	2
-#define GOT_SIDEBAND_ERROR_INFO		3
-
-
-struct got_capability {
-	const char *key;
-	const char *value;
-};
 static const struct got_capability got_capabilities[] = {
 	{ GOT_CAPA_AGENT, "got/" GOT_VERSION_STR },
 	{ GOT_CAPA_OFS_DELTA, NULL },
@@ -153,67 +68,6 @@ static const struct got_capability got_capabilities[] 
 	{ GOT_CAPA_REPORT_STATUS, NULL },
 	{ GOT_CAPA_DELETE_REFS, NULL },
 };
-
-static const struct got_error *
-match_capability(char **my_capabilities, const char *capa,
-    const struct got_capability *mycapa)
-{
-	char *equalsign;
-	char *s;
-
-	equalsign = strchr(capa, '=');
-	if (equalsign) {
-		if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
-			return NULL;
-	} else {
-		if (strcmp(capa, mycapa->key) != 0)
-			return NULL;
-	}
-
-	if (asprintf(&s, "%s %s%s%s",
-	    *my_capabilities != NULL ? *my_capabilities : "",
-	    mycapa->key,
-	    mycapa->value != NULL ? "=" : "",
-	    mycapa->value != NULL? mycapa->value : "") == -1)
-		return got_error_from_errno("asprintf");
-
-	free(*my_capabilities);
-	*my_capabilities = s;
-	return NULL;
-}
-
-static const struct got_error *
-match_capabilities(char **my_capabilities, char *server_capabilities)
-{
-	const struct got_error *err = NULL;
-	char *capa;
-	size_t i;
-
-	*my_capabilities = NULL;
-	do {
-		capa = strsep(&server_capabilities, " ");
-		for (i = 0; capa != NULL && i < nitems(got_capabilities); i++) {
-			err = match_capability(my_capabilities,
-			    capa, &got_capabilities[i]);
-			if (err)
-				goto done;
-		}
-	} while (capa);
-
-	if (*my_capabilities == NULL) {
-		*my_capabilities = strdup("");
-		if (*my_capabilities == NULL) {
-			err = got_error_from_errno("strdup");
-			goto done;
-		}
-	}
-done:
-	if (err) {
-		free(*my_capabilities);
-		*my_capabilities = NULL;
-	}
-	return err;
-}
 
 static const struct got_error *
 send_upload_progress(struct imsgbuf *ibuf, off_t bytes)
@@ -500,16 +354,17 @@ send_pack(int fd, struct got_pathlist_head *refs,
 			err = send_error(&buf[4], n - 4);
 			goto done;
 		}
-		err = parse_refline(&id_str, &refname, &server_capabilities,
-		    buf, n);
+		err = got_gitproto_parse_refline(&id_str, &refname,
+		    &server_capabilities, buf, n);
 		if (err)
 			goto done;
 		if (is_firstpkt) {
 			if (chattygot && server_capabilities[0] != '\0')
 				fprintf(stderr, "%s: server capabilities: %s\n",
 				    getprogname(), server_capabilities);
-			err = match_capabilities(&my_capabilities,
-			    server_capabilities);
+			err = got_gitproto_match_capabilities(&my_capabilities,
+			    NULL, server_capabilities, got_capabilities,
+			    nitems(got_capabilities));
 			if (err)
 				goto done;
 			if (chattygot)