81152e53e310eb9533f2d13a2ef79b93860ec22f
[platform/upstream/rpm.git] / build / build.c
1 /** \ingroup rpmbuild
2  * \file build/build.c
3  *  Top-level build dispatcher.
4  */
5
6 #include "system.h"
7
8 #include <errno.h>
9 #include <sys/wait.h>
10
11 #include <rpm/rpmlog.h>
12 #include <rpm/rpmfileutil.h>
13 #include "build/rpmbuild_internal.h"
14 #include "build/rpmbuild_misc.h"
15 #include "lib/rpmug.h"
16
17 #include "debug.h"
18
19 /**
20  */
21 static rpmRC doRmSource(rpmSpec spec)
22 {
23     struct Source *p;
24     Package pkg;
25     int rc = 0;
26     
27     for (p = spec->sources; p != NULL; p = p->next) {
28         if (! (p->flags & RPMBUILD_ISNO)) {
29             char *fn = rpmGetPath("%{_sourcedir}/", p->source, NULL);
30             rc = unlink(fn);
31             free(fn);
32             if (rc) goto exit;
33         }
34     }
35
36     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
37         for (p = pkg->icon; p != NULL; p = p->next) {
38             if (! (p->flags & RPMBUILD_ISNO)) {
39                 char *fn = rpmGetPath("%{_sourcedir}/", p->source, NULL);
40                 rc = unlink(fn);
41                 free(fn);
42                 if (rc) goto exit;
43             }
44         }
45     }
46 exit:
47     return !rc ? RPMRC_OK : RPMRC_FAIL;
48 }
49
50 /*
51  * @todo Single use by %%doc in files.c prevents static.
52  */
53 rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
54                 const char *sb, int test)
55 {
56     char *scriptName = NULL;
57     char * buildDir = rpmGenPath(spec->rootDir, "%{_builddir}", "");
58     char * buildCmd = NULL;
59     char * buildTemplate = NULL;
60     char * buildPost = NULL;
61     const char * mTemplate = NULL;
62     const char * mCmd = NULL;
63     const char * mPost = NULL;
64     int argc = 0;
65     const char **argv = NULL;
66     FILE * fp = NULL;
67
68     FD_t fd = NULL;
69     pid_t pid;
70     pid_t child;
71     int status;
72     rpmRC rc = RPMRC_FAIL; /* assume failure */
73     
74     switch (what) {
75     case RPMBUILD_PREP:
76         mTemplate = "%{__spec_prep_template}";
77         mPost = "%{__spec_prep_post}";
78         mCmd = "%{__spec_prep_cmd}";
79         break;
80     case RPMBUILD_BUILD:
81         mTemplate = "%{__spec_build_template}";
82         mPost = "%{__spec_build_post}";
83         mCmd = "%{__spec_build_cmd}";
84         break;
85     case RPMBUILD_INSTALL:
86         mTemplate = "%{__spec_install_template}";
87         mPost = "%{__spec_install_post}";
88         mCmd = "%{__spec_install_cmd}";
89         break;
90     case RPMBUILD_CHECK:
91         mTemplate = "%{__spec_check_template}";
92         mPost = "%{__spec_check_post}";
93         mCmd = "%{__spec_check_cmd}";
94         break;
95     case RPMBUILD_CLEAN:
96         mTemplate = "%{__spec_clean_template}";
97         mPost = "%{__spec_clean_post}";
98         mCmd = "%{__spec_clean_cmd}";
99         break;
100     case RPMBUILD_RMBUILD:
101         mTemplate = "%{__spec_clean_template}";
102         mPost = "%{__spec_clean_post}";
103         mCmd = "%{__spec_clean_cmd}";
104         break;
105     case RPMBUILD_STRINGBUF:
106     default:
107         mTemplate = "%{___build_template}";
108         mPost = "%{___build_post}";
109         mCmd = "%{___build_cmd}";
110         break;
111     }
112
113     if ((what != RPMBUILD_RMBUILD) && sb == NULL) {
114         rc = RPMRC_OK;
115         goto exit;
116     }
117     
118     fd = rpmMkTempFile(spec->rootDir, &scriptName);
119     if (Ferror(fd)) {
120         rpmlog(RPMLOG_ERR, _("Unable to open temp file: %s\n"), Fstrerror(fd));
121         goto exit;
122     }
123
124     if ((fp = fdopen(Fileno(fd), "w")) == NULL) {
125         rpmlog(RPMLOG_ERR, _("Unable to open stream: %s\n"), strerror(errno));
126         goto exit;
127     }
128     
129     buildTemplate = rpmExpand(mTemplate, NULL);
130     buildPost = rpmExpand(mPost, NULL);
131
132     (void) fputs(buildTemplate, fp);
133
134     if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir)
135         fprintf(fp, "cd '%s'\n", spec->buildSubdir);
136
137     if (what == RPMBUILD_RMBUILD) {
138         if (spec->buildSubdir)
139             fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
140     } else if (sb != NULL)
141         fprintf(fp, "%s", sb);
142
143     (void) fputs(buildPost, fp);
144     (void) fclose(fp);
145
146     if (test) {
147         rc = RPMRC_OK;
148         goto exit;
149     }
150     
151     if (buildDir && buildDir[0] != '/') {
152         goto exit;
153     }
154
155     buildCmd = rpmExpand(mCmd, " ", scriptName, NULL);
156     (void) poptParseArgvString(buildCmd, &argc, &argv);
157
158     rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
159     if (!(child = fork())) {
160         errno = 0;
161         (void) execvp(argv[0], (char *const *)argv);
162
163         rpmlog(RPMLOG_ERR, _("Exec of %s failed (%s): %s\n"),
164                 scriptName, name, strerror(errno));
165
166         _exit(127); /* exit 127 for compatibility with bash(1) */
167     }
168
169     pid = waitpid(child, &status, 0);
170
171     if (pid == -1) {
172         rpmlog(RPMLOG_ERR, _("Error executing scriptlet %s (%s)\n"),
173                  scriptName, name);
174         goto exit;
175     }
176
177     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
178         rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
179                  scriptName, name);
180     } else
181         rc = RPMRC_OK;
182     
183 exit:
184     Fclose(fd);
185     if (scriptName) {
186         if (rc == RPMRC_OK && !rpmIsDebug())
187             (void) unlink(scriptName);
188         free(scriptName);
189     }
190     free(argv);
191     free(buildCmd);
192     free(buildTemplate);
193     free(buildPost);
194     free(buildDir);
195
196     return rc;
197 }
198
199 static rpmRC buildSpec(BTA_t buildArgs, rpmSpec spec, int what)
200 {
201     rpmRC rc = RPMRC_OK;
202     int test = (what & RPMBUILD_NOBUILD);
203     char *cookie = buildArgs->cookie ? xstrdup(buildArgs->cookie) : NULL;
204
205     if (rpmExpandNumeric("%{?source_date_epoch_from_changelog}") &&
206         getenv("SOURCE_DATE_EPOCH") == NULL) {
207         /* Use date of first (== latest) changelog entry */
208         Header h = spec->packages->header;
209         struct rpmtd_s td;
210         if (headerGet(h, RPMTAG_CHANGELOGTIME, &td, (HEADERGET_MINMEM|HEADERGET_RAW))) {
211             char sdestr[22];
212             snprintf(sdestr, sizeof(sdestr), "%lli",
213                      (long long) rpmtdGetNumber(&td));
214             rpmlog(RPMLOG_NOTICE, _("setting %s=%s\n"), "SOURCE_DATE_EPOCH", sdestr);
215             setenv("SOURCE_DATE_EPOCH", sdestr, 0);
216             rpmtdFreeData(&td);
217         }
218     }
219
220     /* XXX TODO: rootDir is only relevant during build, eliminate from spec */
221     spec->rootDir = buildArgs->rootdir;
222     if (!spec->recursing && spec->BACount) {
223         int x;
224         /* When iterating over BANames, do the source    */
225         /* packaging on the first run, and skip RMSOURCE altogether */
226         if (spec->BASpecs != NULL)
227         for (x = 0; x < spec->BACount; x++) {
228             if ((rc = buildSpec(buildArgs, spec->BASpecs[x],
229                                 (what & ~RPMBUILD_RMSOURCE) |
230                                 (x ? 0 : (what & RPMBUILD_PACKAGESOURCE))))) {
231                 goto exit;
232             }
233         }
234     } else {
235         int didBuild = (what & (RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL));
236
237         if ((what & RPMBUILD_PREP) &&
238             (rc = doScript(spec, RPMBUILD_PREP, "%prep",
239                            getStringBuf(spec->prep), test)))
240                 goto exit;
241
242         if ((what & RPMBUILD_BUILD) &&
243             (rc = doScript(spec, RPMBUILD_BUILD, "%build",
244                            getStringBuf(spec->build), test)))
245                 goto exit;
246
247         if ((what & RPMBUILD_INSTALL) &&
248             (rc = doScript(spec, RPMBUILD_INSTALL, "%install",
249                            getStringBuf(spec->install), test)))
250                 goto exit;
251
252         if ((what & RPMBUILD_CHECK) &&
253             (rc = doScript(spec, RPMBUILD_CHECK, "%check",
254                            getStringBuf(spec->check), test)))
255                 goto exit;
256
257         if ((what & RPMBUILD_PACKAGESOURCE) &&
258             (rc = processSourceFiles(spec, buildArgs->pkgFlags)))
259                 goto exit;
260
261         if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
262             (what & RPMBUILD_FILECHECK)) &&
263             (rc = processBinaryFiles(spec, buildArgs->pkgFlags,
264                                      what & RPMBUILD_INSTALL, test)))
265                 goto exit;
266
267         if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY)) &&
268             (rc = processBinaryPolicies(spec, test)))
269                 goto exit;
270
271         if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
272             (rc = packageSources(spec, &cookie)))
273                 return rc;
274
275         if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
276             (rc = packageBinaries(spec, cookie, (didBuild == 0))))
277                 goto exit;
278         
279         if ((what & RPMBUILD_CLEAN) &&
280             (rc = doScript(spec, RPMBUILD_CLEAN, "%clean",
281                            getStringBuf(spec->clean), test)))
282                 goto exit;
283
284         if ((what & RPMBUILD_RMBUILD) &&
285             (rc = doScript(spec, RPMBUILD_RMBUILD, "--clean", NULL, test)))
286                 goto exit;
287     }
288
289     if (what & RPMBUILD_RMSOURCE)
290         doRmSource(spec);
291
292     if (what & RPMBUILD_RMSPEC)
293         (void) unlink(spec->specFile);
294
295 exit:
296     free(cookie);
297     spec->rootDir = NULL;
298     if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
299         rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
300         rpmlogPrint(NULL);
301     }
302     rpmugFree();
303
304     return rc;
305 }
306
307 rpmRC rpmSpecBuild(rpmSpec spec, BTA_t buildArgs)
308 {
309     /* buildSpec() can recurse with different buildAmount, pass it separately */
310     return buildSpec(buildArgs, spec, buildArgs->buildAmount);
311 }