[pacman-dev,3/4] add pacman-conf utility

Message ID 20180113165000.29311-4-andrew.gregory.8@gmail.com
State Accepted, archived
Headers show
Series add pacman-conf utility | expand

Commit Message

Andrew Gregory Jan. 13, 2018, 4:49 p.m. UTC
Parsing pacman's configuration file is non-trivial and extremely
difficult to do correctly from scripts; even our own do it incorrectly.
pacman-conf is a dedicated tool specifically to allow scripts to parse
config files, getting the same value that pacman itself would use.

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
---
 src/util/.gitignore    |   2 +
 src/util/Makefile.am   |  21 ++-
 src/util/pacman-conf.c | 437 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 458 insertions(+), 2 deletions(-)
 create mode 100644 src/util/pacman-conf.c

Comments

Allan McRae Jan. 18, 2018, 4:59 a.m. UTC | #1
On 14/01/18 02:49, Andrew Gregory wrote:
> Parsing pacman's configuration file is non-trivial and extremely
> difficult to do correctly from scripts; even our own do it incorrectly.
> pacman-conf is a dedicated tool specifically to allow scripts to parse
> config files, getting the same value that pacman itself would use.
> 
> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>

The automake changes resulted in a big warning that is fixed by enabling
subdir-objects in configure.ac and ignoring the .dirstamp file it creates.

There was also a directory being created in the src/util with the name
'$(top_srcdir)'.  This is due to using a variable in the paths (no idea
why this is an issue), but replacing it with a relative path "fixes" the
issue.

I'll squash the following into your patch:


From 4c3d7964da2ba4276e4464920fb795e9f973e3ec Mon Sep 17 00:00:00 2001
From: Allan McRae <allan@archlinux.org>
Date: Thu, 18 Jan 2018 14:54:17 +1000
Subject: [PATCH] [SQUASH] Fix automake usage for pacman-conf

Signed-off-by: Allan McRae <allan@archlinux.org>
---
 .gitignore           |  1 +
 configure.ac         |  2 +-
 src/util/Makefile.am | 20 ++++++++++----------
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/.gitignore b/.gitignore
index 499d499b..7399a120 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 *~
 *.o
+.dirstamp
 ABOUT-NLS
 aclocal.m4
 autom4te.cache
diff --git a/configure.ac b/configure.ac
index 86f5bb6e..02afba83 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,7 +60,7 @@ AC_CONFIG_AUX_DIR([build-aux])
 AC_REQUIRE_AUX_FILE([tap-driver.sh])

 AC_CANONICAL_HOST
-AM_INIT_AUTOMAKE([1.11 foreign])
+AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
 AM_SILENT_RULES([yes])

 LT_INIT
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index aa812b99..84598ea0 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -26,16 +26,16 @@ cleanupdelta_SOURCES = cleanupdelta.c
 cleanupdelta_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la

 pacman_conf_SOURCES = pacman-conf.c \
-	$(top_srcdir)/src/pacman/util.h \
-	$(top_srcdir)/src/pacman/util.c \
-	$(top_srcdir)/src/pacman/ini.h \
-	$(top_srcdir)/src/pacman/ini.c \
-	$(top_srcdir)/src/pacman/util-common.h \
-	$(top_srcdir)/src/pacman/util-common.c \
-	$(top_srcdir)/src/pacman/callback.h \
-	$(top_srcdir)/src/pacman/callback.c \
-	$(top_srcdir)/src/pacman/conf.h \
-	$(top_srcdir)/src/pacman/conf.c
+	../pacman/util.h \
+	../pacman/util.c \
+	../pacman/ini.h \
+	../pacman/ini.c \
+	../pacman/util-common.h \
+	../pacman/util-common.c \
+	../pacman/callback.h \
+	../pacman/callback.c \
+	../pacman/conf.h \
+	../pacman/conf.c
 pacman_conf_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la

 testpkg_SOURCES = testpkg.c
Allan McRae Jan. 18, 2018, 5:29 a.m. UTC | #2
On 18/01/18 14:59, Allan McRae wrote:
> On 14/01/18 02:49, Andrew Gregory wrote:
>> Parsing pacman's configuration file is non-trivial and extremely
>> difficult to do correctly from scripts; even our own do it incorrectly.
>> pacman-conf is a dedicated tool specifically to allow scripts to parse
>> config files, getting the same value that pacman itself would use.
>>
>> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
> 
> The automake changes resulted in a big warning that is fixed by enabling
> subdir-objects in configure.ac and ignoring the .dirstamp file it creates.


Crap... that breaks "make distcheck".  More specifically "make
distclean" as it tries to remove the generated object files for the
common files twice.

> There was also a directory being created in the src/util with the name
> '$(top_srcdir)'.  This is due to using a variable in the paths (no idea
> why this is an issue), but replacing it with a relative path "fixes" the
> issue.
> 
> I'll squash the following into your patch:
> 
> 
>>From 4c3d7964da2ba4276e4464920fb795e9f973e3ec Mon Sep 17 00:00:00 2001
> From: Allan McRae <allan@archlinux.org>
> Date: Thu, 18 Jan 2018 14:54:17 +1000
> Subject: [PATCH] [SQUASH] Fix automake usage for pacman-conf
> 
> Signed-off-by: Allan McRae <allan@archlinux.org>
> ---
>  .gitignore           |  1 +
>  configure.ac         |  2 +-
>  src/util/Makefile.am | 20 ++++++++++----------
>  3 files changed, 12 insertions(+), 11 deletions(-)
> 
> diff --git a/.gitignore b/.gitignore
> index 499d499b..7399a120 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -1,5 +1,6 @@
>  *~
>  *.o
> +.dirstamp
>  ABOUT-NLS
>  aclocal.m4
>  autom4te.cache
> diff --git a/configure.ac b/configure.ac
> index 86f5bb6e..02afba83 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -60,7 +60,7 @@ AC_CONFIG_AUX_DIR([build-aux])
>  AC_REQUIRE_AUX_FILE([tap-driver.sh])
> 
>  AC_CANONICAL_HOST
> -AM_INIT_AUTOMAKE([1.11 foreign])
> +AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
>  AM_SILENT_RULES([yes])
> 
>  LT_INIT
> diff --git a/src/util/Makefile.am b/src/util/Makefile.am
> index aa812b99..84598ea0 100644
> --- a/src/util/Makefile.am
> +++ b/src/util/Makefile.am
> @@ -26,16 +26,16 @@ cleanupdelta_SOURCES = cleanupdelta.c
>  cleanupdelta_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
> 
>  pacman_conf_SOURCES = pacman-conf.c \
> -	$(top_srcdir)/src/pacman/util.h \
> -	$(top_srcdir)/src/pacman/util.c \
> -	$(top_srcdir)/src/pacman/ini.h \
> -	$(top_srcdir)/src/pacman/ini.c \
> -	$(top_srcdir)/src/pacman/util-common.h \
> -	$(top_srcdir)/src/pacman/util-common.c \
> -	$(top_srcdir)/src/pacman/callback.h \
> -	$(top_srcdir)/src/pacman/callback.c \
> -	$(top_srcdir)/src/pacman/conf.h \
> -	$(top_srcdir)/src/pacman/conf.c
> +	../pacman/util.h \
> +	../pacman/util.c \
> +	../pacman/ini.h \
> +	../pacman/ini.c \
> +	../pacman/util-common.h \
> +	../pacman/util-common.c \
> +	../pacman/callback.h \
> +	../pacman/callback.c \
> +	../pacman/conf.h \
> +	../pacman/conf.c
>  pacman_conf_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
> 
>  testpkg_SOURCES = testpkg.c
>
Allan McRae Jan. 18, 2018, 7:43 a.m. UTC | #3
On 18/01/18 15:29, Allan McRae wrote:
> On 18/01/18 14:59, Allan McRae wrote:
>> On 14/01/18 02:49, Andrew Gregory wrote:
>>> Parsing pacman's configuration file is non-trivial and extremely
>>> difficult to do correctly from scripts; even our own do it incorrectly.
>>> pacman-conf is a dedicated tool specifically to allow scripts to parse
>>> config files, getting the same value that pacman itself would use.
>>>
>>> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
>>
>> The automake changes resulted in a big warning that is fixed by enabling
>> subdir-objects in configure.ac and ignoring the .dirstamp file it creates.
> 
> 
> Crap... that breaks "make distcheck".  More specifically "make
> distclean" as it tries to remove the generated object files for the
> common files twice.

Turns out automake with this subdir-objects option (which will become
default next release) is buggy as hell.  Some patches have landed
upstream, but we can't rely on them in the pacman codebase.

Options here....

1) host pacman-conf in the src/pacman directory

2) Use the makefile to copy the needed src/pacman files into
src/util/pacman-conf/... and they get compiled twice.

3) create a small library using the needed files and static link it into
pacman-conf


To be clear, I only included #3 as I saw several projects do this!


I see #1 as the easiest. And probably most correct - the overlap in
source used here is such that they should be located in the same place.

Allan

Patch

diff --git a/src/util/.gitignore b/src/util/.gitignore
index 4cb3103e..3c557cac 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -2,6 +2,8 @@ 
 .libs
 cleanupdelta
 cleanupdelta.exe
+pacman-conf
+pacman-conf.exe
 testpkg
 testpkg.exe
 vercmp
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 562151bc..aa812b99 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -3,8 +3,10 @@  conffile  = ${sysconfdir}/pacman.conf
 dbpath    = ${localstatedir}/lib/pacman/
 gpgdir    = ${sysconfdir}/pacman.d/gnupg/
 cachedir  = ${localstatedir}/cache/pacman/pkg/
+logfile   = ${localstatedir}/log/pacman.log
+hookdir   = ${sysconfdir}/pacman.d/hooks/
 
-bin_PROGRAMS = vercmp testpkg cleanupdelta
+bin_PROGRAMS = vercmp testpkg cleanupdelta pacman-conf
 
 AM_CPPFLAGS = \
 	-imacros $(top_builddir)/config.h \
@@ -13,7 +15,9 @@  AM_CPPFLAGS = \
 	-DCONFFILE=\"$(conffile)\" \
 	-DDBPATH=\"$(dbpath)\" \
 	-DGPGDIR=\"$(gpgdir)\" \
-	-DCACHEDIR=\"$(cachedir)\"
+	-DCACHEDIR=\"$(cachedir)\" \
+	-DHOOKDIR=\"$(hookdir)\" \
+	-DLOGFILE=\"$(logfile)\"
 
 AM_CFLAGS = -pedantic -D_GNU_SOURCE $(WARNING_CFLAGS) \
 	$(LIBARCHIVE_CFLAGS)
@@ -21,6 +25,19 @@  AM_CFLAGS = -pedantic -D_GNU_SOURCE $(WARNING_CFLAGS) \
 cleanupdelta_SOURCES = cleanupdelta.c
 cleanupdelta_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
 
+pacman_conf_SOURCES = pacman-conf.c \
+	$(top_srcdir)/src/pacman/util.h \
+	$(top_srcdir)/src/pacman/util.c \
+	$(top_srcdir)/src/pacman/ini.h \
+	$(top_srcdir)/src/pacman/ini.c \
+	$(top_srcdir)/src/pacman/util-common.h \
+	$(top_srcdir)/src/pacman/util-common.c \
+	$(top_srcdir)/src/pacman/callback.h \
+	$(top_srcdir)/src/pacman/callback.c \
+	$(top_srcdir)/src/pacman/conf.h \
+	$(top_srcdir)/src/pacman/conf.c
+pacman_conf_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
+
 testpkg_SOURCES = testpkg.c
 testpkg_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
 
diff --git a/src/util/pacman-conf.c b/src/util/pacman-conf.c
new file mode 100644
index 00000000..b2be3e13
--- /dev/null
+++ b/src/util/pacman-conf.c
@@ -0,0 +1,437 @@ 
+/*
+ *  pacman-conf.c - parse pacman configuration files
+ *
+ *  Copyright (c) 2013-2018 Pacman Development Team <pacman-dev@archlinux.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 <getopt.h>
+#include <string.h>
+#include "../pacman/conf.h"
+
+const char *myname = "pacman-conf", *myver = "1.0.0";
+
+alpm_list_t *directives = NULL;
+char sep = '\n', *repo_name = NULL;
+const char *config_file = NULL;
+int repo_list = 0, verbose = 0;
+
+static void cleanup(void)
+{
+	alpm_list_free(directives);
+	config_free(config);
+}
+
+static void usage(int ret)
+{
+	FILE *stream = (ret ? stderr : stdout);
+#define hputs(x) fputs(x"\n", stream)
+	hputs("pacman-conf - query pacman's configuration file");
+	hputs("usage:  pacman-conf [options] [<directive>...]");
+	hputs("        pacman-conf (--repo-list|--help|--version)");
+	hputs("options:");
+	hputs("  --config=<path>  set an alternate configuration file");
+	hputs("  --rootdir=<path> set an alternate installation root");
+	hputs("  --repo=<remote>  query options for a specific repo");
+	hputs("  --verbose        always show directive names");
+	hputs("  --repo-list      list configured repositories");
+	hputs("  --help           display this help information");
+	hputs("  --version        display version information");
+#undef hputs
+	cleanup();
+	exit(ret);
+}
+
+static void parse_opts(int argc, char **argv)
+{
+	int c;
+	config_file = CONFFILE;
+
+	const char *short_opts = "";
+	struct option long_opts[] = {
+		{ "config"    , required_argument , NULL , 'c' },
+		{ "rootdir"   , required_argument , NULL , 'R' },
+		{ "repo"      , required_argument , NULL , 'r' },
+		{ "repo-list" , no_argument       , NULL , 'l' },
+		{ "verbose"   , no_argument       , NULL , 'v' },
+		{ "help"      , no_argument       , NULL , 'h' },
+		{ "version"   , no_argument       , NULL , 'V' },
+		{ 0, 0, 0, 0 },
+	};
+
+	while((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+		switch(c) {
+			case 'c':
+				config_file = optarg;
+				break;
+			case 'R':
+				config->rootdir = strdup(optarg);
+				break;
+			case 'l':
+				repo_list = 1;
+				break;
+			case 'r':
+				repo_name = optarg;
+				break;
+			case 'v':
+				verbose = 1;
+				break;
+			case 'h':
+				usage(0);
+				break;
+			case 'V':
+				printf("%s v%s\n", myname, myver);
+				cleanup();
+				exit(0);
+				break;
+			case '?':
+			default:
+				usage(1);
+				break;
+		}
+	}
+
+	if(parseconfigfile(config_file) != 0 || setdefaults(config) != 0) {
+		fprintf(stderr, "error parsing '%s'\n", config_file);
+	}
+}
+
+static void list_repos(void)
+{
+	alpm_list_t *r;
+	for(r = config->repos; r; r = r->next) {
+		config_repo_t *repo = r->data;
+		if(!repo_name || strcmp(repo->name, repo_name) == 0) {
+			printf("%s%c", repo->name, sep);
+		}
+	}
+}
+
+static void show_float(const char *directive, float val)
+{
+	if(verbose) {
+		printf("%s = ", directive);
+	}
+	printf("%f%c", val, sep);
+}
+
+static void show_bool(const char *directive, short unsigned int val)
+{
+	if(val) {
+		printf("%s%c", directive, sep);
+	}
+}
+
+static void show_str(const char *directive, const char *val)
+{
+	if(!val) {
+		return;
+	}
+	if(verbose) {
+		printf("%s = ", directive);
+	}
+	printf("%s%c", val, sep);
+}
+
+static void show_list_str(const char *directive, alpm_list_t *list)
+{
+	alpm_list_t *i;
+	for(i = list; i; i = i->next) {
+		show_str(directive, i->data);
+	}
+}
+
+static void show_cleanmethod(const char *directive, unsigned int method)
+{
+	if(method & PM_CLEAN_KEEPINST) {
+		show_str(directive, "KeepInstalled");
+	}
+	if(method & PM_CLEAN_KEEPCUR) {
+		show_str(directive, "KeepCurrent");
+	}
+}
+
+static void show_siglevel(const char *directive, alpm_siglevel_t level, int pkgonly)
+{
+	if(level == ALPM_SIG_USE_DEFAULT) {
+		return;
+	}
+
+	if(level & ALPM_SIG_PACKAGE) {
+		if(level & ALPM_SIG_PACKAGE_OPTIONAL) {
+			show_str(directive, "PackageOptional");
+		} else {
+			show_str(directive, "PackageRequired");
+		}
+
+		if(level & ALPM_SIG_PACKAGE_UNKNOWN_OK) {
+			show_str(directive, "PackageTrustAll");
+		} else {
+			show_str(directive, "PackageTrustedOnly");
+		}
+	} else {
+		show_str(directive, "PackageNever");
+	}
+
+	if(pkgonly) {
+		return;
+	}
+
+	if(level & ALPM_SIG_DATABASE) {
+		if(level & ALPM_SIG_DATABASE_OPTIONAL) {
+			show_str(directive, "DatabaseOptional");
+		} else {
+			show_str(directive, "DatabaseRequired");
+		}
+
+		if(level & ALPM_SIG_DATABASE_UNKNOWN_OK) {
+			show_str(directive, "DatabaseTrustAll");
+		} else {
+			show_str(directive, "DatabaseTrustedOnly");
+		}
+	} else {
+		show_str(directive, "DatabaseNever");
+	}
+}
+
+static void show_usage(const char *directive, alpm_db_usage_t usage)
+{
+	if(usage & ALPM_DB_USAGE_ALL) {
+		show_str(directive, "All");
+	} else {
+		if(usage & ALPM_DB_USAGE_SYNC) {
+			show_str(directive, "Sync");
+		}
+		if(usage & ALPM_DB_USAGE_SEARCH) {
+			show_str(directive, "Search");
+		}
+		if(usage & ALPM_DB_USAGE_INSTALL) {
+			show_str(directive, "Install");
+		}
+		if(usage & ALPM_DB_USAGE_UPGRADE) {
+			show_str(directive, "Upgrade");
+		}
+	}
+}
+
+static void dump_repo(config_repo_t *repo)
+{
+	show_usage("Usage", repo->usage);
+	show_siglevel("SigLevel", repo->siglevel, 0);
+	show_list_str("Server", repo->servers);
+}
+
+static void dump_config(void)
+{
+	alpm_list_t *i;
+
+	printf("[options]%c", sep);
+
+	show_str("RootDir", config->rootdir);
+	show_str("DBPath", config->dbpath);
+	show_list_str("CacheDir", config->cachedirs);
+	show_list_str("HookDir", config->hookdirs);
+	show_str("GPGDir", config->gpgdir);
+	show_str("LogFile", config->logfile);
+
+	show_list_str("HoldPkg", config->holdpkg);
+	show_list_str("IgnorePkg", config->ignorepkg);
+	show_list_str("IgnoreGroup", config->ignoregrp);
+	show_list_str("NoUpgrade", config->noupgrade);
+	show_list_str("NoExtract", config->noextract);
+
+	show_str("Architecture", config->arch);
+	show_str("XferCommand", config->xfercommand);
+
+	show_bool("UseSyslog", config->usesyslog);
+	show_bool("Color", config->color);
+	show_bool("TotalDownload", config->totaldownload);
+	show_bool("CheckSpace", config->checkspace);
+	show_bool("VerbosePkgLists", config->verbosepkglists);
+	show_bool("ILoveCandy", config->chomp);
+
+	show_float("UseDelta", config->deltaratio);
+
+	show_cleanmethod("CleanMethod", config->cleanmethod);
+
+	show_siglevel("SigLevel", config->siglevel, 0);
+	show_siglevel("LocalFileSigLevel", config->localfilesiglevel, 1);
+	show_siglevel("RemoteFileSigLevel", config->remotefilesiglevel, 1);
+
+	for(i = config->repos; i; i = i->next) {
+		config_repo_t *repo = i->data;
+		printf("[%s]%c", repo->name, sep);
+		dump_repo(repo);
+	}
+}
+
+static int list_repo_directives(void)
+{
+	int ret = 0;
+	alpm_list_t *i;
+	config_repo_t *repo = NULL;
+
+	for(i = config->repos; i; i = i->next) {
+		if(strcmp(repo_name, ((config_repo_t*) i->data)->name) == 0) {
+			repo = i->data;
+			break;
+		}
+	}
+
+	if(!repo) {
+		fprintf(stderr, "error: repo '%s' not configured\n", repo_name);
+		return 1;
+	}
+
+	if(!directives) {
+		dump_repo(repo);
+		return 0;
+	}
+
+	for(i = directives; i; i = i->next) {
+		if(strcasecmp(i->data, "Server") == 0) {
+			show_list_str("Server", repo->servers);
+		} else if(strcasecmp(i->data, "SigLevel") == 0) {
+			show_siglevel("SigLevel", repo->siglevel, 0);
+		} else if(strcasecmp(i->data, "Usage") == 0) {
+			show_usage("Usage", repo->usage);
+		} else if(strcasecmp(i->data, "Include") == 0) {
+			fputs("warning: 'Include' directives cannot be queried\n", stderr);
+			ret = 1;
+		} else {
+			fprintf(stderr, "warning: unknown directive '%s'\n", (char*) i->data);
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+static int list_directives(void)
+{
+	int ret = 0;
+	alpm_list_t *i;
+
+	if(!directives) {
+		dump_config();
+		return 0;
+	}
+
+	for(i = directives; i; i = i->next) {
+		if(strcasecmp(i->data, "RootDir") == 0) {
+			show_str("RootDir", config->rootdir);
+		} else if(strcasecmp(i->data, "DBPath") == 0) {
+			show_str("DBPath", config->dbpath);
+		} else if(strcasecmp(i->data, "CacheDir") == 0) {
+			show_list_str("CacheDir", config->cachedirs);
+		} else if(strcasecmp(i->data, "HookDir") == 0) {
+			show_list_str("HookDir", config->hookdirs);
+		} else if(strcasecmp(i->data, "GPGDir") == 0) {
+			show_str("GPGDir", config->gpgdir);
+		} else if(strcasecmp(i->data, "LogFile") == 0) {
+			show_str("LogFile", config->logfile);
+
+		} else if(strcasecmp(i->data, "HoldPkg") == 0) {
+			show_list_str("HoldPkg", config->holdpkg);
+		} else if(strcasecmp(i->data, "IgnorePkg") == 0) {
+			show_list_str("IgnorePkg", config->ignorepkg);
+		} else if(strcasecmp(i->data, "IgnoreGroup") == 0) {
+			show_list_str("IgnoreGroup", config->ignoregrp);
+		} else if(strcasecmp(i->data, "NoUpgrade") == 0) {
+			show_list_str("NoUpgrade", config->noupgrade);
+		} else if(strcasecmp(i->data, "NoExtract") == 0) {
+			show_list_str("NoExtract", config->noupgrade);
+
+
+		} else if(strcasecmp(i->data, "Architecture") == 0) {
+			show_str("Architecture", config->arch);
+		} else if(strcasecmp(i->data, "XferCommand") == 0) {
+			show_str("XferCommand", config->xfercommand);
+
+		} else if(strcasecmp(i->data, "UseSyslog") == 0) {
+			show_bool("UseSyslog", config->usesyslog);
+		} else if(strcasecmp(i->data, "Color") == 0) {
+			show_bool("Color", config->color);
+		} else if(strcasecmp(i->data, "TotalDownload") == 0) {
+			show_bool("TotalDownload", config->totaldownload);
+		} else if(strcasecmp(i->data, "CheckSpace") == 0) {
+			show_bool("CheckSpace", config->checkspace);
+		} else if(strcasecmp(i->data, "VerbosePkgLists") == 0) {
+			show_bool("VerbosePkgLists", config->verbosepkglists);
+
+		} else if(strcasecmp(i->data, "UseDelta") == 0) {
+			show_float("UseDelta", config->deltaratio);
+
+		} else if(strcasecmp(i->data, "CleanMethod") == 0) {
+			show_cleanmethod("CleanMethod", config->cleanmethod);
+
+		} else if(strcasecmp(i->data, "SigLevel") == 0) {
+			show_siglevel("SigLevel", config->siglevel, 0);
+		} else if(strcasecmp(i->data, "LocalFileSigLevel") == 0) {
+			show_siglevel("LocalFileSigLevel", config->localfilesiglevel, 1);
+		} else if(strcasecmp(i->data, "RemoteFileSigLevel") == 0) {
+			show_siglevel("RemoteFileSigLevel", config->remotefilesiglevel, 1);
+
+		} else if(strcasecmp(i->data, "Include") == 0) {
+			fputs("warning: 'Include' directives cannot be queried\n", stderr);
+			ret = 1;
+		} else {
+			fprintf(stderr, "warning: unknown directive '%s'\n", (char*) i->data);
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	int ret = 0;
+
+	config = config_new();
+	parse_opts(argc, argv);
+	if(!config) {
+		ret = 1;
+		goto cleanup;
+	}
+
+	for(; optind < argc; optind++) {
+		directives = alpm_list_add(directives, argv[optind]);
+	}
+
+	if(alpm_list_count(directives) != 1) {
+		verbose = 1;
+	}
+
+	if(repo_list) {
+		if(directives) {
+			fputs("error: directives may not be specified with --repo-list\n", stderr);
+			ret = 1;
+			goto cleanup;
+		}
+		list_repos();
+	} else if(repo_name) {
+		ret = list_repo_directives();
+	} else {
+		ret = list_directives();
+	}
+
+cleanup:
+	cleanup();
+
+	return ret;
+}
+
+/* vim: set ts=2 sw=2 noet: */