findSource() eats only unsigned SourceXX numbers
[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 extern int specedit;
21
22 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
23 #define SKIPWHITE(_x)   {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
24 #define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
25
26 /**
27  * @param p             trigger entry chain
28  * @return              NULL always
29  */
30 static inline
31 struct TriggerFileEntry * freeTriggerFiles(struct TriggerFileEntry * p)
32 {
33     struct TriggerFileEntry *o, *q = p;
34     
35     while (q != NULL) {
36         o = q;
37         q = q->next;
38         o->fileName = _free(o->fileName);
39         o->script = _free(o->script);
40         o->prog = _free(o->prog);
41         o = _free(o);
42     }
43     return NULL;
44 }
45
46 /**
47  * Destroy source component chain.
48  * @param s             source component chain
49  * @return              NULL always
50  */
51 static inline
52 struct Source * freeSources(struct Source * s)
53 {
54     struct Source *r, *t = s;
55
56     while (t != NULL) {
57         r = t;
58         t = t->next;
59         r->fullSource = _free(r->fullSource);
60         r = _free(r);
61     }
62     return NULL;
63 }
64
65 rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
66 {
67     const char *pname;
68     char *fullName = NULL;
69     Package p;
70
71     /* "main" package */
72     if (name == NULL) {
73         if (pkg)
74             *pkg = spec->packages;
75         return RPMRC_OK;
76     }
77
78     /* Construct package name */
79     if (flag == PART_SUBNAME) {
80         (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
81         rasprintf(&fullName, "%s-%s", pname, name);
82     } else {
83         fullName = xstrdup(name);
84     }
85
86     /* Locate package with fullName */
87     for (p = spec->packages; p != NULL; p = p->next) {
88         (void) headerNVR(p->header, &pname, NULL, NULL);
89         if (pname && (! strcmp(fullName, pname))) {
90             break;
91         }
92     }
93     free(fullName);
94
95     if (pkg)
96         *pkg = p;
97     return ((p == NULL) ? RPMRC_FAIL : RPMRC_OK);
98 }
99
100 Package newPackage(rpmSpec spec)
101 {
102     Package p;
103     Package pp;
104
105     p = xcalloc(1, sizeof(*p));
106
107     p->header = headerNew();
108     p->ds = NULL;
109     p->icon = NULL;
110
111     p->autoProv = 1;
112     p->autoReq = 1;
113     
114 #if 0    
115     p->reqProv = NULL;
116     p->triggers = NULL;
117     p->triggerScripts = NULL;
118 #endif
119
120     p->triggerFiles = NULL;
121     
122     p->fileFile = NULL;
123     p->fileList = NULL;
124
125     p->cpioList = NULL;
126
127     p->preInFile = NULL;
128     p->postInFile = NULL;
129     p->preUnFile = NULL;
130     p->postUnFile = NULL;
131     p->verifyFile = NULL;
132
133     p->specialDoc = NULL;
134     p->specialDocDir = NULL;
135
136     if (spec->packages == NULL) {
137         spec->packages = p;
138     } else {
139         /* Always add package to end of list */
140         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
141             {};
142         pp->next = p;
143     }
144     p->next = NULL;
145
146     return p;
147 }
148
149 Package freePackage(Package pkg)
150 {
151     if (pkg == NULL) return NULL;
152     
153     pkg->preInFile = _free(pkg->preInFile);
154     pkg->postInFile = _free(pkg->postInFile);
155     pkg->preUnFile = _free(pkg->preUnFile);
156     pkg->postUnFile = _free(pkg->postUnFile);
157     pkg->verifyFile = _free(pkg->verifyFile);
158
159     pkg->header = headerFree(pkg->header);
160     pkg->ds = rpmdsFree(pkg->ds);
161     pkg->fileList = freeStringBuf(pkg->fileList);
162     pkg->fileFile = _free(pkg->fileFile);
163     if (pkg->cpioList) {
164         rpmfi fi = pkg->cpioList;
165         pkg->cpioList = NULL;
166         fi = rpmfiFree(fi);
167     }
168
169     pkg->specialDoc = freeStringBuf(pkg->specialDoc);
170     pkg->specialDocDir = _free(pkg->specialDocDir);
171     pkg->icon = freeSources(pkg->icon);
172     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
173
174     pkg = _free(pkg);
175     return NULL;
176 }
177
178 Package freePackages(Package packages)
179 {
180     Package p;
181
182     while ((p = packages) != NULL) {
183         packages = p->next;
184         p->next = NULL;
185         p = freePackage(p);
186     }
187     return NULL;
188 }
189
190 /**
191  */
192 static inline struct Source *findSource(rpmSpec spec, uint32_t num, int flag)
193 {
194     struct Source *p;
195
196     for (p = spec->sources; p != NULL; p = p->next)
197         if ((num == p->num) && (p->flags & flag)) return p;
198
199     return NULL;
200 }
201
202 int parseNoSource(rpmSpec spec, const char * field, rpmTag tag)
203 {
204     const char *f, *fe;
205     const char *name;
206     int num, flag;
207
208     if (tag == RPMTAG_NOSOURCE) {
209         flag = RPMBUILD_ISSOURCE;
210         name = "source";
211     } else {
212         flag = RPMBUILD_ISPATCH;
213         name = "patch";
214     }
215     
216     fe = field;
217     for (f = fe; *f != '\0'; f = fe) {
218         struct Source *p;
219
220         SKIPWHITE(f);
221         if (*f == '\0')
222             break;
223         fe = f;
224         SKIPNONWHITE(fe);
225         if (*fe != '\0') fe++;
226
227         if (parseNum(f, &num)) {
228             rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
229                      spec->lineNum, f);
230             return RPMRC_FAIL;
231         }
232
233         if (! (p = findSource(spec, num, flag))) {
234             rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %d\n"),
235                      spec->lineNum, name, num);
236             return RPMRC_FAIL;
237         }
238
239         p->flags |= RPMBUILD_ISNO;
240
241     }
242
243     return 0;
244 }
245
246 int addSource(rpmSpec spec, Package pkg, const char *field, rpmTag tag)
247 {
248     struct Source *p;
249     int flag = 0;
250     const char *name = NULL;
251     char *nump;
252     char *fieldp = NULL;
253     char *buf = NULL;
254     int num = 0;
255
256     switch ((rpm_tag_t) tag) {
257       case RPMTAG_SOURCE:
258         flag = RPMBUILD_ISSOURCE;
259         name = "source";
260         fieldp = spec->line + 6;
261         break;
262       case RPMTAG_PATCH:
263         flag = RPMBUILD_ISPATCH;
264         name = "patch";
265         fieldp = spec->line + 5;
266         break;
267       case RPMTAG_ICON:
268         flag = RPMBUILD_ISICON;
269         fieldp = NULL;
270         break;
271     }
272
273     /* Get the number */
274     if (tag != RPMTAG_ICON) {
275         /* We already know that a ':' exists, and that there */
276         /* are no spaces before it.                          */
277         /* This also now allows for spaces and tabs between  */
278         /* the number and the ':'                            */
279         char ch;
280         char *fieldp_backup = fieldp;
281
282         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
283             fieldp++;
284         }
285         ch = *fieldp;
286         *fieldp = '\0';
287
288         nump = fieldp_backup;
289         SKIPSPACE(nump);
290         if (nump == NULL || *nump == '\0') {
291             num = 0;
292         } else {
293             if (parseNum(fieldp_backup, &num)) {
294                 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
295                          spec->lineNum, name, spec->line);
296                 *fieldp = ch;
297                 return RPMRC_FAIL;
298             }
299         }
300         *fieldp = ch;
301     }
302
303     /* Create the entry and link it in */
304     p = xmalloc(sizeof(*p));
305     p->num = num;
306     p->fullSource = xstrdup(field);
307     p->flags = flag;
308     p->source = strrchr(p->fullSource, '/');
309     if (p->source) {
310         p->source++;
311     } else {
312         p->source = p->fullSource;
313     }
314
315     if (tag != RPMTAG_ICON) {
316         p->next = spec->sources;
317         spec->sources = p;
318     } else {
319         p->next = pkg->icon;
320         pkg->icon = p;
321     }
322
323     spec->numSources++;
324
325     if (tag != RPMTAG_ICON) {
326         char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
327
328         rasprintf(&buf, "%s%d",
329                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
330         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
331         free(buf);
332         rasprintf(&buf, "%sURL%d",
333                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
334         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
335         free(buf);
336 #ifdef WITH_LUA
337         {
338         rpmlua lua = NULL; /* global state */
339         const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
340         rpmluaPushTable(lua, what);
341         rpmluav var = rpmluavNew();
342         rpmluavSetListMode(var, 1);
343         rpmluavSetValue(var, RPMLUAV_STRING, body);
344         rpmluaSetVar(lua, var);
345         var = rpmluavFree(var);
346         rpmluaPop(lua);
347         }
348 #endif
349         body = _free(body);
350     }
351     
352     return 0;
353 }
354
355 /**
356  */
357 static inline speclines newSl(void)
358 {
359     speclines sl = NULL;
360     if (specedit) {
361         sl = xmalloc(sizeof(*sl));
362         sl->sl_lines = NULL;
363         sl->sl_nalloc = 0;
364         sl->sl_nlines = 0;
365     }
366     return sl;
367 }
368
369 /**
370  */
371 static inline speclines freeSl(speclines sl)
372 {
373     int i;
374     if (sl == NULL) return NULL;
375     for (i = 0; i < sl->sl_nlines; i++)
376         sl->sl_lines[i] = _free(sl->sl_lines[i]);
377     sl->sl_lines = _free(sl->sl_lines);
378     return _free(sl);
379 }
380
381 /**
382  */
383 static inline spectags newSt(void)
384 {
385     spectags st = NULL;
386     if (specedit) {
387         st = xmalloc(sizeof(*st));
388         st->st_t = NULL;
389         st->st_nalloc = 0;
390         st->st_ntags = 0;
391     }
392     return st;
393 }
394
395 /**
396  */
397 static inline spectags freeSt(spectags st)
398 {
399     int i;
400     if (st == NULL) return NULL;
401     for (i = 0; i < st->st_ntags; i++) {
402         spectag t = st->st_t + i;
403         t->t_lang = _free(t->t_lang);
404         t->t_msgid = _free(t->t_msgid);
405     }
406     st->st_t = _free(st->st_t);
407     return _free(st);
408 }
409
410 rpmSpec newSpec(void)
411 {
412     rpmSpec spec = xcalloc(1, sizeof(*spec));
413     
414     spec->specFile = NULL;
415
416     spec->sl = newSl();
417     spec->st = newSt();
418
419     spec->fileStack = NULL;
420     spec->lbuf[0] = '\0';
421     spec->line = spec->lbuf;
422     spec->nextline = NULL;
423     spec->nextpeekc = '\0';
424     spec->lineNum = 0;
425     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
426     spec->readStack->next = NULL;
427     spec->readStack->reading = 1;
428
429     spec->rootDir = NULL;
430     spec->prep = NULL;
431     spec->build = NULL;
432     spec->install = NULL;
433     spec->check = NULL;
434     spec->clean = NULL;
435
436     spec->sources = NULL;
437     spec->packages = NULL;
438     spec->noSource = 0;
439     spec->numSources = 0;
440
441     spec->sourceRpmName = NULL;
442     spec->sourcePkgId = NULL;
443     spec->sourceHeader = NULL;
444     spec->sourceCpioList = NULL;
445     
446     spec->gotBuildRoot = 0;
447     spec->buildRoot = NULL;
448     spec->buildSubdir = NULL;
449
450     spec->passPhrase = NULL;
451     spec->timeCheck = 0;
452     spec->cookie = NULL;
453
454     spec->buildRestrictions = headerNew();
455     spec->BANames = NULL;
456     spec->BACount = 0;
457     spec->recursing = 0;
458     spec->BASpecs = NULL;
459
460     spec->force = 0;
461     spec->anyarch = 0;
462
463     spec->macros = rpmGlobalMacroContext;
464     
465 #ifdef WITH_LUA
466     {
467     /* make sure patches and sources tables always exist */
468     rpmlua lua = NULL; /* global state */
469     rpmluaPushTable(lua, "patches");
470     rpmluaPushTable(lua, "sources");
471     rpmluaPop(lua);
472     rpmluaPop(lua);
473     }
474 #endif
475     return spec;
476 }
477
478 rpmSpec freeSpec(rpmSpec spec)
479 {
480     struct ReadLevelEntry *rl;
481
482     if (spec == NULL) return NULL;
483
484     spec->sl = freeSl(spec->sl);
485     spec->st = freeSt(spec->st);
486
487     spec->prep = freeStringBuf(spec->prep);
488     spec->build = freeStringBuf(spec->build);
489     spec->install = freeStringBuf(spec->install);
490     spec->check = freeStringBuf(spec->check);
491     spec->clean = freeStringBuf(spec->clean);
492
493     spec->buildRoot = _free(spec->buildRoot);
494     spec->buildSubdir = _free(spec->buildSubdir);
495     spec->rootDir = _free(spec->rootDir);
496     spec->specFile = _free(spec->specFile);
497
498     closeSpec(spec);
499
500     while (spec->readStack) {
501         rl = spec->readStack;
502         spec->readStack = rl->next;
503         rl->next = NULL;
504         rl = _free(rl);
505     }
506     
507     spec->sourceRpmName = _free(spec->sourceRpmName);
508     spec->sourcePkgId = _free(spec->sourcePkgId);
509     spec->sourceHeader = headerFree(spec->sourceHeader);
510
511     if (spec->sourceCpioList) {
512         rpmfi fi = spec->sourceCpioList;
513         spec->sourceCpioList = NULL;
514         fi = rpmfiFree(fi);
515     }
516     
517     spec->buildRestrictions = headerFree(spec->buildRestrictions);
518
519     if (!spec->recursing) {
520         if (spec->BASpecs != NULL)
521         while (spec->BACount--) {
522             spec->BASpecs[spec->BACount] =
523                         freeSpec(spec->BASpecs[spec->BACount]);
524         }
525         spec->BASpecs = _free(spec->BASpecs);
526     }
527     spec->BANames = _free(spec->BANames);
528
529     spec->passPhrase = _free(spec->passPhrase);
530     spec->cookie = _free(spec->cookie);
531
532 #ifdef WITH_LUA
533     rpmlua lua = NULL; /* global state */
534     rpmluaDelVar(lua, "patches");
535     rpmluaDelVar(lua, "sources");       
536 #endif
537
538     spec->sources = freeSources(spec->sources);
539     spec->packages = freePackages(spec->packages);
540     
541     spec = _free(spec);
542
543     return spec;
544 }
545
546 struct OpenFileInfo * newOpenFileInfo(void)
547 {
548     struct OpenFileInfo *ofi;
549
550     ofi = xmalloc(sizeof(*ofi));
551     ofi->fd = NULL;
552     ofi->fileName = NULL;
553     ofi->lineNum = 0;
554     ofi->readBuf[0] = '\0';
555     ofi->readPtr = NULL;
556     ofi->next = NULL;
557
558     return ofi;
559 }
560
561 /**
562  * Print copy of spec file, filling in Group/Description/Summary from specspo.
563  * @param spec          spec file control structure
564  */
565 static void
566 printNewSpecfile(rpmSpec spec)
567 {
568     Header h;
569     speclines sl = spec->sl;
570     spectags st = spec->st;
571     char * msgstr = NULL;
572     int i, j;
573
574     if (sl == NULL || st == NULL)
575         return;
576
577     for (i = 0; i < st->st_ntags; i++) {
578         spectag t = st->st_t + i;
579         const char * tn = rpmTagGetName(t->t_tag);
580         const char * errstr;
581         char *fmt;
582
583         if (t->t_msgid == NULL)
584             h = spec->packages->header;
585         else {
586             Package pkg;
587             char *fe;
588             char *buf = xstrdup(t->t_msgid);
589
590             fe = strchr(buf, '(');
591             h = NULL;
592             for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
593                 const char *pkgname;
594                 h = pkg->header;
595                 (void) headerNVR(h, &pkgname, NULL, NULL);
596                 if (!strcmp(pkgname, buf))
597                     break;
598             }
599             if (pkg == NULL || h == NULL)
600                 h = spec->packages->header;
601             free(buf);
602         }
603
604         if (h == NULL)
605             continue;
606
607         rasprintf(&fmt, "%%{%s}", tn);
608         msgstr = _free(msgstr);
609
610         msgstr = headerFormat(h, fmt, &errstr);
611         if (msgstr == NULL) {
612             rpmlog(RPMLOG_ERR, _("can't query %s: %s\n"), tn, errstr);
613             return;
614         }
615         free(fmt);
616
617         switch(t->t_tag) {
618         case RPMTAG_SUMMARY:
619         case RPMTAG_GROUP:
620             sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
621             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
622                 continue;
623             {   char *buf = NULL;
624                 rasprintf(&buf, "%s: %s", tn, msgstr);
625                 sl->sl_lines[t->t_startx] = buf;
626             }
627             break;
628         case RPMTAG_DESCRIPTION:
629             for (j = 1; j < t->t_nlines; j++) {
630                 if (*sl->sl_lines[t->t_startx + j] == '%')
631                     continue;
632                 sl->sl_lines[t->t_startx + j] =
633                         _free(sl->sl_lines[t->t_startx + j]);
634             }
635             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
636                 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
637                 continue;
638             }
639             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
640             if (t->t_nlines > 2)
641                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
642             break;
643         }
644     }
645     msgstr = _free(msgstr);
646
647     for (i = 0; i < sl->sl_nlines; i++) {
648         const char * s = sl->sl_lines[i];
649         if (s == NULL)
650             continue;
651         printf("%s", s);
652         if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
653             printf("\n");
654     }
655 }
656
657 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
658 {
659     rpmSpec spec = NULL;
660     Package pkg;
661     char * buildRoot = NULL;
662     int recursing = 0;
663     char * passPhrase = "";
664     char *cookie = NULL;
665     int anyarch = 1;
666     int force = 1;
667     int res = 1;
668     int xx;
669
670     if (qva->qva_showPackage == NULL)
671         goto exit;
672
673     /* FIX: make spec abstract */
674     if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
675                 cookie, anyarch, force)
676       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
677     {
678         rpmlog(RPMLOG_ERR,
679                         _("query of specfile %s failed, can't parse\n"), arg);
680         goto exit;
681     }
682
683     res = 0;
684     if (specedit) {
685         printNewSpecfile(spec);
686         goto exit;
687     }
688
689     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
690         xx = qva->qva_showPackage(qva, ts, pkg->header);
691
692 exit:
693     spec = freeSpec(spec);
694     return res;
695 }