- Grand Renaming of rpm data types.
[platform/upstream/rpm.git] / build.c
1 /** \ingroup rpmcli
2  * Parse spec file and build package.
3  */
4
5 #include "system.h"
6
7 #include <rpmcli.h>
8 #include <rpmbuild.h>
9
10 #include "rpmps.h"
11 #include "rpmte.h"
12 #include "rpmts.h"
13
14 #include "build.h"
15 #include "debug.h"
16
17 /*@access rpmts @*/     /* XXX compared with NULL @*/
18 /*@access rpmdb @*/             /* XXX compared with NULL @*/
19 /*@access FD_t @*/              /* XXX compared with NULL @*/
20
21 /**
22  */
23 static int checkSpec(rpmts ts, Header h)
24         /*@globals fileSystem, internalState @*/
25         /*@modifies ts, h, fileSystem, internalState @*/
26 {
27     rpmps ps;
28     int rc;
29
30     if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
31      && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
32         return 0;
33
34     rc = rpmtsAddPackage(ts, h, NULL, 0, NULL);
35
36     rc = rpmtsCheck(ts);
37
38     ps = rpmtsGetProblems(ts);
39     if (rc == 0 && ps) {
40         rpmMessage(RPMMESS_ERROR, _("Failed build dependencies:\n"));
41         printDepProblems(stderr, ps);
42         rc = 1;
43     }
44     ps = rpmpsFree(ps);
45
46     /* XXX nuke the added package. */
47     rpmtsClean(ts);
48
49     return rc;
50 }
51
52 /*
53  * Kurwa, durni ameryka?ce sobe zawsze my?l?, ?e ca?y ?wiat mówi po
54  * angielsku...
55  */
56 /* XXX this is still a dumb test but at least it's i18n aware */
57 /**
58  */
59 static int isSpecFile(const char * specfile)
60         /*@globals fileSystem @*/
61         /*@modifies fileSystem @*/
62 {
63     char buf[256];
64     const char * s;
65     FD_t fd;
66     int count;
67     int checking;
68
69     fd = Fopen(specfile, "r.ufdio");
70     if (fd == NULL || Ferror(fd)) {
71         rpmError(RPMERR_OPEN, _("Unable to open spec file %s: %s\n"),
72                 specfile, Fstrerror(fd));
73         return 0;
74     }
75     count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
76     (void) Fclose(fd);
77
78     checking = 1;
79     for (s = buf; count--; s++) {
80         switch (*s) {
81         case '\r':
82         case '\n':
83             checking = 1;
84             /*@switchbreak@*/ break;
85         case ':':
86             checking = 0;
87             /*@switchbreak@*/ break;
88         default:
89             if (checking && !(isprint(*s) || isspace(*s))) return 0;
90             /*@switchbreak@*/ break;
91         }
92     }
93     return 1;
94 }
95
96 /**
97  */
98 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
99         /*@globals rpmGlobalMacroContext,
100                 fileSystem, internalState @*/
101         /*@modifies ts, rpmGlobalMacroContext,
102                 fileSystem, internalState @*/
103 {
104     const char * passPhrase = ba->passPhrase;
105     const char * cookie = ba->cookie;
106     int buildAmount = ba->buildAmount;
107     const char * buildRootURL = NULL;
108     const char * specFile;
109     const char * specURL;
110     int specut;
111     char buf[BUFSIZ];
112     Spec spec = NULL;
113     int rc;
114
115 #ifndef DYING
116     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
117 #endif
118
119     /*@-branchstate@*/
120     if (ba->buildRootOverride)
121         buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
122     /*@=branchstate@*/
123
124     /*@-compmempass@*/ /* FIX: static zcmds heartburn */
125     if (ba->buildMode == 't') {
126         FILE *fp;
127         const char * specDir;
128         const char * tmpSpecFile;
129         char * cmd, * s;
130         rpmCompressedMagic res = COMPRESSED_OTHER;
131         /*@observer@*/ static const char *zcmds[] =
132                 { "cat", "gunzip", "bunzip2", "cat" };
133
134         specDir = rpmGetPath("%{_specdir}", NULL);
135
136         /* XXX Using mkstemp is difficult here. */
137         /* XXX FWIW, default %{_specdir} is root.root 0755 */
138         {   char tfn[64];
139             strcpy(tfn, "rpm-spec.XXXXXX");
140             /*@-unrecog@*/
141             tmpSpecFile = rpmGetPath("%{_specdir}/", mktemp(tfn), NULL);
142             /*@=unrecog@*/
143         }
144
145         (void) isCompressed(arg, &res);
146
147         cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
148         sprintf(cmd, "%s < %s | tar xOvf - Specfile 2>&1 > %s",
149                         zcmds[res & 0x3], arg, tmpSpecFile);
150         if (!(fp = popen(cmd, "r"))) {
151             rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
152             specDir = _free(specDir);
153             tmpSpecFile = _free(tmpSpecFile);
154             return 1;
155         }
156         if ((!fgets(buf, sizeof(buf) - 1, fp)) || !strchr(buf, '/')) {
157             /* Try again */
158             (void) pclose(fp);
159
160             sprintf(cmd, "%s < %s | tar xOvf - \\*.spec 2>&1 > %s",
161                     zcmds[res & 0x3], arg, tmpSpecFile);
162             if (!(fp = popen(cmd, "r"))) {
163                 rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
164                 specDir = _free(specDir);
165                 tmpSpecFile = _free(tmpSpecFile);
166                 return 1;
167             }
168             if (!fgets(buf, sizeof(buf) - 1, fp)) {
169                 /* Give up */
170                 rpmError(RPMERR_READ, _("Failed to read spec file from %s\n"),
171                         arg);
172                 (void) unlink(tmpSpecFile);
173                 specDir = _free(specDir);
174                 tmpSpecFile = _free(tmpSpecFile);
175                 return 1;
176             }
177         }
178         (void) pclose(fp);
179
180         cmd = s = buf;
181         while (*cmd != '\0') {
182             if (*cmd == '/') s = cmd + 1;
183             cmd++;
184         }
185
186         cmd = s;
187
188         /* remove trailing \n */
189         s = cmd + strlen(cmd) - 1;
190         *s = '\0';
191
192         specURL = s = alloca(strlen(specDir) + strlen(cmd) + 5);
193         sprintf(s, "%s/%s", specDir, cmd);
194         res = rename(tmpSpecFile, s);
195         specDir = _free(specDir);
196         
197         if (res) {
198             rpmError(RPMERR_RENAME, _("Failed to rename %s to %s: %m\n"),
199                         tmpSpecFile, s);
200             (void) unlink(tmpSpecFile);
201             tmpSpecFile = _free(tmpSpecFile);
202             return 1;
203         }
204         tmpSpecFile = _free(tmpSpecFile);
205
206         /* Make the directory which contains the tarball the source 
207            directory for this run */
208
209         if (*arg != '/') {
210             (void)getcwd(buf, BUFSIZ);
211             strcat(buf, "/");
212             strcat(buf, arg);
213         } else 
214             strcpy(buf, arg);
215
216         cmd = buf + strlen(buf) - 1;
217         while (*cmd != '/') cmd--;
218         *cmd = '\0';
219
220         addMacro(NULL, "_sourcedir", NULL, buf, RMIL_TARBALL);
221     } else {
222         specURL = arg;
223     }
224     /*@=compmempass@*/
225
226     specut = urlPath(specURL, &specFile);
227     if (*specFile != '/') {
228         char *s = alloca(BUFSIZ);
229         (void)getcwd(s, BUFSIZ);
230         strcat(s, "/");
231         strcat(s, arg);
232         specURL = s;
233     }
234
235     if (specut != URL_IS_DASH) {
236         struct stat st;
237         if (Stat(specURL, &st) < 0) {
238             rpmError(RPMERR_STAT, _("failed to stat %s: %m\n"), specURL);
239             rc = 1;
240             goto exit;
241         }
242         if (! S_ISREG(st.st_mode)) {
243             rpmError(RPMERR_NOTREG, _("File %s is not a regular file.\n"),
244                 specURL);
245             rc = 1;
246             goto exit;
247         }
248
249         /* Try to verify that the file is actually a specfile */
250         if (!isSpecFile(specURL)) {
251             rpmError(RPMERR_BADSPEC,
252                 _("File %s does not appear to be a specfile.\n"), specURL);
253             rc = 1;
254             goto exit;
255         }
256     }
257     
258     /* Parse the spec file */
259 #define _anyarch(_f)    \
260 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
261     if (parseSpec(&spec, specURL, ba->rootdir, buildRootURL, 0, passPhrase,
262                 cookie, _anyarch(buildAmount), ba->force)) {
263         rc = 1;
264         goto exit;
265     }
266 #undef  _anyarch
267
268     /* Assemble source header from parsed components */
269     initSourceHeader(spec);
270
271     /* Check build prerequisites */
272     if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
273         rc = 1;
274         goto exit;
275     }
276
277     if (buildSpec(spec, buildAmount, ba->noBuild)) {
278         rc = 1;
279         goto exit;
280     }
281     
282     if (ba->buildMode == 't')
283         (void) Unlink(specURL);
284     rc = 0;
285
286 exit:
287     spec = freeSpec(spec);
288     buildRootURL = _free(buildRootURL);
289     return rc;
290 }
291
292 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
293 {
294     char *t, *te;
295     int rc = 0;
296     char * targets = ba->targets;
297 #define buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
298     int cleanFlags = ba->buildAmount & buildCleanMask;
299
300     if (targets == NULL) {
301         rc =  buildForTarget(ts, arg, ba);
302         goto exit;
303     }
304
305     /* parse up the build operators */
306
307     printf(_("Building target platforms: %s\n"), targets);
308
309     ba->buildAmount &= ~buildCleanMask;
310     for (t = targets; *t != '\0'; t = te) {
311         char *target;
312         if ((te = strchr(t, ',')) == NULL)
313             te = t + strlen(t);
314         target = alloca(te-t+1);
315         strncpy(target, t, (te-t));
316         target[te-t] = '\0';
317         if (*te != '\0')
318             te++;
319         else    /* XXX Perform clean-up after last target build. */
320             ba->buildAmount |= cleanFlags;
321
322         printf(_("Building for target %s\n"), target);
323
324         /* Read in configuration for target. */
325         rpmFreeMacros(NULL);
326         (void) rpmReadConfigFiles(rcfile, target);
327         rc = buildForTarget(ts, arg, ba);
328         if (rc)
329             break;
330     }
331
332 exit:
333     /* Restore original configuration. */
334     rpmFreeMacros(NULL);
335     (void) rpmReadConfigFiles(rcfile, NULL);
336
337     return rc;
338 }