Change ',' to '#' in sed 's' command
[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;
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         rc = RPMRC_FAIL;
122         goto exit;
123     }
124
125     if ((fp = fdopen(Fileno(fd), "w")) == NULL) {
126         rpmlog(RPMLOG_ERR, _("Unable to open stream: %s\n"), strerror(errno));
127         rc = RPMRC_FAIL;
128         goto exit;
129     }
130     
131     buildTemplate = rpmExpand(mTemplate, NULL);
132     buildPost = rpmExpand(mPost, NULL);
133
134     (void) fputs(buildTemplate, fp);
135
136     if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir)
137         fprintf(fp, "cd '%s'\n", spec->buildSubdir);
138
139     if (what == RPMBUILD_RMBUILD) {
140         if (spec->buildSubdir)
141             fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
142     } else if (sb != NULL)
143         fprintf(fp, "%s", sb);
144
145     (void) fputs(buildPost, fp);
146     (void) fclose(fp);
147
148     if (test) {
149         rc = RPMRC_OK;
150         goto exit;
151     }
152     
153     if (buildDir && buildDir[0] != '/') {
154         rc = RPMRC_FAIL;
155         goto exit;
156     }
157
158     buildCmd = rpmExpand(mCmd, " ", scriptName, NULL);
159     (void) poptParseArgvString(buildCmd, &argc, &argv);
160
161     rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
162     if (!(child = fork())) {
163         /* NSPR messes with SIGPIPE, reset to default for the kids */
164         signal(SIGPIPE, SIG_DFL);
165         errno = 0;
166         (void) execvp(argv[0], (char *const *)argv);
167
168         rpmlog(RPMLOG_ERR, _("Exec of %s failed (%s): %s\n"),
169                 scriptName, name, strerror(errno));
170
171         _exit(127); /* exit 127 for compatibility with bash(1) */
172     }
173
174     pid = waitpid(child, &status, 0);
175
176     if (pid == -1) {
177         rpmlog(RPMLOG_ERR, _("Error executing scriptlet %s (%s)\n"),
178                  scriptName, name);
179         rc = RPMRC_FAIL;
180         goto exit;
181     }
182
183     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
184         rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
185                  scriptName, name);
186         rc = RPMRC_FAIL;
187     } else
188         rc = RPMRC_OK;
189     
190 exit:
191     Fclose(fd);
192     if (scriptName) {
193         if (rc == RPMRC_OK)
194             (void) unlink(scriptName);
195         free(scriptName);
196     }
197     free(argv);
198     free(buildCmd);
199     free(buildTemplate);
200     free(buildPost);
201     free(buildDir);
202
203     return rc;
204 }
205
206 static rpmRC buildSpec(BTA_t buildArgs, rpmSpec spec, int what)
207 {
208     rpmRC rc = RPMRC_OK;
209     int test = (what & RPMBUILD_NOBUILD);
210     char *cookie = buildArgs->cookie ? xstrdup(buildArgs->cookie) : NULL;
211
212     /* XXX TODO: rootDir is only relevant during build, eliminate from spec */
213     spec->rootDir = buildArgs->rootdir;
214     if (!spec->recursing && spec->BACount) {
215         int x;
216         /* When iterating over BANames, do the source    */
217         /* packaging on the first run, and skip RMSOURCE altogether */
218         if (spec->BASpecs != NULL)
219         for (x = 0; x < spec->BACount; x++) {
220             if ((rc = buildSpec(buildArgs, spec->BASpecs[x],
221                                 (what & ~RPMBUILD_RMSOURCE) |
222                                 (x ? 0 : (what & RPMBUILD_PACKAGESOURCE))))) {
223                 goto exit;
224             }
225         }
226     } else {
227         int didBuild = (what & (RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL));
228
229         if ((what & RPMBUILD_PREP) &&
230             (rc = doScript(spec, RPMBUILD_PREP, "%prep",
231                            getStringBuf(spec->prep), test)))
232                 goto exit;
233
234         if ((what & RPMBUILD_BUILD) &&
235             (rc = doScript(spec, RPMBUILD_BUILD, "%build",
236                            getStringBuf(spec->build), test)))
237                 goto exit;
238
239         if ((what & RPMBUILD_INSTALL) &&
240             (rc = doScript(spec, RPMBUILD_INSTALL, "%install",
241                            getStringBuf(spec->install), test)))
242                 goto exit;
243
244         if ((what & RPMBUILD_CHECK) &&
245             (rc = doScript(spec, RPMBUILD_CHECK, "%check",
246                            getStringBuf(spec->check), test)))
247                 goto exit;
248
249         if ((what & RPMBUILD_PACKAGESOURCE) &&
250             (rc = processSourceFiles(spec, buildArgs->pkgFlags)))
251                 goto exit;
252
253         if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
254             (what & RPMBUILD_FILECHECK)) &&
255             (rc = processBinaryFiles(spec, buildArgs->pkgFlags,
256                                      what & RPMBUILD_INSTALL, test)))
257                 goto exit;
258
259         if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY)) &&
260             (rc = processBinaryPolicies(spec, test)))
261                 goto exit;
262
263         if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
264             (rc = packageSources(spec, &cookie)))
265                 return rc;
266
267         if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
268             (rc = packageBinaries(spec, cookie, (didBuild == 0))))
269                 goto exit;
270         
271         if ((what & RPMBUILD_CLEAN) &&
272             (rc = doScript(spec, RPMBUILD_CLEAN, "%clean",
273                            getStringBuf(spec->clean), test)))
274                 goto exit;
275
276         if ((what & RPMBUILD_RMBUILD) &&
277             (rc = doScript(spec, RPMBUILD_RMBUILD, "--clean", NULL, test)))
278                 goto exit;
279     }
280
281     if (what & RPMBUILD_RMSOURCE)
282         doRmSource(spec);
283
284     if (what & RPMBUILD_RMSPEC)
285         (void) unlink(spec->specFile);
286
287 exit:
288     free(cookie);
289     spec->rootDir = NULL;
290     if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
291         rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
292         rpmlogPrint(NULL);
293     }
294     rpmugFree();
295
296     return rc;
297 }
298
299 rpmRC rpmSpecBuild(rpmSpec spec, BTA_t buildArgs)
300 {
301     /* buildSpec() can recurse with different buildAmount, pass it separately */
302     return buildSpec(buildArgs, spec, buildArgs->buildAmount);
303 }