2 * \file build/policies.c
3 * The post-build, packaging of policies
8 #include <rpm/rpmbuild.h>
10 #include <rpm/rpmlog.h>
11 #include <rpm/rpmpol.h>
12 #include <rpm/rpmbase64.h>
14 #include "rpmio/rpmio_internal.h"
15 #include "build/rpmbuild_internal.h"
20 typedef struct ModuleRec_s {
28 static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
30 rpmRC rc = RPMRC_FAIL;
33 struct rpmtd_s policies;
34 struct rpmtd_s policynames;
35 struct rpmtd_s policyflags;
36 struct rpmtd_s policytypes;
37 struct rpmtd_s policytypesidx;
38 rpmtdReset(&policies);
39 rpmtdReset(&policynames);
40 rpmtdReset(&policyflags);
41 rpmtdReset(&policytypes);
42 rpmtdReset(&policytypesidx);
48 /* check for duplicates */
49 if (headerIsEntry(pkg->header, RPMTAG_POLICYNAMES)) {
56 headerGet(pkg->header, RPMTAG_POLICYNAMES, &policynames, HEADERGET_MINMEM);
57 headerGet(pkg->header, RPMTAG_POLICYFLAGS, &policyflags, HEADERGET_ARGV | HEADERGET_MINMEM);
58 headerGet(pkg->header, RPMTAG_POLICYTYPES, &policytypes, HEADERGET_ARGV | HEADERGET_MINMEM);
59 headerGet(pkg->header, RPMTAG_POLICYTYPESINDEXES, &policytypesidx, HEADERGET_ARGV | HEADERGET_MINMEM);
60 typeCount = rpmtdCount(&policytypes);
62 while ((name = rpmtdNextString(&policynames))) {
63 int overlappingtypes = 0;
65 idx = rpmtdGetIndex(&policynames);
67 for (i = 0; i < typeCount; i++) {
68 if (((int *) policytypesidx.data)[i] != idx) {
72 type = ((char **) policytypes.data)[i];
74 if (rstreq(type, RPMPOL_TYPE_DEFAULT) ||
75 argvSearch(mod->types, type, NULL) ||
76 argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL)) {
82 if (!overlappingtypes) {
86 if (rstreq(mod->name, name)) {
87 rpmlog(RPMLOG_ERR, _("Policy module '%s' duplicated with overlapping types\n"), name);
91 if ((mod->flags && RPMPOL_FLAG_BASE) &&
92 (((int *) policyflags.data)[idx] & RPMPOL_FLAG_BASE)) {
93 rpmlog(RPMLOG_ERR, _("Base modules '%s' and '%s' have overlapping types\n"), mod->name, name);
99 if (headerIsEntry(pkg->header, RPMTAG_POLICIES)) {
100 if (!headerGet(pkg->header, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
101 rpmlog(RPMLOG_ERR, _("Failed to get policies from header\n"));
104 count = rpmtdCount(&policies);
109 /* save everything to the header */
110 headerPutString(pkg->header, RPMTAG_POLICIES, mod->data);
111 headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name);
112 headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &mod->flags, 1);
114 for (av = mod->types; av && *av; av++) {
115 headerPutString(pkg->header, RPMTAG_POLICYTYPES, *av);
116 headerPutUint32(pkg->header, RPMTAG_POLICYTYPESINDEXES, &count, 1);
123 rpmtdFreeData(&policies);
124 rpmtdFreeData(&policynames);
125 rpmtdFreeData(&policyflags);
126 rpmtdFreeData(&policytypes);
127 rpmtdFreeData(&policytypesidx);
132 static ModuleRec freeModule(ModuleRec mod)
138 argvFree(mod->types);
145 static ModuleRec newModule(const char *path, const char *name,
146 const char *types, uint32_t flags)
151 const char *buildDir = "%{_builddir}/%{?buildsubdir}/";
154 rpmlog(RPMLOG_ERR, _("%%semodule requires a file path\n"));
158 mod = xcalloc(1, sizeof(*mod));
160 mod->path = rpmGenPath(buildDir, NULL, path);
162 if ((rpmioSlurp(mod->path, &raw, &rawlen)) != 0 || raw == NULL) {
163 rpmlog(RPMLOG_ERR, _("Failed to read policy file: %s\n"),
168 mod->data = rpmBase64Encode(raw, rawlen, -1);
170 rpmlog(RPMLOG_ERR, _("Failed to encode policy file: %s\n"),
176 mod->name = xstrdup(name);
178 /* assume base name (minus extension) if name is not given */
179 char *tmp = xstrdup(mod->path);
180 char *bname = basename(tmp);
181 char *end = strchr(bname, '.');
184 if (strlen(bname) > 0) {
185 mod->name = xstrdup(bname);
187 rpmlog(RPMLOG_ERR, _("Failed to determine a policy name: %s\n"),
196 mod->types = argvSplitString(types, ",", ARGV_SKIPEMPTY);
197 argvSort(mod->types, NULL);
198 if (argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL) && argvCount(mod->types) > 1) {
199 rpmlog(RPMLOG_WARNING, _("'%s' type given with other types in %%semodule %s. Compacting types to '%s'.\n"),
200 RPMPOL_TYPE_DEFAULT, mod->path, RPMPOL_TYPE_DEFAULT);
201 mod->types = argvFree(mod->types);
202 argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
205 argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
217 static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
219 const char *path = NULL;
223 poptContext optCon = NULL;
225 rpmRC rc = RPMRC_FAIL;
227 struct poptOption optionsTable[] = {
228 {"name", 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
229 {"types", 't', POPT_ARG_STRING, &types, 't', NULL, NULL},
230 {"base", 'b', POPT_ARGFLAG_OR, &flags, RPMPOL_FLAG_BASE, NULL, NULL},
238 for (ARGV_const_t pol = pkg->policyList; *pol != NULL; pol++) {
240 const char *line = *pol;
241 const char **argv = NULL;
245 if ((err = poptParseArgvString(line, &argc, &argv))) {
246 rpmlog(RPMLOG_ERR, _("Error parsing %s: %s\n"),
247 line, poptStrerror(err));
251 if (!rstreq(argv[0], "%semodule")) {
252 rpmlog(RPMLOG_ERR, _("Expecting %%semodule tag: %s\n"), line);
256 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
257 while (poptGetNextOpt(optCon) > 0) {
260 path = poptGetArg(optCon);
262 rpmlog(RPMLOG_ERR, _("Missing module path in line: %s\n"),
267 if (poptPeekArg(optCon)) {
268 rpmlog(RPMLOG_ERR, _("Too many arguments in line: %s\n"),
273 mod = newModule(path, name, types, flags);
278 if (writeModuleToHeader(mod, pkg) != RPMRC_OK) {
294 rpmRC processBinaryPolicies(rpmSpec spec, int test)
301 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
302 if (pkg->policyList == NULL) {
306 nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
307 rpmlog(RPMLOG_NOTICE, _("Processing policies: %s\n"), nvr);
310 if (processPolicies(spec, pkg, test) != RPMRC_OK) {