[pacman-dev] [RFC] Add Server-specific options, currently only PinnedPubKey

Travis Burtrum travis.archlinux at burtrum.org
Wed Nov 2 17:13:15 UTC 2016


Hi all,

Here is a rough go at a patch for server-specific options.  It works,
but what still needs done is:

1. Changing alpm_db_remove_server, does it still take a char* url?
   or the entire alpm_server_t struct that alpm_db_add_server does? 
2. Deciding what to do with alpm_cb_fetch's signature, should a new
   struct be added to make adding new server options easier?  Should
   alpm_server_t be sent in instead? (this gets messy in some places).
3. Documentation updates.

The end result looks like:

Server = https://example.org/ PinnedPubKey=sha256//eEHQC9au2QRAP1FnvcYEsmvXT7511EXQ2gw8ppBfseM=

Is this a sound approach?  Any other comments appreciated.

Thanks,
Travis

>From ebf448cd4da77bdea833dc75e60de5c992f21eaf Mon Sep 17 00:00:00 2001
From: Travis Burtrum <travis.archlinux at burtrum.org>
Date: Tue, 1 Nov 2016 23:02:43 -0400
Subject: [PATCH] [RFC] Add Server-specific options, currently only
 PinnedPubKey supported

---
 lib/libalpm/Makefile.am |  1 +
 lib/libalpm/alpm.c      |  1 +
 lib/libalpm/alpm.h      | 18 ++++++++--
 lib/libalpm/be_sync.c   |  7 +++-
 lib/libalpm/db.c        | 16 ++++++---
 lib/libalpm/dload.c     |  8 ++++-
 lib/libalpm/dload.h     |  1 +
 lib/libalpm/hook.c      | 10 +++---
 lib/libalpm/server.c    | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/libalpm/server.h    | 36 +++++++++++++++++++
 lib/libalpm/sync.c      |  4 ++-
 src/pacman/conf.c       | 68 ++++++++++++++++++++++++++++--------
 12 files changed, 234 insertions(+), 27 deletions(-)
 create mode 100644 lib/libalpm/server.c
 create mode 100644 lib/libalpm/server.h

diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am
index f4f20e6..197459c 100644
--- a/lib/libalpm/Makefile.am
+++ b/lib/libalpm/Makefile.am
@@ -48,6 +48,7 @@ libalpm_la_SOURCES = \
 	libarchive-compat.h \
 	log.h log.c \
 	package.h package.c \
+	server.h server.c \
 	pkghash.h pkghash.c \
 	rawstr.c \
 	remove.h remove.c \
diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c
index 5225e4f..82df39f 100644
--- a/lib/libalpm/alpm.c
+++ b/lib/libalpm/alpm.c
@@ -29,6 +29,7 @@
 #include "alpm.h"
 #include "alpm_list.h"
 #include "handle.h"
+#include "server.h"
 #include "log.h"
 #include "util.h"
 
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 2d2491d..53b48e5 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -48,6 +48,7 @@ typedef struct __alpm_handle_t alpm_handle_t;
 typedef struct __alpm_db_t alpm_db_t;
 typedef struct __alpm_pkg_t alpm_pkg_t;
 typedef struct __alpm_trans_t alpm_trans_t;
+typedef struct __alpm_server_t alpm_server_t;
 
 /** @addtogroup alpm_api_errors Error Codes
  * @{
@@ -750,11 +751,12 @@ typedef void (*alpm_cb_totaldl)(off_t total);
  * @param url the URL of the file to be downloaded
  * @param localpath the directory to which the file should be downloaded
  * @param force whether to force an update, even if the file is the same
+ * @param pinnedpubkey a pinned public key string
  * @return 0 on success, 1 if the file exists and is identical, -1 on
  * error.
  */
 typedef int (*alpm_cb_fetch)(const char *url, const char *localpath,
-		int force);
+		int force, const char *pinnedpubkey);
 
 /** Fetch a remote pkg.
  * @param handle the context handle
@@ -998,7 +1000,7 @@ int alpm_db_get_valid(alpm_db_t *db);
  */
 alpm_list_t *alpm_db_get_servers(const alpm_db_t *db);
 int alpm_db_set_servers(alpm_db_t *db, alpm_list_t *servers);
-int alpm_db_add_server(alpm_db_t *db, const char *url);
+int alpm_db_add_server(alpm_db_t *db, alpm_server_t *url);
 int alpm_db_remove_server(alpm_db_t *db, const char *url);
 /** @} */
 
@@ -1061,6 +1063,18 @@ int alpm_db_get_usage(alpm_db_t *db, int *usage);
 
 /** @} */
 
+alpm_server_t *alpm_server_new(void);
+int alpm_server_free(alpm_server_t *server);
+
+const char *alpm_server_get_url(const alpm_server_t *server);
+const char *alpm_server_get_pinnedpubkey(const alpm_server_t *server);
+int alpm_server_set_url(alpm_server_t *server, const char *url);
+int alpm_server_set_pinnedpubkey(alpm_server_t *server, const char *pinnedpubkey);
+
+char **alpm_wordsplit(char *str);
+int alpm_wordsplit_free(char **ws);
+
+
 /** @addtogroup alpm_api_packages Package Functions
  * Functions to manipulate libalpm packages
  * @{
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index 7774975..79a35d2 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -219,7 +219,8 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
 	dbext = db->handle->dbext;
 
 	for(i = db->servers; i; i = i->next) {
-		const char *server = i->data, *final_db_url = NULL;
+		alpm_server_t *server_t = i->data;
+		const char *server = alpm_server_get_url(server_t), *final_db_url = NULL;
 		struct dload_payload payload;
 		size_t len;
 		int sig_ret = 0;
@@ -242,6 +243,8 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
 		payload.handle = handle;
 		payload.force = force;
 		payload.unlink_on_fail = 1;
+		
+		payload.pinnedpubkey = alpm_server_get_pinnedpubkey(server_t);
 
 		ret = _alpm_download(&payload, syncpath, NULL, &final_db_url);
 		_alpm_dload_payload_reset(&payload);
@@ -297,6 +300,8 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
 			/* set hard upper limit of 16KiB */
 			payload.max_size = 16 * 1024;
 
+			payload.pinnedpubkey = alpm_server_get_pinnedpubkey(server_t);
+
 			sig_ret = _alpm_download(&payload, syncpath, NULL, NULL);
 			/* errors_ok suppresses error messages, but not the return code */
 			sig_ret = payload.errors_ok ? 0 : sig_ret;
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index 5d78ee5..7c8dd4b 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -150,7 +150,8 @@ alpm_list_t SYMEXPORT *alpm_db_get_servers(const alpm_db_t *db)
 int SYMEXPORT alpm_db_set_servers(alpm_db_t *db, alpm_list_t *servers)
 {
 	ASSERT(db != NULL, return -1);
-	FREELIST(db->servers);
+	alpm_list_free_inner(db->servers, (alpm_list_fn_free) alpm_server_free);
+	alpm_list_free(db->servers);
 	db->servers = servers;
 	return 0;
 }
@@ -173,9 +174,10 @@ static char *sanitize_url(const char *url)
  * @param url url of the server
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int SYMEXPORT alpm_db_add_server(alpm_db_t *db, const char *url)
+int SYMEXPORT alpm_db_add_server(alpm_db_t *db, alpm_server_t *server)
 {
 	char *newurl;
+	const char *url = alpm_server_get_url(server);
 
 	/* Sanity checks */
 	ASSERT(db != NULL, return -1);
@@ -186,7 +188,12 @@ int SYMEXPORT alpm_db_add_server(alpm_db_t *db, const char *url)
 	if(!newurl) {
 		return -1;
 	}
-	db->servers = alpm_list_add(db->servers, newurl);
+	
+	alpm_server_t *copy = alpm_server_new();
+	alpm_server_set_url(copy, newurl);
+	alpm_server_set_pinnedpubkey(copy, alpm_server_get_pinnedpubkey(server));
+	
+	db->servers = alpm_list_add(db->servers, copy);
 	_alpm_log(db->handle, ALPM_LOG_DEBUG, "adding new server URL to database '%s': %s\n",
 			db->treename, newurl);
 
@@ -348,7 +355,8 @@ void _alpm_db_free(alpm_db_t *db)
 	/* cleanup pkgcache */
 	_alpm_db_free_pkgcache(db);
 	/* cleanup server list */
-	FREELIST(db->servers);
+	alpm_list_free_inner(db->servers, (alpm_list_fn_free) alpm_server_free);
+	alpm_list_free(db->servers);
 	FREE(db->_path);
 	FREE(db->treename);
 	FREE(db);
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index 9d80358..6d5b371 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -327,6 +327,12 @@ static void curl_set_handle_opts(struct dload_payload *payload,
 		curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent);
 	}
 
+	if(payload->pinnedpubkey != NULL) {
+		_alpm_log(handle, ALPM_LOG_DEBUG,
+				"using curl pinnedpubkey: %s\n", payload->pinnedpubkey);
+		curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, payload->pinnedpubkey);
+	}
+
 	if(!payload->allow_resume && !payload->force && payload->destfile_name &&
 			stat(payload->destfile_name, &st) == 0) {
 		/* start from scratch, but only download if our local is out of date. */
@@ -646,7 +652,7 @@ int _alpm_download(struct dload_payload *payload, const char *localpath,
 		RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1);
 #endif
 	} else {
-		int ret = handle->fetchcb(payload->fileurl, localpath, payload->force);
+		int ret = handle->fetchcb(payload->fileurl, localpath, payload->force, payload->pinnedpubkey);
 		if(ret == -1 && !payload->errors_ok) {
 			RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1);
 		}
diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h
index 427c486..9b8453a 100644
--- a/lib/libalpm/dload.h
+++ b/lib/libalpm/dload.h
@@ -41,6 +41,7 @@ struct dload_payload {
 	int errors_ok;
 	int unlink_on_fail;
 	int trust_remote_name;
+	const char *pinnedpubkey;
 #ifdef HAVE_LIBCURL
 	CURLcode curlerr;       /* last error produced by curl */
 #endif
diff --git a/lib/libalpm/hook.c b/lib/libalpm/hook.c
index ccde225..9e84d78 100644
--- a/lib/libalpm/hook.c
+++ b/lib/libalpm/hook.c
@@ -71,7 +71,7 @@ static void _alpm_trigger_free(struct _alpm_trigger_t *trigger)
 	}
 }
 
-static void _alpm_wordsplit_free(char **ws)
+int SYMEXPORT alpm_wordsplit_free(char **ws)
 {
 	if(ws) {
 		char **c;
@@ -79,7 +79,9 @@ static void _alpm_wordsplit_free(char **ws)
 			free(*c);
 		}
 		free(ws);
+		return 0;
 	}
+	return -1;
 }
 
 static void _alpm_hook_free(struct _alpm_hook_t *hook)
@@ -87,7 +89,7 @@ static void _alpm_hook_free(struct _alpm_hook_t *hook)
 	if(hook) {
 		free(hook->name);
 		free(hook->desc);
-		_alpm_wordsplit_free(hook->cmd);
+		alpm_wordsplit_free(hook->cmd);
 		alpm_list_free_inner(hook->triggers, (alpm_list_fn_free) _alpm_trigger_free);
 		alpm_list_free(hook->triggers);
 		alpm_list_free(hook->matches);
@@ -158,7 +160,7 @@ static int _alpm_hook_validate(alpm_handle_t *handle,
 	return ret;
 }
 
-static char **_alpm_wordsplit(char *str)
+char SYMEXPORT **alpm_wordsplit(char *str)
 {
 	char *c = str, *end;
 	char **out = NULL, **outsave;
@@ -330,7 +332,7 @@ static int _alpm_hook_parse_cb(const char *file, int line,
 		} else if(strcmp(key, "NeedsTargets") == 0) {
 			hook->needs_targets = 1;
 		} else if(strcmp(key, "Exec") == 0) {
-			if((hook->cmd = _alpm_wordsplit(value)) == NULL) {
+			if((hook->cmd = alpm_wordsplit(value)) == NULL) {
 				if(errno == EINVAL) {
 					error(_("hook %s line %d: invalid value %s\n"), file, line, value);
 				} else {
diff --git a/lib/libalpm/server.c b/lib/libalpm/server.c
new file mode 100644
index 0000000..29aa365
--- /dev/null
+++ b/lib/libalpm/server.c
@@ -0,0 +1,91 @@
+/*
+ *  server.c
+ *
+ *  Copyright (c) 2006-2016 Pacman Development Team <pacman-dev at archlinux.org>
+ *  Copyright (c) 2002-2006 by Judd Vinet <jvinet at zeroflux.org>
+ *  Copyright (c) 2005 by Aurelien Foret <orelien at chez.com>
+ *  Copyright (c) 2005, 2006 by Christian Hamar <krics at linuxforum.hu>
+ *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos at frugalware.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+/* libalpm */
+#include "server.h"
+#include "alpm_list.h"
+#include "log.h"
+#include "util.h"
+#include "db.h"
+#include "delta.h"
+#include "handle.h"
+#include "deps.h"
+
+/** \addtogroup alpm_packages Server Functions
+ * @brief Functions to manipulate libalpm servers
+ * @{
+ */
+
+alpm_server_t SYMEXPORT *alpm_server_new(void)
+{
+	alpm_server_t *server;
+
+	CALLOC(server, 1, sizeof(alpm_server_t), return NULL);
+
+	return server;
+}
+
+/** Free a package. */
+int SYMEXPORT alpm_server_free(alpm_server_t *server)
+{
+	ASSERT(server != NULL, return -1);
+	FREE(server->url);
+	FREE(server->pinnedpubkey);
+	return 0;
+}
+
+const char SYMEXPORT *alpm_server_get_url(const alpm_server_t *server)
+{
+	ASSERT(server != NULL, return NULL);
+	return server->url;
+}
+
+const char SYMEXPORT *alpm_server_get_pinnedpubkey(const alpm_server_t *server)
+{
+	ASSERT(server != NULL, return NULL);
+	return server->pinnedpubkey;
+}
+
+int SYMEXPORT alpm_server_set_url(alpm_server_t *server, const char *url)
+{
+	ASSERT(server != NULL, return -1);
+	ASSERT(url != NULL, return 0);
+	FREE(server->url);
+	server->url = strdup(url);
+	return 0;
+}
+
+int SYMEXPORT alpm_server_set_pinnedpubkey(alpm_server_t *server, const char *pinnedpubkey)
+{
+	ASSERT(server != NULL, return -1);
+	ASSERT(pinnedpubkey != NULL, return 0);
+	FREE(server->pinnedpubkey);
+	server->pinnedpubkey = strdup(pinnedpubkey);
+	return 0;
+}
+
+/* vim: set noet: */
diff --git a/lib/libalpm/server.h b/lib/libalpm/server.h
new file mode 100644
index 0000000..b88f9ee
--- /dev/null
+++ b/lib/libalpm/server.h
@@ -0,0 +1,36 @@
+/*
+ *  server.h
+ *
+ *  Copyright (c) 2006-2016 Pacman Development Team <pacman-dev at archlinux.org>
+ *  Copyright (c) 2002-2006 by Judd Vinet <jvinet at zeroflux.org>
+ *  Copyright (c) 2005 by Aurelien Foret <orelien at chez.com>
+ *  Copyright (c) 2006 by David Kimpe <dnaku at frugalware.org>
+ *  Copyright (c) 2005, 2006 by Christian Hamar <krics at linuxforum.hu>
+ *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos at frugalware.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef ALPM_SERVER_H
+#define ALPM_SERVER_H
+
+#include "alpm.h"
+
+struct __alpm_server_t {
+	char *url;
+	char *pinnedpubkey;
+};
+
+#endif /* ALPM_SERVER_H */
+
+/* vim: set noet: */
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 837639d..c54f951 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -933,7 +933,9 @@ static int download_single_file(alpm_handle_t *handle, struct dload_payload *pay
 
 	EVENT(handle, &event);
 	for(server = payload->servers; server; server = server->next) {
-		const char *server_url = server->data;
+		const alpm_server_t *server_t = server->data;
+		payload->pinnedpubkey = alpm_server_get_pinnedpubkey(server_t);
+		const char *server_url = alpm_server_get_url(server_t);
 		size_t len;
 
 		/* print server + filename into a buffer */
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index d8d64fb..4905310 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -164,7 +164,8 @@ void config_repo_free(config_repo_t *repo)
 		return;
 	}
 	free(repo->name);
-	FREELIST(repo->servers);
+	alpm_list_free_inner(repo->servers, (alpm_list_fn_free) alpm_server_free);
+	alpm_list_free(repo->servers);
 	free(repo);
 }
 
@@ -204,7 +205,7 @@ static char *get_tempfile(const char *path, const char *filename)
 
 /** External fetch callback */
 static int download_with_xfercommand(const char *url, const char *localpath,
-		int force)
+		int force, const char *pinnedpubkey)
 {
 	int ret = 0, retval;
 	int usepart = 0;
@@ -232,6 +233,16 @@ static int download_with_xfercommand(const char *url, const char *localpath,
 	}
 
 	tempcmd = strdup(config->xfercommand);
+	/* replace all occurrences of %p with pinnedpubkey */
+	if(strstr(tempcmd, "%p")) {
+		if(pinnedpubkey == NULL) {
+			parsedcmd = strreplace(tempcmd, "%p", "");
+		} else {
+			parsedcmd = strreplace(tempcmd, "%p", pinnedpubkey);
+		}
+		free(tempcmd);
+		tempcmd = parsedcmd;
+	}
 	/* replace all occurrences of %o with fn.part */
 	if(strstr(tempcmd, "%o")) {
 		usepart = 1;
@@ -613,16 +624,17 @@ static int _parse_options(const char *key, char *value,
 	return 0;
 }
 
-static int _add_mirror(alpm_db_t *db, char *value)
+static int _add_mirror(alpm_db_t *db, alpm_server_t *server)
 {
+	const char *value = alpm_server_get_url(server);
 	const char *dbname = alpm_db_get_name(db);
 	/* let's attempt a replacement for the current repo */
 	char *temp = strreplace(value, "$repo", dbname);
 	/* let's attempt a replacement for the arch */
 	const char *arch = config->arch;
-	char *server;
+	char *url;
 	if(arch) {
-		server = strreplace(temp, "$arch", arch);
+		url = strreplace(temp, "$arch", arch);
 		free(temp);
 	} else {
 		if(strstr(temp, "$arch")) {
@@ -632,18 +644,19 @@ static int _add_mirror(alpm_db_t *db, char *value)
 					value, "$arch", "Architecture");
 			return 1;
 		}
-		server = temp;
+		url = temp;
 	}
+	alpm_server_set_url(server, url);
 
 	if(alpm_db_add_server(db, server) != 0) {
 		/* pm_errno is set by alpm_db_setserver */
 		pm_printf(ALPM_LOG_ERROR, _("could not add server URL to database '%s': %s (%s)\n"),
-				dbname, server, alpm_strerror(alpm_errno(config->handle)));
-		free(server);
+				dbname, url, alpm_strerror(alpm_errno(config->handle)));
+		free(url);
 		return 1;
 	}
 
-	free(server);
+	free(url);
 	return 0;
 }
 
@@ -669,11 +682,11 @@ static int register_repo(config_repo_t *repo)
 	alpm_db_set_usage(db, repo->usage == 0 ? ALPM_DB_USAGE_ALL : repo->usage);
 
 	for(i = repo->servers; i; i = alpm_list_next(i)) {
-		char *value = i->data;
-		if(_add_mirror(db, value) != 0) {
+		alpm_server_t *server = i->data;
+		if(_add_mirror(db, server) != 0) {
 			pm_printf(ALPM_LOG_ERROR,
 					_("could not add mirror '%s' to database '%s' (%s)\n"),
-					value, repo->name, alpm_strerror(alpm_errno(config->handle)));
+					alpm_server_get_url(server), repo->name, alpm_strerror(alpm_errno(config->handle)));
 			return 1;
 		}
 	}
@@ -883,6 +896,7 @@ static int _parse_repo(const char *key, char *value, const char *file,
 {
 	int ret = 0;
 	config_repo_t *repo = section->repo;
+	char *server_key, *server_value;
 
 	if(strcmp(key, "Server") == 0) {
 		if(!value) {
@@ -890,7 +904,34 @@ static int _parse_repo(const char *key, char *value, const char *file,
 					file, line, key);
 			ret = 1;
 		} else {
-			repo->servers = alpm_list_add(repo->servers, strdup(value));
+			alpm_server_t *server = alpm_server_new();
+			char **cmd = alpm_wordsplit(value);
+			alpm_server_set_url(server, cmd[0]);
+			char **c;
+			for(c = cmd + 1; *c; c++) {
+				server_key = *c;
+				server_value = *c;
+				strsep(&server_value, "=");
+				strtrim(server_key);
+				strtrim(server_value);
+				
+				if(strcmp(server_key, "PinnedPubKey") == 0) {
+					if(!server_value) {
+						pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"),
+								file, line, server_key);
+					} else {
+						alpm_server_set_pinnedpubkey(server, server_value);
+						pm_printf(ALPM_LOG_DEBUG, "server config: server: %s, pinnedpubkey: %s\n", cmd[0], server_value);
+					}
+				} else {
+					pm_printf(ALPM_LOG_WARNING,
+							_("config file %s, line %d: directive '%s' in section '%s', server '%s', key '%s' not recognized.\n"),
+							file, line, key, repo->name, cmd[0], server_key);
+				}
+				
+			}
+			alpm_wordsplit_free(cmd);
+			repo->servers = alpm_list_add(repo->servers, server);
 		}
 	} else if(strcmp(key, "SigLevel") == 0) {
 		if(!value) {
@@ -920,7 +961,6 @@ static int _parse_repo(const char *key, char *value, const char *file,
 				_("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
 				file, line, key, repo->name);
 	}
-
 	return ret;
 }
 
-- 
2.10.2


More information about the pacman-dev mailing list