Make Source0: equal to Source: again
[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         (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
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         (void) headerNVR(p->header, &pname, NULL, NULL);
87         if (pname && (! strcmp(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 = _free(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 ((rpm_tag_t) 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     }
271
272     /* Get the number */
273     if (tag != RPMTAG_ICON) {
274         /* We already know that a ':' exists, and that there */
275         /* are no spaces before it.                          */
276         /* This also now allows for spaces and tabs between  */
277         /* the number and the ':'                            */
278         char ch;
279         char *fieldp_backup = fieldp;
280
281         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
282             fieldp++;
283         }
284         ch = *fieldp;
285         *fieldp = '\0';
286
287         nump = fieldp_backup;
288         SKIPSPACE(nump);
289         if (nump == NULL || *nump == '\0') {
290             num = flag == RPMBUILD_ISSOURCE ? 0 : INT_MAX;
291         } else {
292             if (parseUnsignedNum(fieldp_backup, &num)) {
293                 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
294                          spec->lineNum, name, spec->line);
295                 *fieldp = ch;
296                 return RPMRC_FAIL;
297             }
298         }
299         *fieldp = ch;
300     }
301
302     /* Create the entry and link it in */
303     p = xmalloc(sizeof(*p));
304     p->num = num;
305     p->fullSource = xstrdup(field);
306     p->flags = flag;
307     p->source = strrchr(p->fullSource, '/');
308     if (p->source) {
309         p->source++;
310     } else {
311         p->source = p->fullSource;
312     }
313
314     if (tag != RPMTAG_ICON) {
315         p->next = spec->sources;
316         spec->sources = p;
317     } else {
318         p->next = pkg->icon;
319         pkg->icon = p;
320     }
321
322     spec->numSources++;
323
324     if (tag != RPMTAG_ICON) {
325         char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
326
327         rasprintf(&buf, "%s%d",
328                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
329         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
330         free(buf);
331         rasprintf(&buf, "%sURL%d",
332                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
333         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
334         free(buf);
335 #ifdef WITH_LUA
336         {
337         rpmlua lua = NULL; /* global state */
338         const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
339         rpmluaPushTable(lua, what);
340         rpmluav var = rpmluavNew();
341         rpmluavSetListMode(var, 1);
342         rpmluavSetValue(var, RPMLUAV_STRING, body);
343         rpmluaSetVar(lua, var);
344         var = rpmluavFree(var);
345         rpmluaPop(lua);
346         }
347 #endif
348         body = _free(body);
349     }
350     
351     return 0;
352 }
353
354 /**
355  */
356 static inline speclines freeSl(speclines sl)
357 {
358     int i;
359     if (sl == NULL) return NULL;
360     for (i = 0; i < sl->sl_nlines; i++)
361         sl->sl_lines[i] = _free(sl->sl_lines[i]);
362     sl->sl_lines = _free(sl->sl_lines);
363     return _free(sl);
364 }
365
366 /**
367  */
368 static inline spectags freeSt(spectags st)
369 {
370     int i;
371     if (st == NULL) return NULL;
372     for (i = 0; i < st->st_ntags; i++) {
373         spectag t = st->st_t + i;
374         t->t_lang = _free(t->t_lang);
375         t->t_msgid = _free(t->t_msgid);
376     }
377     st->st_t = _free(st->st_t);
378     return _free(st);
379 }
380
381 rpmSpec newSpec(void)
382 {
383     rpmSpec spec = xcalloc(1, sizeof(*spec));
384     
385     spec->specFile = NULL;
386
387     spec->sl = NULL;
388     spec->st = NULL;
389
390     spec->fileStack = NULL;
391     spec->lbuf[0] = '\0';
392     spec->line = spec->lbuf;
393     spec->nextline = NULL;
394     spec->nextpeekc = '\0';
395     spec->lineNum = 0;
396     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
397     spec->readStack->next = NULL;
398     spec->readStack->reading = 1;
399
400     spec->rootDir = NULL;
401     spec->prep = NULL;
402     spec->build = NULL;
403     spec->install = NULL;
404     spec->check = NULL;
405     spec->clean = NULL;
406
407     spec->sources = NULL;
408     spec->packages = NULL;
409     spec->noSource = 0;
410     spec->numSources = 0;
411
412     spec->sourceRpmName = NULL;
413     spec->sourcePkgId = NULL;
414     spec->sourceHeader = NULL;
415     spec->sourceCpioList = NULL;
416     
417     spec->gotBuildRoot = 0;
418     spec->buildRoot = NULL;
419     spec->buildSubdir = NULL;
420
421     spec->passPhrase = NULL;
422     spec->timeCheck = 0;
423     spec->cookie = NULL;
424
425     spec->buildRestrictions = headerNew();
426     spec->BANames = NULL;
427     spec->BACount = 0;
428     spec->recursing = 0;
429     spec->BASpecs = NULL;
430
431     spec->force = 0;
432     spec->anyarch = 0;
433
434     spec->macros = rpmGlobalMacroContext;
435     
436 #ifdef WITH_LUA
437     {
438     /* make sure patches and sources tables always exist */
439     rpmlua lua = NULL; /* global state */
440     rpmluaPushTable(lua, "patches");
441     rpmluaPushTable(lua, "sources");
442     rpmluaPop(lua);
443     rpmluaPop(lua);
444     }
445 #endif
446     return spec;
447 }
448
449 rpmSpec freeSpec(rpmSpec spec)
450 {
451     struct ReadLevelEntry *rl;
452
453     if (spec == NULL) return NULL;
454
455     spec->sl = freeSl(spec->sl);
456     spec->st = freeSt(spec->st);
457
458     spec->prep = freeStringBuf(spec->prep);
459     spec->build = freeStringBuf(spec->build);
460     spec->install = freeStringBuf(spec->install);
461     spec->check = freeStringBuf(spec->check);
462     spec->clean = freeStringBuf(spec->clean);
463
464     spec->buildRoot = _free(spec->buildRoot);
465     spec->buildSubdir = _free(spec->buildSubdir);
466     spec->rootDir = _free(spec->rootDir);
467     spec->specFile = _free(spec->specFile);
468
469     closeSpec(spec);
470
471     while (spec->readStack) {
472         rl = spec->readStack;
473         spec->readStack = rl->next;
474         rl->next = NULL;
475         rl = _free(rl);
476     }
477     
478     spec->sourceRpmName = _free(spec->sourceRpmName);
479     spec->sourcePkgId = _free(spec->sourcePkgId);
480     spec->sourceHeader = headerFree(spec->sourceHeader);
481
482     if (spec->sourceCpioList) {
483         rpmfi fi = spec->sourceCpioList;
484         spec->sourceCpioList = NULL;
485         fi = rpmfiFree(fi);
486     }
487     
488     spec->buildRestrictions = headerFree(spec->buildRestrictions);
489
490     if (!spec->recursing) {
491         if (spec->BASpecs != NULL)
492         while (spec->BACount--) {
493             spec->BASpecs[spec->BACount] =
494                         freeSpec(spec->BASpecs[spec->BACount]);
495         }
496         spec->BASpecs = _free(spec->BASpecs);
497     }
498     spec->BANames = _free(spec->BANames);
499
500     spec->passPhrase = _free(spec->passPhrase);
501     spec->cookie = _free(spec->cookie);
502
503 #ifdef WITH_LUA
504     rpmlua lua = NULL; /* global state */
505     rpmluaDelVar(lua, "patches");
506     rpmluaDelVar(lua, "sources");       
507 #endif
508
509     spec->sources = freeSources(spec->sources);
510     spec->packages = freePackages(spec->packages);
511     
512     spec = _free(spec);
513
514     return spec;
515 }
516
517 struct OpenFileInfo * newOpenFileInfo(void)
518 {
519     struct OpenFileInfo *ofi;
520
521     ofi = xmalloc(sizeof(*ofi));
522     ofi->fd = NULL;
523     ofi->fileName = NULL;
524     ofi->lineNum = 0;
525     ofi->readBuf[0] = '\0';
526     ofi->readPtr = NULL;
527     ofi->next = NULL;
528
529     return ofi;
530 }
531
532 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
533 {
534     rpmSpec spec = NULL;
535     Package pkg;
536     char * buildRoot = NULL;
537     int recursing = 0;
538     char * passPhrase = "";
539     char *cookie = NULL;
540     int anyarch = 1;
541     int force = 1;
542     int res = 1;
543     int xx;
544
545     if (qva->qva_showPackage == NULL)
546         goto exit;
547
548     /* FIX: make spec abstract */
549     if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
550                 cookie, anyarch, force)
551       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
552     {
553         rpmlog(RPMLOG_ERR,
554                         _("query of specfile %s failed, can't parse\n"), arg);
555         goto exit;
556     }
557
558     res = 0;
559     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
560         xx = qva->qva_showPackage(qva, ts, pkg->header);
561
562 exit:
563     spec = freeSpec(spec);
564     return res;
565 }