[Rpm-maint] [PATCH 04/18] Add new %policy section to the spec file format

Steve Lawrence slawrence at tresys.com
Wed Dec 23 20:57:24 UTC 2009


The %policy section is similar to other sections (%files, %pre, %post,
etc.) in that you can provide a string and -n after the declaration to
specify policy should be added to a subpackage.

For example:

%policy
 # policy in this section will be added to the main package

%policy foo
 # policy in this section will be added to the '<mainpackage>-foo' subpackage

%policy -n bar
 # policy in this section will be added to the 'bar' subpackage

The %policy section contains zero or more %module directives, each of
which specifies a path into the build directory of a policy file, for
example:

%module policies/foo.pp
%module policies/bar.pp

After each %module directive can be zero or more options, specified in
the same format as Preamble tags. The current options are:

Base:      Whether or not the module is a base module. Values can be
           yes/1 or no/0. Defaults to no/0 if not given.

Name:      The name of the module. If not given, we assume the name is
           the basename of the module file with file extensions removed

Obsoletes: One or more space-separated strings specifying which modules
           are obsoleted by a module. Obsoleted modules are removed and
           the new modules are installed. An example of when this might
           be used is in policy renames. For example, if we renamed
		   foo.pp to bar.pp, we would specify that bar obsoletes foo. If
		   not specified, it is assumed the module obsoletes nothing.

Types:     One or more space-separated strings specifying which policy
           types the module can work with. To explicitly state that a module
		   can work with any policy type, "default" can be specified as
		   the value. If not specified, we assume the module can work with
		   any policy type, and assign the types as "default".

Spaces before and after the %module directive and options are ignored.
Options always apply to the previously defined %module directive.

Below is an example of this new format:

%policy
%module policy/foo.pp
   Name: foo
   Types: mls
   Obsoletes: baz boo
%module policy/bar.pp
   Name: bar
   Types: strict targeted mls
   Obsoletes: foo
   Base: yes

This also adds new header tags to store the new information:
 RPMTAG_POLICYNAMES        (string array)
 RPMTAG_POLICYTYPES        (string array)
 RPMTAG_POLICYTYPESINDEXES (uint32 array)
 RPMTAG_POLICYFLAGS        (uint32 array)
 RPMTAG_POLICYOBSOLETES    (string array)
 RPMTAG_POLICYOBSOLETESBY  (uint32 array)

The index of NAMES and FLAGS maps directly to the index of RPMTAG_POLICIES.
However, because a single policy can have multiple types and obsoletes,
the mapping for TYPES and OBSOLETES is not direct. For those two,
the index maps to TYPESINDEXES and OBSOLETESBY, which contains the
index of the policy that the type/obsoletes maps to. This is similar to
how DIRINDEXES is used to map DIRNAMES and BASENAMES. As an example,
the previous spec file snippet would have the following header tags:

RPMTAG_POLICIES:
 0: <foo.pp data, base64 encoded>
 1: <bar.pp data, base64 encoded>

RPMTAG_POLICYNAMES:
 0: foo
 1: bar

RPMTAG_POLICYFLAGS:
 0: 0
 1: 1	# assumes flag 1 == BASE

RPMTAG_POILCYTYPES:        RPMTAG_POLICYTYPESINDEXES:
 0: mls                     0: 0
 1: strict                  1: 1
 2: targeted                2: 1
 3: mls                     3: 1

RPMTAG_POLICYOBSOLETES:    RPMTAG_POLICYOBSOLETESBY:
 0: baz                     0: 0
 1: boo                     1: 0
 2: foo                     2: 1
---
 Makefile.am           |    1 +
 build/Makefile.am     |    4 +-
 build/build.c         |    4 +
 build/parsePolicies.c |   88 ++++++++++
 build/parseSpec.c     |    5 +
 build/policies.c      |  460 +++++++++++++++++++++++++++++++++++++++++++++++++
 build/rpmbuild.h      |   18 ++-
 build/rpmspec.h       |    1 +
 build/spec.c          |    2 +
 lib/rpmpol.h          |   24 +++
 lib/rpmtag.h          |    6 +
 preinstall.am         |    4 +
 12 files changed, 614 insertions(+), 3 deletions(-)
 create mode 100644 build/parsePolicies.c
 create mode 100644 build/policies.c
 create mode 100644 lib/rpmpol.h

diff --git a/Makefile.am b/Makefile.am
index 587cfa7..6dd2c4a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -62,6 +62,7 @@ pkginclude_HEADERS += lib/rpmfi.h
 pkginclude_HEADERS += lib/rpmgi.h
 pkginclude_HEADERS += lib/rpmlegacy.h
 pkginclude_HEADERS += lib/rpmps.h
+pkginclude_HEADERS += lib/rpmpol.h
 pkginclude_HEADERS += lib/rpmtag.h
 pkginclude_HEADERS += lib/rpmtd.h
 pkginclude_HEADERS += lib/rpmte.h
diff --git a/build/Makefile.am b/build/Makefile.am
index 30cb089..bfde891 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -12,8 +12,8 @@ usrlib_LTLIBRARIES = librpmbuild.la
 librpmbuild_la_SOURCES = \
 	build.c buildio.h expression.c files.c misc.c names.c pack.c \
 	parseBuildInstallClean.c parseChangelog.c parseDescription.c \
-	parseFiles.c parsePreamble.c parsePrep.c parseReqs.c parseScript.c \
-	parseSpec.c poptBT.c reqprov.c rpmfc.c spec.c
+	parseFiles.c parsePolicies.c parsePreamble.c parsePrep.c parseReqs.c parseScript.c \
+	parseSpec.c policies.c poptBT.c reqprov.c rpmfc.c spec.c
 librpmbuild_la_LDFLAGS = -version-info 1:0:0
 librpmbuild_la_LIBADD = \
 	$(top_builddir)/lib/librpm.la \
diff --git a/build/build.c b/build/build.c
index a4a271a..981f5fa 100644
--- a/build/build.c
+++ b/build/build.c
@@ -257,6 +257,10 @@ rpmRC buildSpec(rpmts ts, rpmSpec spec, int what, int test)
 	    (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
 		goto exit;
 
+	if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY)) &&
+	    (rc = processBinaryPolicies(spec, test)))
+		goto exit;
+
 	if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
 	    (rc = packageSources(spec)))
 		return rc;
diff --git a/build/parsePolicies.c b/build/parsePolicies.c
new file mode 100644
index 0000000..904a00b
--- /dev/null
+++ b/build/parsePolicies.c
@@ -0,0 +1,88 @@
+/** \ingroup rpmbuild
+ * \file build/parsePolicies.c
+ *  Parse %policies section from spec file.
+ */
+
+#include "system.h"
+
+#include <rpm/header.h>
+#include <rpm/rpmbuild.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmfileutil.h>
+#include "debug.h"
+
+int parsePolicies(rpmSpec spec)
+{
+	int nextPart, res = PART_ERROR;
+	Package pkg;
+	int rc, argc;
+	int arg;
+	const char ** argv = NULL;
+	const char * name = NULL;
+	int flag = PART_SUBNAME;
+	poptContext optCon = NULL;
+
+	struct poptOption optionsTable[] = {
+		{NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
+		{0, 0, 0, 0, 0, NULL, NULL}
+	};
+
+	if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
+		rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%policies: %s\n"), spec->lineNum, poptStrerror(rc));
+		goto exit;
+	}
+
+	optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
+	while ((arg = poptGetNextOpt(optCon)) > 0) {
+		if (arg == 'n') {
+			flag = PART_NAME;
+		}
+	}
+
+	if (arg < -1) {
+		rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
+		       spec->lineNum,
+		       poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+		       spec->line);
+		goto exit;
+	}
+
+	if (poptPeekArg(optCon)) {
+		if (name == NULL)
+			name = poptGetArg(optCon);
+		if (poptPeekArg(optCon)) {
+			rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"), spec->lineNum, spec->line);
+			goto exit;
+		}
+	}
+
+	if (lookupPackage(spec, name, flag, &pkg)) {
+		rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"), spec->lineNum, spec->line);
+		goto exit;
+	}
+
+	pkg->policyList = newStringBuf();
+
+	if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
+		nextPart = PART_NONE;
+	} else if (rc < 0) {
+		goto exit;
+	} else {
+		while (!(nextPart = isPart(spec->line))) {
+			appendLineStringBuf(pkg->policyList, spec->line);
+			if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
+				nextPart = PART_NONE;
+				break;
+			} else if (rc < 0) {
+				goto exit;
+			}
+		}
+	}
+	res = nextPart;
+
+ exit:
+	argv = _free(argv);
+	optCon = poptFreeContext(optCon);
+
+	return res;
+}
diff --git a/build/parseSpec.c b/build/parseSpec.c
index 816aa81..a5dab1a 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -45,6 +45,7 @@ static const struct PartRec {
     { PART_TRIGGERIN,     LEN_AND_STR("%triggerin")},
     { PART_TRIGGERIN,     LEN_AND_STR("%trigger")},
     { PART_VERIFYSCRIPT,  LEN_AND_STR("%verifyscript")},
+    { PART_POLICIES,      LEN_AND_STR("%policy")},
     {0, 0, 0}
 };
 
@@ -489,6 +490,10 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootDir,
 	    parsePart = parseFiles(spec);
 	    break;
 
+	case PART_POLICIES:
+	    parsePart = parsePolicies(spec);
+	    break;
+
 	case PART_NONE:		/* XXX avoid gcc whining */
 	case PART_LAST:
 	case PART_BUILDARCHITECTURES:
diff --git a/build/policies.c b/build/policies.c
new file mode 100644
index 0000000..7e4d2ee
--- /dev/null
+++ b/build/policies.c
@@ -0,0 +1,460 @@
+/** \ingroup rpmbuild
+ * \file build/policies.c
+ *  The post-build, packaging of policies
+ */
+
+#include "system.h"
+
+#include <rpm/rpmbuild.h>
+#include <rpm/argv.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmpol.h>
+
+#include "rpmio/rpmio_internal.h"
+#include "rpmio/base64.h"
+
+#include "debug.h"
+
+#define SKIPSPACE(s)    { while (*(s) &&  risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
+
+typedef struct ModuleRec_s {
+	char *path;
+	char *name;
+	ARGV_t obsoletes;
+	ARGV_t types;
+	uint32_t base;
+} *ModuleRec;
+
+typedef enum MODATag_e {
+	MODOPT_UNKNOWN = 0,
+	MODOPT_NAME = 1,
+	MODOPT_OBSOLETES = 2,
+	MODOPT_TYPES = 3,
+	MODOPT_BASE = 4
+} MODATag;
+
+typedef const struct MODA {
+	MODATag tag;
+	int deprecated;
+	size_t len;
+	const char *token;
+} MODA_t;
+
+#define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
+
+static MODA_t const moduleAttrs[] = {
+	{MODOPT_NAME, 0, LEN_AND_STR("name")},
+	{MODOPT_OBSOLETES, 0, LEN_AND_STR("obsoletes")},
+	{MODOPT_TYPES, 0, LEN_AND_STR("types")},
+	{MODOPT_BASE, 0, LEN_AND_STR("base")},
+	{MODOPT_UNKNOWN, 0, 0, 0} /* must be last */
+};
+
+/* returns 0 if no, 1 if yes, -1 if unknown */
+static inline int parseYesNo(const char *s)
+{
+	if (s) {
+		if (((s[0] == 'n' || s[0] == 'N' || s[0] == '0') && strlen(s) == 1) ||
+			!rstrcasecmp(s, "no") || !rstrcasecmp(s, "false")) {
+			return 0;
+		}
+		if (((s[0] == 'y' || s[0] == 'Y' || s[0] == '1') && strlen(s) == 1) ||
+			!rstrcasecmp(s, "yes") || !rstrcasecmp(s, "true")) {
+			return 1;
+		}
+	}
+	return -1;
+}
+
+static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
+{
+	const char *buildDir = "%{_builddir}/%{?buildsubdir}/";
+	char *fullpath;
+	char *encoded = NULL;
+	uint8_t *raw = NULL;
+	ssize_t rawlen = 0;
+	int rc = RPMRC_FAIL;
+	ARGV_t av;
+	uint32_t flags = 0;
+	uint32_t count;
+	struct rpmtd_s policies;
+	struct rpmtd_s policynames;
+	struct rpmtd_s policyflags;
+	struct rpmtd_s policytypes;
+	struct rpmtd_s policytypesidx;
+	rpmtdReset(&policies);
+	rpmtdReset(&policynames);
+	rpmtdReset(&policyflags);
+	rpmtdReset(&policytypes);
+	rpmtdReset(&policytypesidx);
+
+	fullpath = rpmGenPath(buildDir, NULL, mod->path);
+
+	if ((rpmioSlurp(fullpath, &raw, &rawlen)) != 0 || raw == NULL) {
+		rpmlog(RPMLOG_ERR, _("Failed to read  policy file: %s\n"), fullpath);
+		goto exit;
+	}
+
+	encoded = b64encode(raw, rawlen, -1);
+	if (!encoded) {
+		rpmlog(RPMLOG_ERR, _("Failed to encode policy file: %s\n"), fullpath);
+		goto exit;
+	}
+
+	if(!mod->name) {
+		/* assume base name (minus extension) if name is not given */
+		char * tmp = xstrdup(mod->path);
+		char * bname = basename(tmp);
+		char * end = strchr(bname, '.');
+		if (end) *end = '\0';
+		if (strlen(bname) > 0) {
+			mod->name = xstrdup(bname);
+		} else {
+			rpmlog(RPMLOG_ERR, _("Failed to determine a policy name: %s\n"), mod->path);
+			_free(tmp);
+			goto exit;
+		}
+		_free(tmp);
+	}
+
+	if (!mod->types) {
+		argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
+	} else {
+		argvSort(mod->types, NULL);
+		if (argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL) && argvCount(mod->types) > 1) {
+			rpmlog(RPMLOG_WARNING, _("'%s' type given with other types in %%module %s. Compacting types to '%s'.\n"),
+			       RPMPOL_TYPE_DEFAULT, mod->path, RPMPOL_TYPE_DEFAULT);
+			mod->types = argvFree(mod->types);
+			argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
+		}
+	}
+
+	if(mod->base) {
+		flags |= RPMPOL_FLAG_BASE;
+	}
+
+	/* check for duplicates */
+	if (headerIsEntry(pkg->header, RPMTAG_POLICYNAMES)) {
+		int typeCount;
+		const char * name;
+		char * type;
+		int i;
+		int idx;
+
+		headerGet(pkg->header, RPMTAG_POLICYNAMES, &policynames, HEADERGET_MINMEM);
+		headerGet(pkg->header, RPMTAG_POLICYFLAGS, &policyflags, HEADERGET_ARGV | HEADERGET_MINMEM);
+		headerGet(pkg->header, RPMTAG_POLICYTYPES, &policytypes, HEADERGET_ARGV | HEADERGET_MINMEM);
+		headerGet(pkg->header, RPMTAG_POLICYTYPESINDEXES, &policytypesidx, HEADERGET_ARGV | HEADERGET_MINMEM);
+		typeCount = rpmtdCount(&policytypes);
+
+		while ((name = rpmtdNextString(&policynames))) {
+			int overlappingtypes = 0;
+
+			idx = rpmtdGetIndex(&policynames);
+
+			for (i = 0; i < typeCount; i++) {
+				if (((int*)policytypesidx.data)[i] != idx) {
+					continue;
+				}
+
+				type = ((char**)policytypes.data)[i];
+
+				if (rstreq(type, RPMPOL_TYPE_DEFAULT) ||
+					argvSearch(mod->types, type, NULL) ||
+					argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL)) {
+					overlappingtypes = 1;
+					break;
+				}
+			}
+
+			if (!overlappingtypes) {
+				continue;
+			}
+
+			if (rstreq(mod->name, name)) {
+				rpmlog(RPMLOG_ERR, "Policy module '%s' duplicated with overlapping types\n", name);
+				goto exit;
+			}
+
+			if (mod->base && (((int*)policyflags.data)[idx] & RPMPOL_FLAG_BASE)) {
+				rpmlog(RPMLOG_ERR, "Base modules '%s' and '%s' have overlapping types\n", mod->name, name);
+				goto exit;
+			}
+		}
+	}
+
+	if (headerIsEntry(pkg->header, RPMTAG_POLICIES)) {
+		if (!headerGet(pkg->header, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
+			rpmlog(RPMLOG_ERR, _("Failed to get policies from header\n"));
+			goto exit;
+		}
+		count = rpmtdCount(&policies);
+	} else {
+		count = 0;
+	}
+
+	/* save everything to the header */
+	headerPutString(pkg->header, RPMTAG_POLICIES, encoded);
+	headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name);
+	headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &flags, 1);
+
+	for (av = mod->types; av && *av; av++) {
+		headerPutString(pkg->header, RPMTAG_POLICYTYPES, *av);
+		headerPutUint32(pkg->header, RPMTAG_POLICYTYPESINDEXES, &count, 1);
+	}
+
+	for (av = mod->obsoletes; av && *av; av++) {
+		headerPutString(pkg->header, RPMTAG_POLICYOBSOLETES, *av);
+		headerPutUint32(pkg->header, RPMTAG_POLICYOBSOLETESBY, &count, 1);
+	}
+
+	rc = RPMRC_OK;
+
+exit:
+	_free(encoded);
+	_free(raw);
+	_free(fullpath);
+
+	rpmtdFreeData(&policies);
+	rpmtdFreeData(&policynames);
+	rpmtdFreeData(&policyflags);
+	rpmtdFreeData(&policytypes);
+	rpmtdFreeData(&policytypesidx);
+
+	return rc;
+}
+
+static ModuleRec freeModule(ModuleRec mod)
+{
+	if (mod) {
+		_free(mod->path);
+		_free(mod->name);
+		argvFree(mod->obsoletes);
+		argvFree(mod->types);
+	}
+
+	return NULL;
+}
+
+static ModuleRec newModule(char * path)
+{
+	char *end;
+	ModuleRec mod;
+
+	if (!path) {
+		return NULL;
+	}
+
+	SKIPSPACE(path);
+	if (*path == '\0') {
+		rpmlog(RPMLOG_ERR, _("%%module requires a file path\n"));
+		return NULL;
+	}
+
+	end = path;
+	SKIPNONSPACE(end);
+	if (*end != '\0') {
+		*end++ = '\0';
+		SKIPSPACE(end);
+		if (*end != '\0') {
+			rpmlog(RPMLOG_ERR, _("%%module takes a single token only\n"));
+			return NULL;
+		}
+	}
+
+	mod = xcalloc(1, sizeof(*mod));
+	mod->path = strdup(path);
+
+	return mod;
+}
+
+
+static rpmRC parseModuleAttr(ModuleRec mod, char *line)
+{
+	MODA_t *moda;
+	char *l;
+	char *s;
+	char *end;
+	int multitoken;
+	rpmRC rc = RPMRC_FAIL;
+
+	if (!mod) {
+		rpmlog(RPMLOG_ERR, _("Expected %%module directive: %s\n"), line);
+		goto exit;
+	}
+
+	l = line;
+	SKIPSPACE(l);
+
+	for (moda = moduleAttrs; moda->token != MODOPT_UNKNOWN; moda++) {
+		if (rstrncasecmp(l, moda->token, moda->len)) {
+			continue;
+		}
+		if (moda->deprecated) {
+			rpmlog(RPMLOG_WARNING, _("%s is deprecated: %s\n"), moda->token, line);
+		}
+		break;
+	}
+
+	if (moda->token == MODOPT_UNKNOWN) {
+		rpmlog(RPMLOG_ERR, _("Unknown option: %s\n"), line);
+		goto exit;
+	}
+
+	l += moda->len;
+	SKIPSPACE(l);
+	if (*l++ != ':') {
+		rpmlog(RPMLOG_ERR, _("Malformed option: %s\n"), line);
+		goto exit;
+	}
+
+	SKIPSPACE(l);
+	if (*l == '\0') {
+		rpmlog(RPMLOG_ERR, _("Empty option: %s\n"), line);
+		goto exit;
+	}
+
+	s = end = l;
+	SKIPNONSPACE(s); SKIPSPACE(s);
+	while (*end) end++;
+	multitoken = (s != end);
+
+#define SINGLE_TOKEN_ONLY \
+	if (multitoken) { \
+		rpmlog(RPMLOG_ERR, _("Option takes single token only: %s\n"), line); \
+		goto exit; \
+	}
+
+#define SINGLE_DEFINE_ONLY(ptr) \
+	if (ptr) { \
+		rpmlog(RPMLOG_ERR, _("Option specified more than once: %s\n"), line); \
+		goto exit; \
+	}
+
+	switch (moda->tag) {
+	case MODOPT_NAME:
+		SINGLE_DEFINE_ONLY(mod->name)
+		SINGLE_TOKEN_ONLY
+		mod->name = strdup(l);
+		break;
+	case MODOPT_OBSOLETES:
+		SINGLE_DEFINE_ONLY(mod->obsoletes)
+		s = l;
+		do {
+			SKIPNONSPACE(s);
+			end = s;
+			SKIPSPACE(s);
+			*end = '\0';
+			argvAdd(&mod->obsoletes, l);
+			l = s;
+		} while (*l != '\0');
+		break;
+	case MODOPT_TYPES:
+		SINGLE_DEFINE_ONLY(mod->types)
+		s = l;
+		do {
+			SKIPNONSPACE(s);
+			end = s;
+			SKIPSPACE(s);
+			*end = '\0';
+			argvAdd(&mod->types, l);
+			l = s;
+		} while (*l != '\0');
+		break;
+	case MODOPT_BASE:
+		SINGLE_TOKEN_ONLY
+		mod->base = parseYesNo(l);
+		if (mod->base == -1) {
+			rpmlog(RPMLOG_ERR, _("Unknown boolean value: %s\n"), line);
+			goto exit;
+		}
+		break;
+	default:
+		rpmlog(RPMLOG_ERR, _("Unhandled option: %s\n"), line);
+		goto exit;
+	}
+
+	rc = RPMRC_OK;
+
+exit:
+	return rc;
+}
+
+static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
+{
+	ARGV_t policies = NULL;
+	ARGV_t pol;
+	ModuleRec mod = NULL;
+	char *linep;
+	rpmRC rc = RPMRC_FAIL;
+
+	argvSplit(&policies, getStringBuf(pkg->policyList), "\n");
+	for (pol = policies; *pol != NULL; pol++) {
+		linep = *pol;
+		SKIPSPACE(linep);
+		if (*linep == '\0') {
+			continue;
+		}
+
+		if (!rstrncasecmp(linep, "%module", strlen("%module"))) {
+			if (mod) {
+				rc = writeModuleToHeader(mod, pkg);
+				if (rc != RPMRC_OK) {
+					goto exit;
+				}
+				mod = freeModule(mod);
+			}
+			mod = newModule(linep + strlen("%module"));
+			if (!mod) {
+				rc = RPMRC_FAIL;
+				goto exit;
+			}
+		} else {
+			rc = parseModuleAttr(mod, linep);
+			if (rc != RPMRC_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	if (mod) {
+		rc = writeModuleToHeader(mod, pkg);
+		if (rc != RPMRC_OK) {
+			goto exit;
+		}
+	}
+
+	rc = RPMRC_OK;
+
+exit:
+	mod = freeModule(mod);
+	argvFree(policies);
+
+	return rc;
+}
+
+int processBinaryPolicies(rpmSpec spec, int test)
+{
+	Package pkg;
+	int rc = RPMRC_OK;
+	char *nvr;
+
+	for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
+		if (pkg->policyList == NULL) {
+			continue;
+		}
+
+		nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
+		rpmlog(RPMLOG_NOTICE, _("Processing policies: %s\n"), nvr);
+		free(nvr);
+
+		if (processPolicies(spec, pkg, test) != RPMRC_OK) {
+			rc = RPMRC_FAIL;
+			break;
+		}
+	}
+
+	return rc;
+}
+
diff --git a/build/rpmbuild.h b/build/rpmbuild.h
index c7d0da3..39f35fe 100644
--- a/build/rpmbuild.h
+++ b/build/rpmbuild.h
@@ -73,7 +73,8 @@ typedef enum rpmParseState_e {
     PART_BUILDARCHITECTURES= 29+PART_BASE,/*!< */ 
     PART_TRIGGERPOSTUN  = 30+PART_BASE, /*!< */ 
     PART_TRIGGERPREIN   = 31+PART_BASE, /*!< */ 
-    PART_LAST           = 32+PART_BASE  /*!< */ 
+    PART_POLICIES       = 32+PART_BASE, /*!< */
+    PART_LAST           = 33+PART_BASE  /*!< */
 } rpmParseState; 
 
 
@@ -221,6 +222,13 @@ int parseDescription(rpmSpec spec);
 int parseFiles(rpmSpec spec);
 
 /** \ingroup rpmbuild
+ * Parse %%policy section of a spec file.
+ * @param spec		spec file control structure
+ * @return		>= 0 next rpmParseState, < 0 on error
+ */
+int parsePolicies(rpmSpec spec);
+
+/** \ingroup rpmbuild
  * Parse tags from preamble of a spec file.
  * @param spec		spec file control structure
  * @param initialPackage
@@ -368,6 +376,14 @@ int rpmlibNeedsFeature(Header h, const char * feature, const char * featureEVR);
 int processBinaryFiles(rpmSpec spec, int installSpecialDoc, int test);
 
 /** \ingroup rpmbuild
+ * Post-build processing for policy files in binary package(s).
+ * @param spec		spec file control structure
+ * @param test		don't execute scripts or package if testing
+ * @return		0 on success
+ */
+int processBinaryPolicies(rpmSpec spec, int test);
+
+/** \ingroup rpmbuild
  * Create and initialize header for source package.
  * @param spec		spec file control structure
  */
diff --git a/build/rpmspec.h b/build/rpmspec.h
index c944677..072dbb8 100644
--- a/build/rpmspec.h
+++ b/build/rpmspec.h
@@ -171,6 +171,7 @@ struct Package_s {
 
     StringBuf fileFile;
     StringBuf fileList;		/* If NULL, package will not be written */
+    StringBuf policyList;
 
     Package next;
 };
diff --git a/build/spec.c b/build/spec.c
index d3e6a6a..0ec70cc 100644
--- a/build/spec.c
+++ b/build/spec.c
@@ -119,6 +119,7 @@ Package newPackage(rpmSpec spec)
     
     p->fileFile = NULL;
     p->fileList = NULL;
+    p->policyList = NULL;
 
     p->cpioList = NULL;
 
@@ -158,6 +159,7 @@ Package freePackage(Package pkg)
     pkg->ds = rpmdsFree(pkg->ds);
     pkg->fileList = freeStringBuf(pkg->fileList);
     pkg->fileFile = freeStringBuf(pkg->fileFile);
+    pkg->policyList = freeStringBuf(pkg->policyList);
     if (pkg->cpioList) {
 	rpmfi fi = pkg->cpioList;
 	pkg->cpioList = NULL;
diff --git a/lib/rpmpol.h b/lib/rpmpol.h
new file mode 100644
index 0000000..ee74a84
--- /dev/null
+++ b/lib/rpmpol.h
@@ -0,0 +1,24 @@
+#ifndef H_RPMPOL
+#define H_RPMPOL
+
+/** \ingroup rpmpol
+ * \file lib/rpmpol.h
+ * Structure(s) used for policy sets.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum rpmpolFlags_e {
+	RPMPOL_FLAG_NONE = 0,
+	RPMPOL_FLAG_BASE = (1 << 0)
+} rpmpolFlags;
+
+#define RPMPOL_TYPE_DEFAULT "default"
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif				/* H_rpmpol */
diff --git a/lib/rpmtag.h b/lib/rpmtag.h
index eb3b1ad..a2ee6d9 100644
--- a/lib/rpmtag.h
+++ b/lib/rpmtag.h
@@ -272,6 +272,12 @@ typedef enum rpmTag_e {
     RPMTAG_BUILDOBSOLETES	= 1194, /* internal */
     RPMTAG_DBINSTANCE		= 1195, /* i extension */
     RPMTAG_NVRA			= 1196, /* s extension */
+    RPMTAG_POLICYNAMES		= 2100,	/* s[] */
+    RPMTAG_POLICYTYPES		= 2101,	/* s[] */
+    RPMTAG_POLICYTYPESINDEXES		= 2102,	/* i[] */
+    RPMTAG_POLICYFLAGS		= 2103,	/* i[] */
+    RPMTAG_POLICYOBSOLETES		= 2104,	/* s[] */
+    RPMTAG_POLICYOBSOLETESBY		= 2105,	/* i[] */
     RPMTAG_FILENAMES		= 5000, /* s[] extension */
     RPMTAG_FILEPROVIDE		= 5001, /* s[] extension */
     RPMTAG_FILEREQUIRE		= 5002, /* s[] extension */
diff --git a/preinstall.am b/preinstall.am
index d79a9f0..1e0cfa2 100644
--- a/preinstall.am
+++ b/preinstall.am
@@ -86,6 +86,10 @@ include/rpm/rpmps.h: lib/rpmps.h include/rpm/$(dirstamp)
 	$(INSTALL_DATA) $(top_srcdir)/lib/rpmps.h include/rpm/rpmps.h
 BUILT_SOURCES += include/rpm/rpmps.h
 CLEANFILES += include/rpm/rpmps.h
+include/rpm/rpmpol.h: lib/rpmpol.h include/rpm/$(dirstamp)
+	$(INSTALL_DATA) $(top_srcdir)/lib/rpmpol.h include/rpm/rpmpol.h
+BUILT_SOURCES += include/rpm/rpmpol.h
+CLEANFILES += include/rpm/rpmpol.h
 include/rpm/rpmtag.h: lib/rpmtag.h include/rpm/$(dirstamp)
 	$(INSTALL_DATA) $(top_srcdir)/lib/rpmtag.h include/rpm/rpmtag.h
 BUILT_SOURCES += include/rpm/rpmtag.h
-- 
1.6.0.6



More information about the Rpm-maint mailing list