Use regular stream functions instead of rpmio in spec sanity check
[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 <rpm/rpmcli.h>
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmlib.h>         /* rpmrc, MACHTABLE .. */
10 #include <rpm/rpmbuild.h>
11
12 #include <rpm/rpmps.h>
13 #include <rpm/rpmte.h>
14 #include <rpm/rpmts.h>
15 #include <rpm/rpmfileutil.h>
16 #include <rpm/rpmlog.h>
17
18 #include "build.h"
19 #include "debug.h"
20
21 /**
22  */
23 static int checkSpec(rpmts ts, Header h)
24 {
25     rpmps ps;
26     int rc;
27
28     if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
29      && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
30         return 0;
31
32     rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
33
34     rc = rpmtsCheck(ts);
35
36     ps = rpmtsProblems(ts);
37     if (rc == 0 && rpmpsNumProblems(ps) > 0) {
38         rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
39         rpmpsPrint(NULL, ps);
40         rc = 1;
41     }
42     ps = rpmpsFree(ps);
43
44     /* XXX nuke the added package. */
45     rpmtsClean(ts);
46
47     return rc;
48 }
49
50 /**
51  */
52 static int isSpecFile(const char * specfile)
53 {
54     char buf[256];
55     const char * s;
56     FILE * f;
57     int count;
58     int checking;
59
60     f = fopen(specfile, "r");
61     if (f == NULL || ferror(f)) {
62         rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
63                 specfile, strerror(errno));
64         return 0;
65     }
66     count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
67     (void) fclose(f);
68
69     checking = 1;
70     for (s = buf; count--; s++) {
71         switch (*s) {
72         case '\r':
73         case '\n':
74             checking = 1;
75             break;
76         case ':':
77             checking = 0;
78             break;
79         default:
80 #if 0
81             if (checking && !(isprint(*s) || isspace(*s))) return 0;
82             break;
83 #else
84             if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
85             break;
86 #endif
87         }
88     }
89     return 1;
90 }
91
92 /**
93  */
94 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
95 {
96     const char * passPhrase = ba->passPhrase;
97     const char * cookie = ba->cookie;
98     int buildAmount = ba->buildAmount;
99     char * buildRootURL = NULL;
100     const char * specFile;
101     const char * specURL;
102     int specut;
103     char buf[BUFSIZ];
104     rpmSpec spec = NULL;
105     int rc;
106
107 #ifndef DYING
108     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
109 #endif
110
111     if (ba->buildRootOverride)
112         buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
113
114     /* FIX: static zcmds heartburn */
115     if (ba->buildMode == 't') {
116         FILE *fp;
117         char * specDir;
118         char * tmpSpecFile;
119         char * cmd, * s;
120         rpmCompressedMagic res = COMPRESSED_OTHER;
121         static const char *zcmds[] =
122                 { "cat", "gunzip", "bunzip2", "cat" };
123
124         specDir = rpmGetPath("%{_specdir}", NULL);
125
126         tmpSpecFile = (char *) rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
127 #if defined(HAVE_MKSTEMP)
128         (void) close(mkstemp(tmpSpecFile));
129 #else
130         (void) mktemp(tmpSpecFile);
131 #endif
132
133         (void) rpmFileIsCompressed(arg, &res);
134
135         cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
136         sprintf(cmd, "%s < '%s' | tar xOvf - Specfile 2>&1 > '%s'",
137                         zcmds[res & 0x3], arg, tmpSpecFile);
138         if (!(fp = popen(cmd, "r"))) {
139             rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
140             specDir = _free(specDir);
141             tmpSpecFile = _free(tmpSpecFile);
142             return 1;
143         }
144         if ((!fgets(buf, sizeof(buf) - 1, fp)) || !strchr(buf, '/')) {
145             /* Try again */
146             (void) pclose(fp);
147
148             sprintf(cmd, "%s < '%s' | tar xOvf - --wildcards \\*.spec 2>&1 > '%s'",
149                     zcmds[res & 0x3], arg, tmpSpecFile);
150             if (!(fp = popen(cmd, "r"))) {
151                 rpmlog(RPMLOG_ERR, _("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)) {
157                 /* Give up */
158                 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"),
159                         arg);
160                 (void) unlink(tmpSpecFile);
161                 specDir = _free(specDir);
162                 tmpSpecFile = _free(tmpSpecFile);
163                 return 1;
164             }
165         }
166         (void) pclose(fp);
167
168         cmd = s = buf;
169         while (*cmd != '\0') {
170             if (*cmd == '/') s = cmd + 1;
171             cmd++;
172         }
173
174         cmd = s;
175
176         /* remove trailing \n */
177         s = cmd + strlen(cmd) - 1;
178         *s = '\0';
179
180         specURL = s = alloca(strlen(specDir) + strlen(cmd) + 5);
181         sprintf(s, "%s/%s", specDir, cmd);
182         res = rename(tmpSpecFile, s);
183         specDir = _free(specDir);
184         
185         if (res) {
186             rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
187                         tmpSpecFile, s);
188             (void) unlink(tmpSpecFile);
189             tmpSpecFile = _free(tmpSpecFile);
190             return 1;
191         }
192         tmpSpecFile = _free(tmpSpecFile);
193
194         /* Make the directory which contains the tarball the source 
195            directory for this run */
196
197         if (*arg != '/') {
198             if (!getcwd(buf, BUFSIZ)) {
199                 rpmlog(RPMLOG_ERR, _("getcwd failed: %m\n"));
200                 return 1;
201             }
202             strcat(buf, "/");
203             strcat(buf, arg);
204         } else 
205             strcpy(buf, arg);
206
207         cmd = buf + strlen(buf) - 1;
208         while (*cmd != '/') cmd--;
209         *cmd = '\0';
210
211         addMacro(NULL, "_sourcedir", NULL, buf, RMIL_TARBALL);
212     } else {
213         specURL = arg;
214     }
215
216     specut = urlPath(specURL, &specFile);
217     if (*specFile != '/') {
218         char *s = alloca(BUFSIZ);
219         if (!getcwd(s, BUFSIZ)) {
220             rpmlog(RPMLOG_ERR, _("getcwd failed: %m\n"));
221             rc = 1;
222             goto exit;
223         }
224         strcat(s, "/");
225         strcat(s, arg);
226         specURL = s;
227     }
228
229     if (specut != URL_IS_DASH) {
230         struct stat st;
231         if (stat(specURL, &st) < 0) {
232             rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specURL);
233             rc = 1;
234             goto exit;
235         }
236         if (! S_ISREG(st.st_mode)) {
237             rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"),
238                 specURL);
239             rc = 1;
240             goto exit;
241         }
242
243         /* Try to verify that the file is actually a specfile */
244         if (!isSpecFile(specURL)) {
245             rpmlog(RPMLOG_ERR,
246                 _("File %s does not appear to be a specfile.\n"), specURL);
247             rc = 1;
248             goto exit;
249         }
250     }
251     
252     /* Parse the spec file */
253 #define _anyarch(_f)    \
254 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
255     if (parseSpec(ts, specURL, ba->rootdir, buildRootURL, 0, passPhrase,
256                 cookie, _anyarch(buildAmount), ba->force))
257     {
258         rc = 1;
259         goto exit;
260     }
261 #undef  _anyarch
262     if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
263         rc = 1;
264         goto exit;
265     }
266
267     /* Assemble source header from parsed components */
268     initSourceHeader(spec);
269
270     /* Check build prerequisites */
271     if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
272         rc = 1;
273         goto exit;
274     }
275
276     if (buildSpec(ts, 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(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
292 {
293     char *t, *te;
294     int rc = 0;
295     char * targets = ba->targets;
296 #define buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
297     int cleanFlags = ba->buildAmount & buildCleanMask;
298     rpmVSFlags vsflags, ovsflags;
299
300     vsflags = rpmExpandNumeric("%{_vsflags_build}");
301     if (ba->qva_flags & VERIFY_DIGEST)
302         vsflags |= _RPMVSF_NODIGESTS;
303     if (ba->qva_flags & VERIFY_SIGNATURE)
304         vsflags |= _RPMVSF_NOSIGNATURES;
305     if (ba->qva_flags & VERIFY_HDRCHK)
306         vsflags |= RPMVSF_NOHDRCHK;
307     ovsflags = rpmtsSetVSFlags(ts, vsflags);
308
309     if (targets == NULL) {
310         rc =  buildForTarget(ts, arg, ba);
311         goto exit;
312     }
313
314     /* parse up the build operators */
315
316     printf(_("Building target platforms: %s\n"), targets);
317
318     ba->buildAmount &= ~buildCleanMask;
319     for (t = targets; *t != '\0'; t = te) {
320         char *target;
321         if ((te = strchr(t, ',')) == NULL)
322             te = t + strlen(t);
323         target = alloca(te-t+1);
324         strncpy(target, t, (te-t));
325         target[te-t] = '\0';
326         if (*te != '\0')
327             te++;
328         else    /* XXX Perform clean-up after last target build. */
329             ba->buildAmount |= cleanFlags;
330
331         printf(_("Building for target %s\n"), target);
332
333         /* Read in configuration for target. */
334         rpmFreeMacros(NULL);
335         rpmFreeRpmrc();
336         (void) rpmReadConfigFiles(rcfile, target);
337         rc = buildForTarget(ts, arg, ba);
338         if (rc)
339             break;
340     }
341
342 exit:
343     vsflags = rpmtsSetVSFlags(ts, ovsflags);
344     /* Restore original configuration. */
345     rpmFreeMacros(NULL);
346     rpmFreeRpmrc();
347     (void) rpmReadConfigFiles(rcfile, NULL);
348
349     return rc;
350 }