Realize the remaining bits of direct rpmdb interface are dead too
[platform/upstream/rpm.git] / build / spec.c
1 /** \ingroup rpmbuild
2  * \file build/spec.c
3  * Handle spec data structure.
4  */
5
6 #include "system.h"
7
8 #include <rpm/header.h>
9 #include <rpm/rpmds.h>
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmts.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmfileutil.h>
14
15 #include "build/buildio.h"
16 #include "rpmio/rpmlua.h"
17
18 #include "debug.h"
19
20 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
21 #define SKIPWHITE(_x)   {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
22 #define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
23
24 /**
25  * @param p             trigger entry chain
26  * @return              NULL always
27  */
28 static inline
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         o = _free(o);
40     }
41     return NULL;
42 }
43
44 /**
45  * Destroy source component chain.
46  * @param s             source component chain
47  * @return              NULL always
48  */
49 static inline
50 struct Source * freeSources(struct Source * s)
51 {
52     struct Source *r, *t = s;
53
54     while (t != NULL) {
55         r = t;
56         t = t->next;
57         r->fullSource = _free(r->fullSource);
58         r = _free(r);
59     }
60     return NULL;
61 }
62
63 rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
64 {
65     const char *pname;
66     char *fullName = NULL;
67     Package p;
68
69     /* "main" package */
70     if (name == NULL) {
71         if (pkg)
72             *pkg = spec->packages;
73         return RPMRC_OK;
74     }
75
76     /* Construct package name */
77     if (flag == PART_SUBNAME) {
78         pname = headerGetString(spec->packages->header, RPMTAG_NAME);
79         rasprintf(&fullName, "%s-%s", pname, name);
80     } else {
81         fullName = xstrdup(name);
82     }
83
84     /* Locate package with fullName */
85     for (p = spec->packages; p != NULL; p = p->next) {
86         pname = headerGetString(p->header, RPMTAG_NAME);
87         if (pname && (rstreq(fullName, pname))) {
88             break;
89         }
90     }
91     free(fullName);
92
93     if (pkg)
94         *pkg = p;
95     return ((p == NULL) ? RPMRC_FAIL : RPMRC_OK);
96 }
97
98 Package newPackage(rpmSpec spec)
99 {
100     Package p;
101     Package pp;
102
103     p = xcalloc(1, sizeof(*p));
104
105     p->header = headerNew();
106     p->ds = NULL;
107     p->icon = NULL;
108
109     p->autoProv = 1;
110     p->autoReq = 1;
111     
112 #if 0    
113     p->reqProv = NULL;
114     p->triggers = NULL;
115     p->triggerScripts = NULL;
116 #endif
117
118     p->triggerFiles = NULL;
119     
120     p->fileFile = NULL;
121     p->fileList = NULL;
122
123     p->cpioList = NULL;
124
125     p->preInFile = NULL;
126     p->postInFile = NULL;
127     p->preUnFile = NULL;
128     p->postUnFile = NULL;
129     p->verifyFile = NULL;
130
131     p->specialDoc = NULL;
132     p->specialDocDir = NULL;
133
134     if (spec->packages == NULL) {
135         spec->packages = p;
136     } else {
137         /* Always add package to end of list */
138         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
139             {};
140         pp->next = p;
141     }
142     p->next = NULL;
143
144     return p;
145 }
146
147 Package freePackage(Package pkg)
148 {
149     if (pkg == NULL) return NULL;
150     
151     pkg->preInFile = _free(pkg->preInFile);
152     pkg->postInFile = _free(pkg->postInFile);
153     pkg->preUnFile = _free(pkg->preUnFile);
154     pkg->postUnFile = _free(pkg->postUnFile);
155     pkg->verifyFile = _free(pkg->verifyFile);
156
157     pkg->header = headerFree(pkg->header);
158     pkg->ds = rpmdsFree(pkg->ds);
159     pkg->fileList = freeStringBuf(pkg->fileList);
160     pkg->fileFile = freeStringBuf(pkg->fileFile);
161     if (pkg->cpioList) {
162         rpmfi fi = pkg->cpioList;
163         pkg->cpioList = NULL;
164         fi = rpmfiFree(fi);
165     }
166
167     pkg->specialDoc = freeStringBuf(pkg->specialDoc);
168     pkg->specialDocDir = _free(pkg->specialDocDir);
169     pkg->icon = freeSources(pkg->icon);
170     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
171
172     pkg = _free(pkg);
173     return NULL;
174 }
175
176 Package freePackages(Package packages)
177 {
178     Package p;
179
180     while ((p = packages) != NULL) {
181         packages = p->next;
182         p->next = NULL;
183         p = freePackage(p);
184     }
185     return NULL;
186 }
187
188 /**
189  */
190 static inline struct Source *findSource(rpmSpec spec, uint32_t num, int flag)
191 {
192     struct Source *p;
193
194     for (p = spec->sources; p != NULL; p = p->next)
195         if ((num == p->num) && (p->flags & flag)) return p;
196
197     return NULL;
198 }
199
200 int parseNoSource(rpmSpec spec, const char * field, rpmTag tag)
201 {
202     const char *f, *fe;
203     const char *name;
204     int flag;
205     uint32_t num;
206
207     if (tag == RPMTAG_NOSOURCE) {
208         flag = RPMBUILD_ISSOURCE;
209         name = "source";
210     } else {
211         flag = RPMBUILD_ISPATCH;
212         name = "patch";
213     }
214     
215     fe = field;
216     for (f = fe; *f != '\0'; f = fe) {
217         struct Source *p;
218
219         SKIPWHITE(f);
220         if (*f == '\0')
221             break;
222         fe = f;
223         SKIPNONWHITE(fe);
224         if (*fe != '\0') fe++;
225
226         if (parseUnsignedNum(f, &num)) {
227             rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
228                      spec->lineNum, f);
229             return RPMRC_FAIL;
230         }
231
232         if (! (p = findSource(spec, num, flag))) {
233             rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %u\n"),
234                      spec->lineNum, name, num);
235             return RPMRC_FAIL;
236         }
237
238         p->flags |= RPMBUILD_ISNO;
239
240     }
241
242     return 0;
243 }
244
245 int addSource(rpmSpec spec, Package pkg, const char *field, rpmTag tag)
246 {
247     struct Source *p;
248     int flag = 0;
249     const char *name = NULL;
250     char *nump;
251     char *fieldp = NULL;
252     char *buf = NULL;
253     uint32_t num = 0;
254
255     switch (tag) {
256       case RPMTAG_SOURCE:
257         flag = RPMBUILD_ISSOURCE;
258         name = "source";
259         fieldp = spec->line + 6;
260         break;
261       case RPMTAG_PATCH:
262         flag = RPMBUILD_ISPATCH;
263         name = "patch";
264         fieldp = spec->line + 5;
265         break;
266       case RPMTAG_ICON:
267         flag = RPMBUILD_ISICON;
268         fieldp = NULL;
269         break;
270       default:
271         return -1;
272         break;
273     }
274
275     /* Get the number */
276     if (tag != RPMTAG_ICON) {
277         /* We already know that a ':' exists, and that there */
278         /* are no spaces before it.                          */
279         /* This also now allows for spaces and tabs between  */
280         /* the number and the ':'                            */
281         char ch;
282         char *fieldp_backup = fieldp;
283
284         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
285             fieldp++;
286         }
287         ch = *fieldp;
288         *fieldp = '\0';
289
290         nump = fieldp_backup;
291         SKIPSPACE(nump);
292         if (nump == NULL || *nump == '\0') {
293             num = flag == RPMBUILD_ISSOURCE ? 0 : INT_MAX;
294         } else {
295             if (parseUnsignedNum(fieldp_backup, &num)) {
296                 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
297                          spec->lineNum, name, spec->line);
298                 *fieldp = ch;
299                 return RPMRC_FAIL;
300             }
301         }
302         *fieldp = ch;
303     }
304
305     /* Check whether tags of the same number haven't already been defined */
306     for (p = spec->sources; p != NULL; p = p->next) {
307         if ( p->num != num ) continue;
308         if ((tag == RPMTAG_SOURCE && p->flags == RPMBUILD_ISSOURCE) ||
309             (tag == RPMTAG_PATCH  && p->flags == RPMBUILD_ISPATCH)) {
310                 rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num);
311                 return RPMRC_FAIL;
312             }
313     }
314
315     /* Create the entry and link it in */
316     p = xmalloc(sizeof(*p));
317     p->num = num;
318     p->fullSource = xstrdup(field);
319     p->flags = flag;
320     p->source = strrchr(p->fullSource, '/');
321     if (p->source) {
322         p->source++;
323     } else {
324         p->source = p->fullSource;
325     }
326
327     if (tag != RPMTAG_ICON) {
328         p->next = spec->sources;
329         spec->sources = p;
330     } else {
331         p->next = pkg->icon;
332         pkg->icon = p;
333     }
334
335     spec->numSources++;
336
337     if (tag != RPMTAG_ICON) {
338         char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
339
340         rasprintf(&buf, "%s%d",
341                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
342         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
343         free(buf);
344         rasprintf(&buf, "%sURL%d",
345                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
346         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
347         free(buf);
348 #ifdef WITH_LUA
349         if (!spec->recursing) {
350             rpmlua lua = NULL; /* global state */
351             const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
352             rpmluaPushTable(lua, what);
353             rpmluav var = rpmluavNew();
354             rpmluavSetListMode(var, 1);
355             rpmluavSetValue(var, RPMLUAV_STRING, body);
356             rpmluaSetVar(lua, var);
357             var = rpmluavFree(var);
358             rpmluaPop(lua);
359         }
360 #endif
361         body = _free(body);
362     }
363     
364     return 0;
365 }
366
367 /**
368  */
369 static inline speclines freeSl(speclines sl)
370 {
371     int i;
372     if (sl == NULL) return NULL;
373     for (i = 0; i < sl->sl_nlines; i++)
374         sl->sl_lines[i] = _free(sl->sl_lines[i]);
375     sl->sl_lines = _free(sl->sl_lines);
376     return _free(sl);
377 }
378
379 /**
380  */
381 static inline spectags freeSt(spectags st)
382 {
383     int i;
384     if (st == NULL) return NULL;
385     for (i = 0; i < st->st_ntags; i++) {
386         spectag t = st->st_t + i;
387         t->t_lang = _free(t->t_lang);
388         t->t_msgid = _free(t->t_msgid);
389     }
390     st->st_t = _free(st->st_t);
391     return _free(st);
392 }
393
394 rpmSpec newSpec(void)
395 {
396     rpmSpec spec = xcalloc(1, sizeof(*spec));
397     
398     spec->specFile = NULL;
399
400     spec->sl = NULL;
401     spec->st = NULL;
402
403     spec->fileStack = NULL;
404     spec->lbuf[0] = '\0';
405     spec->line = spec->lbuf;
406     spec->nextline = NULL;
407     spec->nextpeekc = '\0';
408     spec->lineNum = 0;
409     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
410     spec->readStack->next = NULL;
411     spec->readStack->reading = 1;
412
413     spec->rootDir = NULL;
414     spec->prep = NULL;
415     spec->build = NULL;
416     spec->install = NULL;
417     spec->check = NULL;
418     spec->clean = NULL;
419
420     spec->sources = NULL;
421     spec->packages = NULL;
422     spec->noSource = 0;
423     spec->numSources = 0;
424
425     spec->sourceRpmName = NULL;
426     spec->sourcePkgId = NULL;
427     spec->sourceHeader = NULL;
428     spec->sourceCpioList = NULL;
429     
430     spec->buildRoot = NULL;
431     spec->buildSubdir = NULL;
432
433     spec->passPhrase = NULL;
434     spec->timeCheck = 0;
435     spec->cookie = NULL;
436
437     spec->buildRestrictions = headerNew();
438     spec->BANames = NULL;
439     spec->BACount = 0;
440     spec->recursing = 0;
441     spec->BASpecs = NULL;
442
443     spec->force = 0;
444     spec->anyarch = 0;
445
446     spec->macros = rpmGlobalMacroContext;
447     
448 #ifdef WITH_LUA
449     {
450     /* make sure patches and sources tables always exist */
451     rpmlua lua = NULL; /* global state */
452     rpmluaPushTable(lua, "patches");
453     rpmluaPushTable(lua, "sources");
454     rpmluaPop(lua);
455     rpmluaPop(lua);
456     }
457 #endif
458     return spec;
459 }
460
461 rpmSpec freeSpec(rpmSpec spec)
462 {
463
464     if (spec == NULL) return NULL;
465
466     spec->sl = freeSl(spec->sl);
467     spec->st = freeSt(spec->st);
468
469     spec->prep = freeStringBuf(spec->prep);
470     spec->build = freeStringBuf(spec->build);
471     spec->install = freeStringBuf(spec->install);
472     spec->check = freeStringBuf(spec->check);
473     spec->clean = freeStringBuf(spec->clean);
474
475     spec->buildRoot = _free(spec->buildRoot);
476     spec->buildSubdir = _free(spec->buildSubdir);
477     spec->rootDir = _free(spec->rootDir);
478     spec->specFile = _free(spec->specFile);
479
480     closeSpec(spec);
481
482     while (spec->readStack) {
483         struct ReadLevelEntry *rl = spec->readStack;
484         spec->readStack = rl->next;
485         rl->next = NULL;
486         free(rl);
487     }
488     
489     spec->sourceRpmName = _free(spec->sourceRpmName);
490     spec->sourcePkgId = _free(spec->sourcePkgId);
491     spec->sourceHeader = headerFree(spec->sourceHeader);
492
493     if (spec->sourceCpioList) {
494         rpmfi fi = spec->sourceCpioList;
495         spec->sourceCpioList = NULL;
496         fi = rpmfiFree(fi);
497     }
498     
499     spec->buildRestrictions = headerFree(spec->buildRestrictions);
500
501     if (!spec->recursing) {
502         if (spec->BASpecs != NULL)
503         while (spec->BACount--) {
504             spec->BASpecs[spec->BACount] =
505                         freeSpec(spec->BASpecs[spec->BACount]);
506         }
507         spec->BASpecs = _free(spec->BASpecs);
508     }
509     spec->BANames = _free(spec->BANames);
510
511     spec->passPhrase = _free(spec->passPhrase);
512     spec->cookie = _free(spec->cookie);
513
514 #ifdef WITH_LUA
515     rpmlua lua = NULL; /* global state */
516     rpmluaDelVar(lua, "patches");
517     rpmluaDelVar(lua, "sources");       
518 #endif
519
520     spec->sources = freeSources(spec->sources);
521     spec->packages = freePackages(spec->packages);
522     
523     spec = _free(spec);
524
525     return spec;
526 }
527
528 struct OpenFileInfo * newOpenFileInfo(void)
529 {
530     struct OpenFileInfo *ofi;
531
532     ofi = xmalloc(sizeof(*ofi));
533     ofi->fd = NULL;
534     ofi->fileName = NULL;
535     ofi->lineNum = 0;
536     ofi->readBuf[0] = '\0';
537     ofi->readPtr = NULL;
538     ofi->next = NULL;
539
540     return ofi;
541 }
542
543 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
544 {
545     rpmSpec spec = NULL;
546     Package pkg;
547     char * buildRoot = NULL;
548     int recursing = 0;
549     char * passPhrase = "";
550     char *cookie = NULL;
551     int anyarch = 1;
552     int force = 1;
553     int res = 1;
554     int xx;
555
556     if (qva->qva_showPackage == NULL)
557         goto exit;
558
559     /* FIX: make spec abstract */
560     if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
561                 cookie, anyarch, force)
562       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
563     {
564         rpmlog(RPMLOG_ERR,
565                         _("query of specfile %s failed, can't parse\n"), arg);
566         goto exit;
567     }
568
569     res = 0;
570     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
571         xx = qva->qva_showPackage(qva, ts, pkg->header);
572
573 exit:
574     spec = freeSpec(spec);
575     return res;
576 }