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

Steve Lawrence slawrence at tresys.com
Thu Sep 10 19:33:09 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:

%policy
%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, the name is assumed to be
           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. During installation, obsoleted modules
           are removed and the new modules are installed. An example of when
           this might be used is during 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 explicity state that a module
           can work with any policy type, "default" can be specified as
           the value. If not specified, it is assumed the module can work with
           any policy type, implying the "default" type.

Spaces before and after options and the %module directive are ignored.
Options always apply to the previously declared %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 a flag value of 1 means a base policy

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
---
 build/Makefile.am     |    4 +-
 build/build.c         |    4 +
 build/parsePolicies.c |   88 +++++++++++
 build/parseSpec.c     |    5 +
 build/policies.c      |  402 +++++++++++++++++++++++++++++++++++++++++++++++++
 build/rpmbuild.h      |   18 ++-
 build/rpmspec.h       |    1 +
 build/spec.c          |    2 +
 lib/rpmtag.h          |    6 +
 9 files changed, 527 insertions(+), 3 deletions(-)
 create mode 100644 build/parsePolicies.c
 create mode 100644 build/policies.c

diff --git a/build/Makefile.am b/build/Makefile.am
index 131fbda..d0a87a0 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 0: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 3c5349d..c3295c3 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}
 };
 
@@ -490,6 +491,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..29f7788
--- /dev/null
+++ b/build/policies.c
@@ -0,0 +1,402 @@
+/** \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 "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)++; }
+
+/* TODO: move to rpmpol.h */
+#define RPMPOL_TYPE_DEFAULT "default"
+#define RPMPOL_FLAG_BASE 1
+
+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;
+	rpmtdReset(&policies);
+
+	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 {
+		for(av = mod->types; av && *av; av++) {
+			if (!rstrcasecmp(*av, RPMPOL_TYPE_DEFAULT) && argvCount(av) > 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);
+				break;
+			}
+		}
+	}
+
+	if(mod->base) {
+		flags |= RPMPOL_FLAG_BASE;
+	}
+
+	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;
+	}
+
+	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);
+
+	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 6b3d765..27ca77b 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 eb94118..e64a108 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 a867500..b747748 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/rpmtag.h b/lib/rpmtag.h
index c2b6146..3159b64 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 */
-- 
1.6.0.6



More information about the Rpm-maint mailing list