1 /** \ingroup rpmbuild
2  * \file build/spec.c
3  * Handle spec data structure.
4  */
5 
6 #include "system.h"
7 #include <errno.h>
8 
9 #include <rpm/header.h>
10 #include <rpm/rpmds.h>
11 #include <rpm/rpmfi.h>
12 #include <rpm/rpmts.h>
13 #include <rpm/rpmlog.h>
14 #include <rpm/rpmfileutil.h>
15 
16 #include "rpmio/rpmlua.h"
17 #include "lib/rpmfi_internal.h"		/* rpmfiles stuff */
18 #include "build/rpmbuild_internal.h"
19 
20 #include "debug.h"
21 
22 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
23 
24 /**
25  * @param p		trigger entry chain
26  * @return		NULL always
27  */
28 static inline
freeTriggerFiles(struct TriggerFileEntry * p)29 struct TriggerFileEntry * freeTriggerFiles(struct TriggerFileEntry * p)
30 {
31     struct TriggerFileEntry *o, *q = p;
32 
33     while (q != NULL) {
34 	o = q;
35 	q = q->next;
36 	o->fileName = _free(o->fileName);
37 	o->script = _free(o->script);
38 	o->prog = _free(o->prog);
39 	free(o);
40     }
41     return NULL;
42 }
43 
freeSources(struct Source * s)44 struct Source * freeSources(struct Source * s)
45 {
46     struct Source *r, *t = s;
47 
48     while (t != NULL) {
49 	r = t;
50 	t = t->next;
51 	r->fullSource = _free(r->fullSource);
52 	r->path = _free(r->path);
53 	free(r);
54     }
55     return NULL;
56 }
57 
lookupPackage(rpmSpec spec,const char * name,int flag,Package * pkg)58 rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
59 {
60     char *fullName = NULL;
61     rpmsid nameid = 0;
62     Package p;
63 
64     /* "main" package */
65     if (name == NULL) {
66 	if (pkg)
67 	    *pkg = spec->packages;
68 	return RPMRC_OK;
69     }
70 
71     /* Construct partial package name */
72     if (!(flag & PART_NAME)) {
73 	rasprintf(&fullName, "%s-%s",
74 		 headerGetString(spec->packages->header, RPMTAG_NAME), name);
75 	name = fullName;
76     }
77     nameid = rpmstrPoolId(spec->pool, name, 1);
78 
79     /* Locate package the name */
80     for (p = spec->packages; p != NULL; p = p->next) {
81 	if (p->name && p->name == nameid) {
82 	    break;
83 	}
84     }
85 
86     if (!(flag & PART_QUIET)) {
87 	if (p == NULL && pkg != NULL) {
88 	    rpmlog(RPMLOG_ERR, _("line %d: %s: package %s does not exist\n"),
89 				    spec->lineNum, spec->line, name);
90 	} else if (p != NULL && pkg == NULL) {
91 	    rpmlog(RPMLOG_ERR, _("line %d: %s: package %s already exists\n"),
92 				    spec->lineNum, spec->line, name);
93 	}
94     }
95 
96     if (fullName == name)
97 	free(fullName);
98 
99     if (pkg)
100 	*pkg = p;
101     return ((p == NULL) ? RPMRC_FAIL : RPMRC_OK);
102 }
103 
newPackage(const char * name,rpmstrPool pool,Package * pkglist)104 Package newPackage(const char *name, rpmstrPool pool, Package *pkglist)
105 {
106     Package p = xcalloc(1, sizeof(*p));
107     p->header = headerNew();
108     p->autoProv = 1;
109     p->autoReq = 1;
110     p->fileList = NULL;
111     p->fileExcludeList = NULL;
112     p->fileFile = NULL;
113     p->policyList = NULL;
114     p->fileRenameMap = NULL;
115     p->pool = rpmstrPoolLink(pool);
116     p->dpaths = NULL;
117 
118     if (name)
119 	p->name = rpmstrPoolId(p->pool, name, 1);
120 
121     if (pkglist) {
122 	if (*pkglist == NULL) {
123 	    *pkglist = p;
124 	} else {
125 	    Package pp;
126 	    /* Always add package to end of list */
127 	    for (pp = *pkglist; pp->next != NULL; pp = pp->next)
128 		{};
129 	    pp->next = p;
130 	}
131     }
132     p->next = NULL;
133 
134     return p;
135 }
136 
freePackage(Package pkg)137 Package freePackage(Package pkg)
138 {
139     if (pkg == NULL) return NULL;
140 
141     pkg->filename = _free(pkg->filename);
142     pkg->preInFile = _free(pkg->preInFile);
143     pkg->postInFile = _free(pkg->postInFile);
144     pkg->preUnFile = _free(pkg->preUnFile);
145     pkg->postUnFile = _free(pkg->postUnFile);
146     pkg->verifyFile = _free(pkg->verifyFile);
147 
148     pkg->header = headerFree(pkg->header);
149     pkg->ds = rpmdsFree(pkg->ds);
150 
151     for (int i=0; i<PACKAGE_NUM_DEPS; i++) {
152 	pkg->dependencies[i] = rpmdsFree(pkg->dependencies[i]);
153     }
154 
155     pkg->fileList = argvFree(pkg->fileList);
156     pkg->fileExcludeList = argvFree(pkg->fileExcludeList);
157     pkg->fileFile = argvFree(pkg->fileFile);
158     pkg->policyList = argvFree(pkg->policyList);
159     pkg->removePostfixes = argvFree(pkg->removePostfixes);
160     pkg->fileRenameMap = fileRenameHashFree(pkg->fileRenameMap);
161     pkg->cpioList = rpmfilesFree(pkg->cpioList);
162     pkg->dpaths = argvFree(pkg->dpaths);
163 
164     pkg->icon = freeSources(pkg->icon);
165     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
166     pkg->fileTriggerFiles = freeTriggerFiles(pkg->fileTriggerFiles);
167     pkg->transFileTriggerFiles = freeTriggerFiles(pkg->transFileTriggerFiles);
168     pkg->pool = rpmstrPoolFree(pkg->pool);
169 
170     free(pkg);
171     return NULL;
172 }
173 
freePackages(Package packages)174 static Package freePackages(Package packages)
175 {
176     Package p;
177 
178     while ((p = packages) != NULL) {
179 	packages = p->next;
180 	p->next = NULL;
181 	freePackage(p);
182     }
183     return NULL;
184 }
185 
packageDependencies(Package pkg,rpmTagVal tag)186 rpmds * packageDependencies(Package pkg, rpmTagVal tag)
187 {
188     for (int i=0; i<PACKAGE_NUM_DEPS; i++) {
189 	if (pkg->dependencies[i] == NULL) {
190 	    return &pkg->dependencies[i];
191 	}
192 	rpmTagVal tagN = rpmdsTagN(pkg->dependencies[i]);
193 	if (tagN == tag || tagN == 0) {
194 	    return &pkg->dependencies[i];
195 	}
196     }
197     return NULL;
198 }
199 
newSpec(void)200 rpmSpec newSpec(void)
201 {
202     rpmSpec spec = xcalloc(1, sizeof(*spec));
203 
204     spec->specFile = NULL;
205 
206     spec->fileStack = NULL;
207     spec->lbufSize = BUFSIZ * 10;
208     spec->lbuf = xmalloc(spec->lbufSize);
209     spec->lbuf[0] = '\0';
210     spec->line = spec->lbuf;
211     spec->nextline = NULL;
212     spec->nextpeekc = '\0';
213     spec->lineNum = 0;
214     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
215     spec->readStack->next = NULL;
216     spec->readStack->reading = 1;
217     spec->readStack->lastConditional = lineTypes;
218     spec->readStack->readable = 1;
219 
220     spec->rootDir = NULL;
221     spec->prep = NULL;
222     spec->build = NULL;
223     spec->install = NULL;
224     spec->check = NULL;
225     spec->clean = NULL;
226     spec->parsed = NULL;
227 
228     spec->sources = NULL;
229     spec->packages = NULL;
230     spec->noSource = 0;
231     spec->numSources = 0;
232     spec->autonum_patch = -1;
233     spec->autonum_source = -1;
234 
235     spec->sourceRpmName = NULL;
236     spec->sourcePkgId = NULL;
237     spec->sourcePackage = NULL;
238 
239     spec->buildRoot = NULL;
240     spec->buildSubdir = NULL;
241 
242     spec->buildRestrictions = headerNew();
243     spec->BANames = NULL;
244     spec->BACount = 0;
245     spec->recursing = 0;
246     spec->BASpecs = NULL;
247 
248     spec->flags = RPMSPEC_NONE;
249 
250     spec->macros = rpmGlobalMacroContext;
251     spec->pool = rpmstrPoolCreate();
252 
253 #ifdef WITH_LUA
254     /* make sure patches and sources tables always exist */
255     rpmlua lua = NULL; /* global state */
256     const char * luavars[] = { "patches", "sources",
257 			       "patch_nums", "source_nums", NULL, };
258     for (const char **vp = luavars; vp && *vp; vp++) {
259 	rpmluaDelVar(lua, *vp);
260 	rpmluaPushTable(lua, *vp);
261 	rpmluaPop(lua);
262     }
263 #endif
264     return spec;
265 }
266 
rpmSpecFree(rpmSpec spec)267 rpmSpec rpmSpecFree(rpmSpec spec)
268 {
269 
270     if (spec == NULL) return NULL;
271 
272     spec->prep = freeStringBuf(spec->prep);
273     spec->build = freeStringBuf(spec->build);
274     spec->install = freeStringBuf(spec->install);
275     spec->check = freeStringBuf(spec->check);
276     spec->clean = freeStringBuf(spec->clean);
277     spec->parsed = freeStringBuf(spec->parsed);
278     spec->buildrequires = freeStringBuf(spec->buildrequires);
279 
280     spec->buildRoot = _free(spec->buildRoot);
281     spec->buildSubdir = _free(spec->buildSubdir);
282     spec->specFile = _free(spec->specFile);
283 
284     closeSpec(spec);
285 
286     while (spec->readStack) {
287 	struct ReadLevelEntry *rl = spec->readStack;
288 	spec->readStack = rl->next;
289 	rl->next = NULL;
290 	free(rl);
291     }
292     spec->lbuf = _free(spec->lbuf);
293 
294     spec->sourceRpmName = _free(spec->sourceRpmName);
295     spec->sourcePkgId = _free(spec->sourcePkgId);
296     spec->sourcePackage = freePackage(spec->sourcePackage);
297 
298     spec->buildRestrictions = headerFree(spec->buildRestrictions);
299 
300     if (!spec->recursing) {
301 	if (spec->BASpecs != NULL)
302 	while (spec->BACount--) {
303 	    spec->BASpecs[spec->BACount] =
304 			rpmSpecFree(spec->BASpecs[spec->BACount]);
305 	}
306 	spec->BASpecs = _free(spec->BASpecs);
307     }
308     spec->BANames = _free(spec->BANames);
309 
310 #ifdef WITH_LUA
311     // only destroy lua tables if there are no BASpecs left
312     if (spec->recursing || spec->BACount == 0) {
313     rpmlua lua = NULL; /* global state */
314     rpmluaDelVar(lua, "patches");
315     rpmluaDelVar(lua, "sources");
316     }
317 #endif
318 
319     spec->sources = freeSources(spec->sources);
320     spec->packages = freePackages(spec->packages);
321     spec->pool = rpmstrPoolFree(spec->pool);
322 
323     spec->buildHost = _free(spec->buildHost);
324 
325     spec = _free(spec);
326 
327     return spec;
328 }
329 
rpmSpecSourceHeader(rpmSpec spec)330 Header rpmSpecSourceHeader(rpmSpec spec)
331 {
332     return (spec && spec->sourcePackage) ? spec->sourcePackage->header : NULL;
333 }
334 
rpmSpecDS(rpmSpec spec,rpmTagVal tag)335 rpmds rpmSpecDS(rpmSpec spec, rpmTagVal tag)
336 {
337     return (spec != NULL) ? rpmdsNew(spec->sourcePackage->header, tag, 0) : NULL;
338 }
339 
rpmSpecCheckDeps(rpmts ts,rpmSpec spec)340 rpmps rpmSpecCheckDeps(rpmts ts, rpmSpec spec)
341 {
342     rpmps probs = NULL;
343 
344     rpmtsEmpty(ts);
345 
346     rpmtsAddInstallElement(ts, rpmSpecSourceHeader(spec), NULL, 0, NULL);
347     rpmtsCheck(ts);
348     probs = rpmtsProblems(ts);
349 
350     rpmtsEmpty(ts);
351     return probs;
352 }
353 
354 struct rpmSpecIter_s {
355     void *next;
356 };
357 
358 #define SPEC_LISTITER_INIT(_itertype, _iteritem)	\
359     _itertype iter = NULL;				\
360     if (spec) {						\
361 	iter = xcalloc(1, sizeof(*iter));		\
362 	iter->next = spec->_iteritem;			\
363     }							\
364     return iter
365 
366 #define SPEC_LISTITER_NEXT(_valuetype)			\
367     _valuetype item = NULL;				\
368     if (iter) {						\
369 	item = iter->next;				\
370 	iter->next = (item) ? item->next : NULL;	\
371     }							\
372     return item
373 
374 #define SPEC_LISTITER_FREE()				\
375     free(iter);						\
376     return NULL
377 
378 
rpmSpecPkgIterInit(rpmSpec spec)379 rpmSpecPkgIter rpmSpecPkgIterInit(rpmSpec spec)
380 {
381     SPEC_LISTITER_INIT(rpmSpecPkgIter, packages);
382 }
383 
rpmSpecPkgIterFree(rpmSpecPkgIter iter)384 rpmSpecPkgIter rpmSpecPkgIterFree(rpmSpecPkgIter iter)
385 {
386     SPEC_LISTITER_FREE();
387 }
388 
rpmSpecPkgIterNext(rpmSpecPkgIter iter)389 rpmSpecPkg rpmSpecPkgIterNext(rpmSpecPkgIter iter)
390 {
391     SPEC_LISTITER_NEXT(rpmSpecPkg);
392 }
393 
rpmSpecPkgHeader(rpmSpecPkg pkg)394 Header rpmSpecPkgHeader(rpmSpecPkg pkg)
395 {
396     return (pkg != NULL) ? pkg->header : NULL;
397 }
398 
rpmSpecPkgGetSection(rpmSpecPkg pkg,int section)399 char* rpmSpecPkgGetSection(rpmSpecPkg pkg, int section)
400 {
401     if (pkg) {
402         switch (section) {
403         case RPMBUILD_FILE_FILE: return argvJoin(pkg->fileFile, "");
404         case RPMBUILD_FILE_LIST: return argvJoin(pkg->fileList, "");
405         case RPMBUILD_POLICY:    return argvJoin(pkg->policyList, "");
406         }
407     }
408     return NULL;
409 }
410 
rpmSpecSrcIterInit(rpmSpec spec)411 rpmSpecSrcIter rpmSpecSrcIterInit(rpmSpec spec)
412 {
413     SPEC_LISTITER_INIT(rpmSpecSrcIter, sources);
414 }
415 
rpmSpecSrcIterFree(rpmSpecSrcIter iter)416 rpmSpecSrcIter rpmSpecSrcIterFree(rpmSpecSrcIter iter)
417 {
418     SPEC_LISTITER_FREE();
419 }
420 
rpmSpecSrcIterNext(rpmSpecSrcIter iter)421 rpmSpecSrc rpmSpecSrcIterNext(rpmSpecSrcIter iter)
422 {
423     SPEC_LISTITER_NEXT(rpmSpecSrc);
424 }
425 
rpmSpecSrcFlags(rpmSpecSrc src)426 rpmSourceFlags rpmSpecSrcFlags(rpmSpecSrc src)
427 {
428     return (src != NULL) ? src->flags : 0;
429 }
430 
rpmSpecSrcNum(rpmSpecSrc src)431 int rpmSpecSrcNum(rpmSpecSrc src)
432 {
433     return (src != NULL) ? src->num : -1;
434 }
435 
rpmSpecSrcFilename(rpmSpecSrc src,int full)436 const char * rpmSpecSrcFilename(rpmSpecSrc src, int full)
437 {
438     const char *source = NULL;
439     if (src) {
440 	source = full ? src->fullSource : src->source;
441     }
442     return source;
443 }
444 
rpmSpecGetSection(rpmSpec spec,int section)445 const char * rpmSpecGetSection(rpmSpec spec, int section)
446 {
447     if (spec) {
448 	switch (section) {
449 	case RPMBUILD_NONE:	return getStringBuf(spec->parsed);
450 	case RPMBUILD_PREP:	return getStringBuf(spec->prep);
451 	case RPMBUILD_BUILD:	return getStringBuf(spec->build);
452 	case RPMBUILD_INSTALL:	return getStringBuf(spec->install);
453 	case RPMBUILD_CHECK:	return getStringBuf(spec->check);
454 	case RPMBUILD_CLEAN:	return getStringBuf(spec->clean);
455 	}
456     }
457     return NULL;
458 }
459 
rpmspecQuery(rpmts ts,QVA_t qva,const char * arg)460 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
461 {
462     rpmSpec spec = NULL;
463     int res = 1;
464 
465     if (qva->qva_showPackage == NULL)
466 	goto exit;
467 
468     spec = rpmSpecParse(arg, (RPMSPEC_ANYARCH|RPMSPEC_FORCE), NULL);
469     if (spec == NULL) {
470 	rpmlog(RPMLOG_ERR,
471 	    		_("query of specfile %s failed, can't parse\n"), arg);
472 	goto exit;
473     }
474 
475     if (qva->qva_source == RPMQV_SPECRPMS ||
476 	    qva->qva_source == RPMQV_SPECBUILTRPMS) {
477 
478 	res = 0;
479 	for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
480 
481 	    if (qva->qva_source == RPMQV_SPECBUILTRPMS && pkg->fileList == NULL)
482 		continue;
483 
484 	    res += qva->qva_showPackage(qva, ts, pkg->header);
485 	}
486     } else {
487 	Package sourcePkg = spec->sourcePackage;
488 	res = qva->qva_showPackage(qva, ts, sourcePkg->header);
489     }
490 
491 exit:
492     rpmSpecFree(spec);
493     return res;
494 }
495