- fix typos in linux.{req,prov}.
[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 <rpmbuild.h>
8 #include <rpmurl.h>
9
10 #include "build.h"
11 #include "debug.h"
12
13 /*@access rpmTransactionSet @*/ /* XXX compared with NULL @*/
14 /*@access rpmdb @*/             /* XXX compared with NULL @*/
15 /*@access FD_t @*/              /* XXX compared with NULL @*/
16
17 /**
18  */
19 static int checkSpec(Header h)
20         /*@modifies h, fileSystem @*/
21 {
22     const char * rootdir = NULL;
23     rpmdb db = NULL;
24     int mode = O_RDONLY;
25     rpmTransactionSet ts;
26     rpmDependencyConflict conflicts;
27     int numConflicts;
28     int rc;
29
30     if (!headerIsEntry(h, RPMTAG_REQUIREFLAGS))
31         return 0;
32
33     if (rpmdbOpen(rootdir, &db, mode, 0644)) {
34         const char * dn;
35         dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
36         rpmError(RPMERR_OPEN, _("cannot open rpm database in %s\n"), dn);
37         dn = _free(dn);
38         exit(EXIT_FAILURE);
39     }
40     ts = rpmtransCreateSet(db, rootdir);
41
42     rc = rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
43
44     rc = rpmdepCheck(ts, &conflicts, &numConflicts);
45     if (rc == 0 && conflicts) {
46         rpmMessage(RPMMESS_ERROR, _("failed build dependencies:\n"));
47         printDepProblems(stderr, conflicts, numConflicts);
48         conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
49         rc = 1;
50     }
51
52     if (ts != NULL)
53         rpmtransFree(ts);
54     if (db != NULL)
55         (void) rpmdbClose(db);
56
57     return rc;
58 }
59
60 /*
61  * Kurwa, durni ameryka?ce sobe zawsze my?l?, ?e ca?y ?wiat mówi po
62  * angielsku...
63  */
64 /* XXX this is still a dumb test but at least it's i18n aware */
65 /**
66  */
67 static int isSpecFile(const char * specfile)
68         /*@modifies fileSystem @*/
69 {
70     char buf[256];
71     const char * s;
72     FD_t fd;
73     int count;
74     int checking;
75
76     fd = Fopen(specfile, "r.ufdio");
77     if (fd == NULL || Ferror(fd)) {
78         rpmError(RPMERR_OPEN, _("Unable to open spec file %s: %s\n"),
79                 specfile, Fstrerror(fd));
80         return 0;
81     }
82     count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
83     (void) Fclose(fd);
84
85     checking = 1;
86     for (s = buf; count--; s++) {
87         switch (*s) {
88         case '\r':
89         case '\n':
90             checking = 1;
91             break;
92         case ':':
93             checking = 0;
94             break;
95         default:
96             if (checking && !(isprint(*s) || isspace(*s))) return 0;
97             break;
98         }
99     }
100     return 1;
101 }
102
103 /**
104  */
105 static int buildForTarget(const char * arg, BTA_t ba,
106                 const char * passPhrase, char * cookie)
107         /*@modifies fileSystem @*/
108 {
109     int buildAmount = ba->buildAmount;
110     const char * buildRootURL = NULL;
111     const char * specFile;
112     const char * specURL;
113     int specut;
114     char buf[BUFSIZ];
115     Spec spec = NULL;
116     int rc;
117
118 #ifndef DYING
119     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
120 #endif
121
122     if (ba->buildRootOverride)
123         buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
124
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
225     specut = urlPath(specURL, &specFile);
226     if (*specFile != '/') {
227         char *s = alloca(BUFSIZ);
228         (void)getcwd(s, BUFSIZ);
229         strcat(s, "/");
230         strcat(s, arg);
231         specURL = s;
232     }
233
234     if (specut != URL_IS_DASH) {
235         struct stat st;
236         if (Stat(specURL, &st) < 0) {
237             rpmError(RPMERR_STAT, _("failed to stat %s: %m\n"), specURL);
238             rc = 1;
239             goto exit;
240         }
241         if (! S_ISREG(st.st_mode)) {
242             rpmError(RPMERR_NOTREG, _("File %s is not a regular file.\n"),
243                 specURL);
244             rc = 1;
245             goto exit;
246         }
247
248         /* Try to verify that the file is actually a specfile */
249         if (!isSpecFile(specURL)) {
250             rpmError(RPMERR_BADSPEC,
251                 _("File %s does not appear to be a specfile.\n"), specURL);
252             rc = 1;
253             goto exit;
254         }
255     }
256     
257     /* Parse the spec file */
258 #define _anyarch(_f)    \
259 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
260     if (parseSpec(&spec, specURL, ba->rootdir, buildRootURL, 0, passPhrase,
261                 cookie, _anyarch(buildAmount), ba->force)) {
262         rc = 1;
263         goto exit;
264     }
265 #undef  _anyarch
266
267     /* Assemble source header from parsed components */
268     initSourceHeader(spec);
269
270     /* Check build prerequisites */
271     if (!ba->noDeps && checkSpec(spec->sourceHeader)) {
272         rc = 1;
273         goto exit;
274     }
275
276     if (buildSpec(spec, buildAmount, ba->noBuild)) {
277         rc = 1;
278         goto exit;
279     }
280     
281     if (ba->buildMode == 't')
282         (void) Unlink(specURL);
283     rc = 0;
284
285 exit:
286     spec = freeSpec(spec);
287     buildRootURL = _free(buildRootURL);
288     return rc;
289 }
290
291 int build(const char * arg, BTA_t ba,
292         const char * passPhrase, char * cookie, 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(arg, ba, passPhrase, cookie);
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(arg, ba, passPhrase, cookie);
328         if (rc)
329             break;
330     }
331
332 exit:
333     /* Restore original configuration. */
334     rpmFreeMacros(NULL);
335     (void) rpmReadConfigFiles(rcfile, NULL);
336     return rc;
337 }