Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote-tracking branch 'upstream/master'
Shawn Webb committed 2 years ago
commit a88747aa3d8e7a2da8f2c4710a2bfc1a4e3a92d7
parent ffa5b3d
11 files changed +320 -37
modified libpkg/Makefile.autosetup
@@ -182,7 +182,7 @@ install: all pkg.h lib$(LIB)$(LIBSOEXT) lib$(LIB)_flat.a
	install -d -m 755 $(DESTDIR)$(pkgconfigdir)
	install -m 644 lib$(LIB)$(LIBSOEXT) $(DESTDIR)$(libdir)/
	ln -sf lib$(LIB)$(LIBSOEXT) $(DESTDIR)$(libdir)/lib$(LIB)$(SH_SOEXT)
-
	install -m 644 lib$(LIB).a $(DESTDIR)$(libdir)/lib$(LIB).a
+
	install -m 644 lib$(LIB)_flat.a $(DESTDIR)$(libdir)/lib$(LIB).a
	install -m 644 pkg.h $(DESTDIR)$(includedir)/
	install -m 644 $(top_srcdir)/libpkg/pkg/audit.h $(DESTDIR)$(includedir)/pkg
	install -m 644 pkg.pc $(DESTDIR)$(pkgconfigdir)/
modified libpkg/backup_lib.c
@@ -141,7 +141,7 @@ backup_library(struct pkgdb *db, struct pkg *p, const char *path)
		goto out;
	}

-
	while (nread = read(from, buf, sizeof(buf)), nread > 0) {
+
	while ((nread = read(from, buf, sizeof(buf))) > 0) {
		outbuf = buf;
		do {
			nwritten = write(to, outbuf, nread);
@@ -174,6 +174,4 @@ out:
		close(from);
	if (to >= 0)
		close(to);
-

-
	return;
}
modified libpkg/pkg.h.in
@@ -238,6 +238,14 @@ typedef enum {
	 * The pkg refers to a local file old archive.
	 */
	PKG_OLD_FILE = (1U << 4),
+
	/**
+
	 * The pkg is group available in a remove repository
+
	 */
+
	PKG_GROUP_REMOTE = (1U << 5),
+
	/**
+
	 * The pkg refers to an installed group
+
	 */
+
	PKG_GROUP_INSTALLED = (1U << 6),
} pkg_t;

/**
modified libpkg/pkg_jobs.c
@@ -969,6 +969,15 @@ pkg_jobs_guess_upgrade_candidate(struct pkg_jobs *j, const char *pattern)
}

static int
+
pkg_jobs_find_group_upgrade(struct pkg_jobs *j __unused, const char *pattern __unused, match_t m __unused)
+
{
+
	int rc = EPKG_FATAL;
+
	struct pkg_repo_it *it;
+

+
	return (rc);
+
}
+

+
static int
pkg_jobs_find_upgrade(struct pkg_jobs *j, const char *pattern, match_t m)
{
	struct pkg *p = NULL;
@@ -983,6 +992,10 @@ pkg_jobs_find_upgrade(struct pkg_jobs *j, const char *pattern, match_t m)
			PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
	struct pkg_job_universe_item *unit = NULL;

+
	/* We are looking for groups */
+
	if (*pattern == '@')
+
		return (pkg_jobs_find_group_upgrade(j, pattern, m));
+

	if ((it = pkgdb_repo_query(j->db, pattern, m, j->reponame)) == NULL)
		return (rc);

modified libpkg/pkgdb_query.c
@@ -393,7 +393,10 @@ pkgdb_repo_query_cond(struct pkgdb *db, const char *cond, const char *pattern, m

	tll_foreach(db->repos, cur) {
		if (repo == NULL || strcasecmp(cur->item->name, repo) == 0) {
-
			rit = cur->item->ops->query(cur->item, cond, pattern, match);
+
			if (*pattern == '@')
+
				rit = cur->item->ops->groupquery(cur->item, pattern + 1, match);
+
			else
+
				rit = cur->item->ops->query(cur->item, cond, pattern, match);
			if (rit != NULL)
				pkgdb_it_repo_attach(it, rit);
		}
@@ -519,6 +522,11 @@ pkgdb_repo_search(struct pkgdb *db, const char *pattern, match_t match,
				if (rit != NULL)
					pkgdb_it_repo_attach(it, rit);
			}
+
			if (cur->item->ops->groupsearch != NULL) {
+
				rit = cur->item->ops->groupsearch(cur->item, pattern, match, field);
+
				if (rit != NULL)
+
					pkgdb_it_repo_attach(it, rit);
+
			}
		}
	}

modified libpkg/private/pkg.h
@@ -498,6 +498,8 @@ struct pkg_repo_ops {
	/* Query repo */
	struct pkg_repo_it * (*query)(struct pkg_repo *,
					const char*, const char *, match_t);
+
	struct pkg_repo_it * (*groupquery)(struct pkg_repo *,
+
					const char*, match_t);
	struct pkg_repo_it * (*shlib_required)(struct pkg_repo *,
					const char *);
	struct pkg_repo_it * (*shlib_provided)(struct pkg_repo *,
@@ -508,6 +510,8 @@ struct pkg_repo_ops {
					const char *);
	struct pkg_repo_it * (*search)(struct pkg_repo *, const char *, match_t,
					pkgdb_field field, pkgdb_field sort);
+
	struct pkg_repo_it * (*groupsearch)(struct pkg_repo *, const char *,
+
	    match_t, pkgdb_field field);

	int64_t (*stat)(struct pkg_repo *, pkg_stats_t type);

modified libpkg/repo/binary/binary.c
@@ -1,13 +1,14 @@
-
/* Copyright (c) 2014, Vsevolod Stakhov
-
 * All rights reserved.
+
/*
+
 * Copyright (c) 2014, Vsevolod Stakhov
+
 * Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
-
 *       * Redistributions of source code must retain the above copyright
-
 *         notice, this list of conditions and the following disclaimer.
-
 *       * Redistributions in binary form must reproduce the above copyright
-
 *         notice, this list of conditions and the following disclaimer in the
-
 *         documentation and/or other materials provided with the distribution.
+
 * * Redistributions of source code must retain the above copyright
+
 *   notice, this list of conditions and the following disclaimer.
+
 * * Redistributions in binary form must reproduce the above copyright
+
 *   notice, this list of conditions and the following disclaimer in the
+
 *   documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -32,11 +33,13 @@ struct pkg_repo_ops pkg_repo_binary_ops = {
	.close = pkg_repo_binary_close,
	.update = pkg_repo_binary_update,
	.query = pkg_repo_binary_query,
+
	.groupquery = pkg_repo_binary_groupquery,
	.shlib_provided = pkg_repo_binary_shlib_provide,
	.shlib_required = pkg_repo_binary_shlib_require,
	.provided = pkg_repo_binary_provide,
	.required = pkg_repo_binary_require,
	.search = pkg_repo_binary_search,
+
	.groupsearch = pkg_repo_binary_groupsearch,
	.fetch_pkg = pkg_repo_binary_fetch,
	.mirror_pkg = pkg_repo_binary_mirror,
	.get_cached_name = pkg_repo_binary_get_cached_name,
modified libpkg/repo/binary/binary.h
@@ -1,13 +1,14 @@
-
/* Copyright (c) 2014, Vsevolod Stakhov
-
 * All rights reserved.
+
/*
+
 * Copyright (c) 2014, Vsevolod Stakhov
+
 * Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
-
 *       * Redistributions of source code must retain the above copyright
-
 *         notice, this list of conditions and the following disclaimer.
-
 *       * Redistributions in binary form must reproduce the above copyright
-
 *         notice, this list of conditions and the following disclaimer in the
-
 *         documentation and/or other materials provided with the distribution.
+
 * * Redistributions of source code must retain the above copyright
+
 *   notice, this list of conditions and the following disclaimer.
+
 * * Redistributions in binary form must reproduce the above copyright
+
 *   notice, this list of conditions and the following disclaimer in the
+
 *   documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -41,6 +42,8 @@ int pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode);

struct pkg_repo_it *pkg_repo_binary_query(struct pkg_repo *repo,
	const char *cond, const char *pattern, match_t match);
+
struct pkg_repo_it *pkg_repo_binary_groupquery(struct pkg_repo *repo,
+
	const char *pattern, match_t match);
struct pkg_repo_it *pkg_repo_binary_shlib_provide(struct pkg_repo *repo,
	const char *require);
struct pkg_repo_it *pkg_repo_binary_provide(struct pkg_repo *repo,
@@ -52,6 +55,8 @@ struct pkg_repo_it *pkg_repo_binary_require(struct pkg_repo *repo,
struct pkg_repo_it *pkg_repo_binary_search(struct pkg_repo *repo,
	const char *pattern, match_t match,
    pkgdb_field field, pkgdb_field sort);
+
struct pkg_repo_it *pkg_repo_binary_groupsearch(struct pkg_repo *repo,
+
	const char *pattern, match_t match, pkgdb_field field);
int pkg_repo_binary_ensure_loaded(struct pkg_repo *repo,
	struct pkg *pkg, unsigned flags);
int64_t pkg_repo_binary_stat(struct pkg_repo *repo, pkg_stats_t type);
modified libpkg/repo/binary/query.c
@@ -1,15 +1,16 @@
-
/* Copyright (c) 2014, Vsevolod Stakhov
+
/*
+
 * Copyright (c) 2014, Vsevolod Stakhov
+
 * Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2023, Serenity Cyber Security, LLC
 *                     Author: Gleb Popov <arrowd@FreeBSD.org>
-
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
-
 *       * Redistributions of source code must retain the above copyright
-
 *         notice, this list of conditions and the following disclaimer.
-
 *       * Redistributions in binary form must reproduce the above copyright
-
 *         notice, this list of conditions and the following disclaimer in the
-
 *         documentation and/or other materials provided with the distribution.
+
 * * Redistributions of source code must retain the above copyright
+
 *   notice, this list of conditions and the following disclaimer.
+
 * * Redistributions in binary form must reproduce the above copyright
+
 *   notice, this list of conditions and the following disclaimer in the
+
 *   documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -33,6 +34,8 @@
#include <string.h>
#include <unistd.h>
#include <libgen.h>
+
#include <fcntl.h>
+
#include <fnmatch.h>

#include <sqlite3.h>

@@ -45,16 +48,31 @@

static struct pkg_repo_it* pkg_repo_binary_it_new(struct pkg_repo *repo,
	sqlite3_stmt *s, short flags);
+

+
struct pkg_repo_group {
+
	size_t index;
+
	ucl_object_t *groups;
+
};
static int pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags);
static void pkg_repo_binary_it_free(struct pkg_repo_it *it);
static void pkg_repo_binary_it_reset(struct pkg_repo_it *it);

+
static int pkg_repo_binary_group_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags);
+
static void pkg_repo_binary_group_it_free(struct pkg_repo_it *it);
+
static void pkg_repo_binary_group_it_reset(struct pkg_repo_it *it);
+

static struct pkg_repo_it_ops pkg_repo_binary_it_ops = {
	.next = pkg_repo_binary_it_next,
	.free = pkg_repo_binary_it_free,
	.reset = pkg_repo_binary_it_reset
};

+
static struct pkg_repo_it_ops pkg_repo_binary_group_it_ops = {
+
	.next = pkg_repo_binary_group_it_next,
+
	.free = pkg_repo_binary_group_it_free,
+
	.reset = pkg_repo_binary_group_it_reset
+
};
+

static struct pkg_repo_it*
pkg_repo_binary_it_new(struct pkg_repo *repo, sqlite3_stmt *s, short flags)
{
@@ -78,12 +96,51 @@ pkg_repo_binary_it_new(struct pkg_repo *repo, sqlite3_stmt *s, short flags)
	return (it);
}

+
static struct pkg_repo_it *
+
pkg_repo_binary_group_it_new(struct pkg_repo *repo __unused, ucl_object_t *matching)
+
{
+
	struct pkg_repo_group *prg;
+
	struct pkg_repo_it *it;
+

+
	it = xcalloc(1, sizeof(*it));
+
	prg = xcalloc(1, sizeof(*prg));
+
	prg->groups = matching;
+
	it->ops = &pkg_repo_binary_group_it_ops;
+
	it->data = prg;
+

+
	return (it);
+
}
+

static int
pkg_repo_binary_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags)
{
	return (pkgdb_it_next(it->data, pkg_p, flags));
}

+
static int
+
pkg_repo_binary_group_it_next(struct pkg_repo_it *it, struct pkg **pkg_p, unsigned flags __unused)
+
{
+
	int ret;
+
	struct pkg_repo_group *prg;
+
	const ucl_object_t *o, *el;
+

+
	prg = it->data;
+
	if (prg->index == ucl_array_size(prg->groups))
+
		return (EPKG_END);
+

+
	el = ucl_array_find_index(prg->groups, prg->index);
+
	prg->index++;
+
	pkg_free(*pkg_p);
+
	if ((ret = pkg_new(pkg_p, PKG_GROUP_REMOTE)) != EPKG_OK)
+
		return (ret);
+
	o = ucl_object_find_key(el, "name");
+
	xasprintf(&(*pkg_p)->name, ucl_object_tostring(o));
+
	o = ucl_object_find_key(el, "comment");
+
	xasprintf(&(*pkg_p)->comment, ucl_object_tostring(o));
+

+
	return (EPKG_OK);
+
}
+

static void
pkg_repo_binary_it_free(struct pkg_repo_it *it)
{
@@ -92,11 +149,34 @@ pkg_repo_binary_it_free(struct pkg_repo_it *it)
}

static void
+
pkg_repo_binary_group_it_free(struct pkg_repo_it *it)
+
{
+
	struct pkg_repo_group *prg = it->data;
+
	free(prg->groups);
+
	free(prg);
+
	free(it);
+
}
+

+
static void
pkg_repo_binary_it_reset(struct pkg_repo_it *it)
{
	pkgdb_it_reset(it->data);
}

+
static void
+
pkg_repo_binary_group_it_reset(struct pkg_repo_it *it)
+
{
+
	struct pkg_repo_group *prg = it->data;
+

+
	prg->index = 0;
+
}
+

+
struct pkg_repo_it *
+
pkg_repo_binary_groupquery(struct pkg_repo *repo, const char *pattern, match_t match)
+
{
+
	return (pkg_repo_binary_groupsearch(repo, pattern, match, FIELD_NAME));
+
}
+

struct pkg_repo_it *
pkg_repo_binary_query(struct pkg_repo *repo, const char *cond, const char *pattern, match_t match)
{
@@ -423,6 +503,133 @@ pkg_repo_binary_search(struct pkg_repo *repo, const char *pattern, match_t match
	return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
}

+
struct pkg_repo_it *
+
pkg_repo_binary_groupsearch(struct pkg_repo *repo, const char *pattern, match_t match,
+
    pkgdb_field field)
+
{
+
	ucl_object_t *groups, *ar, *el;
+
	const ucl_object_t *o;
+
	const char *cmp;
+
	struct ucl_parser *p;
+
	int fd;
+
	regex_t *re = NULL;
+
	int flag = 0;
+
	bool in_comment = false;
+
	bool start_with = false;
+

+
	switch (field) {
+
		case FIELD_NAME:
+
		case FIELD_NAMEVER:
+
			break;
+
		case FIELD_COMMENT:
+
			in_comment = true;
+
			break;
+
		default:
+
			/* we cannot search in other fields */
+
			return (NULL);
+
	}
+

+
	if (repo->dfd == -1 && pkg_repo_open(repo) == EPKG_FATAL)
+
		return (NULL);
+
	fd = openat(repo->dfd, "groups.ucl", O_RDONLY|O_CLOEXEC);
+
	if (fd == -1)
+
		return (NULL);
+
	p = ucl_parser_new(0);
+
	if (!ucl_parser_add_fd(p, fd)) {
+
		pkg_emit_error("Error parsing groups for: %s'",
+
		    repo->name);
+
		ucl_parser_free(p);
+
		close(fd);
+
		return (NULL);
+

+
	}
+
	groups = ucl_parser_get_object(p);
+
	ucl_parser_free(p);
+
	close(fd);
+

+
	if (ucl_object_type(groups) != UCL_ARRAY) {
+
		ucl_object_unref(groups);
+
		return (NULL);
+
	}
+
	if (*pattern == '@') {
+
		pattern++;
+
		start_with = true;
+
	}
+

+
	ar = NULL;
+
	while (ucl_array_size(groups) > 0) {
+
		el = ucl_array_pop_first(groups);
+
		if (in_comment) {
+
			o = ucl_object_find_key(el, "comment");
+
		} else {
+
			o = ucl_object_find_key(el, "name");
+
		}
+
		if (o == NULL) {
+
			ucl_object_unref(el);
+
			continue;
+
		}
+
		cmp = ucl_object_tostring(o);
+
		switch (match) {
+
		case MATCH_ALL:
+
			break;
+
		case MATCH_INTERNAL:
+
			if (strcmp(cmp, pattern) == 0)
+
				continue;
+
			break;
+
		case MATCH_EXACT:
+
			if (pkgdb_case_sensitive()) {
+
				if (strcmp(cmp, pattern) != 0)
+
					continue;
+
			} else {
+
				if (strcasecmp(cmp, pattern) != 0)
+
					continue;
+
			}
+
			break;
+
		case MATCH_GLOB:
+
			if (pkgdb_case_sensitive() != 0)
+
				flag = FNM_CASEFOLD;
+
			if (fnmatch(cmp, pattern, flag) == FNM_NOMATCH)
+
				continue;
+
		case MATCH_REGEX:
+
			if (re == NULL) {
+
				char *newpattern = NULL;
+
				const char *pat = pattern;
+
				flag = REG_EXTENDED | REG_NOSUB;
+
				if (pkgdb_case_sensitive() != 0)
+
					flag |= REG_ICASE;
+
				re = xmalloc(sizeof(regex_t));
+
				if (start_with) {
+
					xasprintf(&newpattern, "^%s", pattern);
+
					pat = newpattern;
+
				}
+
				if (regcomp(re, pat, flag) != 0) {
+
					pkg_emit_error("Invalid regex: 'pattern'");
+
					ucl_object_unref(groups);
+
					if (ar != NULL)
+
						ucl_object_unref(ar);
+
					free(newpattern);
+
					return (NULL);
+
				}
+
				free(newpattern);
+
			}
+
			if (regexec(re, cmp, 0, NULL, 0) == REG_NOMATCH)
+
				continue;
+
		}
+
		if (ar == NULL)
+
			ar = ucl_object_typed_new(UCL_ARRAY);
+
		ucl_array_append(ar, el);
+
	}
+

+
	if (re != NULL)
+
		regfree(re);
+
	ucl_object_unref(groups);
+

+
	if (ar == NULL)
+
		return (NULL);
+

+
	return (pkg_repo_binary_group_it_new(repo, ar));
+
}
+

int
pkg_repo_binary_ensure_loaded(struct pkg_repo *repo,
	struct pkg *pkg, unsigned flags)
modified src/upgrade.c
@@ -162,13 +162,8 @@ add_vulnerable_upgrades(struct pkg_jobs *jobs, struct pkgdb *db)
	ssize_t				linelen;

	/* Fetch audit file */
-
	/* TODO: maybe, we can skip it somethimes? */
-
	audit = pkg_audit_new();
-

-
	if (pkg_audit_fetch(NULL, NULL) != EPKG_OK) {
-
		pkg_audit_free(audit);
+
	if (pkg_audit_fetch(NULL, NULL) != EPKG_OK)
		return (EXIT_FAILURE);
-
	}

	/* Create socketpair to execute audit check in a detached mode */
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1)  {
@@ -177,6 +172,7 @@ add_vulnerable_upgrades(struct pkg_jobs *jobs, struct pkgdb *db)
		return (EPKG_FATAL);
	}

+
	audit = pkg_audit_new();
	cld = fork();

	switch (cld) {
@@ -188,6 +184,7 @@ add_vulnerable_upgrades(struct pkg_jobs *jobs, struct pkgdb *db)
		break;
	case -1:
		warnx("Cannot fork");
+
	        pkg_audit_free(audit);
		return (EPKG_FATAL);
	default:
		/* Parent code */
modified src/utils.c
@@ -331,6 +331,7 @@ print_info(struct pkg * const pkg, uint64_t options)
{
	bool print_tag = false;
	bool show_locks = false;
+
	bool is_group = false;
	const char *repourl = NULL;
	unsigned opt;
	int cout = 0;		/* Number of characters output */
@@ -367,6 +368,8 @@ print_info(struct pkg * const pkg, uint64_t options)
	   package is locally installed */
	if (pkg_type(pkg) == PKG_INSTALLED && (options & INFO_LOCKED) != 0)
		show_locks = true;
+
	if (pkg_type(pkg) == PKG_GROUP_REMOTE || pkg_type(pkg) == PKG_GROUP_INSTALLED)
+
		is_group = true;

	if (!quiet) {
		/* Print a tag-line identifying the package -- either
@@ -374,12 +377,23 @@ print_info(struct pkg * const pkg, uint64_t options)
		   preference).  This may be the only output from this
		   function */

-
		if (options & INFO_TAG_NAMEVER)
-
			cout = pkg_printf("%n-%v", pkg, pkg);
-
		else if (options & INFO_TAG_ORIGIN)
+
		if (options & INFO_TAG_NAMEVER) {
+
			if (is_group)
+
				cout = pkg_printf("@%n", pkg);
+
			else
+
				cout = pkg_printf("%n-%v", pkg, pkg);
+
		}
+
		else if (options & INFO_TAG_ORIGIN) {
+
			if (is_group)
+
				return;
			cout = pkg_printf("%o", pkg);
-
		else if (options & INFO_TAG_NAME)
-
			cout = pkg_printf("%n", pkg);
+
		}
+
		else if (options & INFO_TAG_NAME) {
+
			if (is_group)
+
				cout = pkg_printf("@%n", pkg);
+
			else
+
				cout = pkg_printf("%n", pkg);
+
		}
	}

	/* If we printed a tag, and there are no other items to print,
@@ -440,21 +454,29 @@ print_info(struct pkg * const pkg, uint64_t options)
				printf("\n");
			break;
		case INFO_VERSION:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Version");
			pkg_printf("%v\n", pkg);
			break;
		case INFO_ORIGIN:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Origin");
			pkg_printf("%o\n", pkg);
			break;
		case INFO_PREFIX:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Prefix");
			pkg_printf("%p\n", pkg);
			break;
		case INFO_REPOSITORY:
+
			if (is_group)
+
				break;
			if (pkg_type(pkg) == PKG_REMOTE &&
			    repourl != NULL && repourl[0] != '\0') {
				if (print_tag)
@@ -464,21 +486,29 @@ print_info(struct pkg * const pkg, uint64_t options)
				printf("\n");
			break;
		case INFO_CATEGORIES:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Categories");
			pkg_printf("%C%{%Cn%| %}\n", pkg);
			break;
		case INFO_LICENSES:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Licenses");
			pkg_printf("%L%{%Ln%| %l %}\n", pkg);
			break;
		case INFO_MAINTAINER:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Maintainer");
			pkg_printf("%m\n", pkg);
			break;
		case INFO_WWW:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "WWW");
			pkg_printf("%w\n", pkg);
@@ -539,6 +569,8 @@ print_info(struct pkg * const pkg, uint64_t options)
			}
			break;
		case INFO_ANNOTATIONS:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s:\n", "Annotations");
			if (quiet)
@@ -547,6 +579,8 @@ print_info(struct pkg * const pkg, uint64_t options)
				pkg_printf("%A%{\t%-15An: %Av\n%|%}", pkg);
			break;
		case INFO_FLATSIZE:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Flat size");
			pkg_printf("%#sB\n", pkg);
@@ -560,11 +594,15 @@ print_info(struct pkg * const pkg, uint64_t options)
				printf("\n");
			break;
		case INFO_DESCR:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s:\n", "Description");
			pkg_printf("%e\n", pkg);
			break;
		case INFO_MESSAGE:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s:\n", "Message");
			if (pkg_has_message(pkg))
@@ -643,6 +681,8 @@ print_info(struct pkg * const pkg, uint64_t options)
			}
			break;
		case INFO_ARCH:
+
			if (is_group)
+
				break;
			if (print_tag)
				printf("%-15s: ", "Architecture");
			pkg_printf("%q\n", pkg);