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