rpm  5.2.1
build.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include <rpmio_internal.h> /* XXX fdGetFp */
9 #include <rpmcb.h>
10 #define _RPMTAG_INTERNAL
11 #include <rpmbuild.h>
12 #include "signature.h" /* XXX rpmTempFile */
13 
14 #include "debug.h"
15 
16 /*@unchecked@*/
17 static int _build_debug = 0;
18 
21 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
22 const char * getSourceDir(rpmfileAttrs attr, const char *filename)
23 #else
24 const char * getSourceDir(rpmfileAttrs attr)
25 #endif
26 {
27  const char * dir = NULL;
28 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
29  const char *fn;
30 
31  /* support splitted source directories, i.e., source files which
32  are alternatively placed into the .spec directory and picked
33  up from there, too. */
34  if (attr & (RPMFILE_SOURCE|RPMFILE_PATCH|RPMFILE_ICON) && filename != NULL)
35  {
36  fn = rpmGetPath("%{_specdir}/", filename, NULL);
37  if (access(fn, F_OK) == 0)
38  dir = "%{_specdir}/";
39  fn = _free(fn);
40  }
41  if (dir != NULL) {
42  } else
43 #endif
44  if (attr & RPMFILE_SOURCE)
45  dir = "%{_sourcedir}/";
46  else if (attr & RPMFILE_PATCH)
47  dir = "%{_patchdir}/";
48  else if (attr & RPMFILE_ICON)
49  dir = "%{_icondir}/";
50 
51  return dir;
52 }
53 
54 /*@access urlinfo @*/ /* XXX compared with NULL */
55 /*@access FD_t @*/
56 
59 static void doRmSource(Spec spec)
60  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
61  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
62 {
63  struct Source *sp;
64  int rc;
65 
66 #if 0
67  rc = Unlink(spec->specFile);
68 #endif
69 
70  for (sp = spec->sources; sp != NULL; sp = sp->next) {
71  const char *dn, *fn;
72  if (sp->flags & RPMFILE_GHOST)
73  continue;
74 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
75  if (! (dn = getSourceDir(sp->flags, sp->source)))
76 #else
77  if (! (dn = getSourceDir(sp->flags)))
78 #endif
79  continue;
80  fn = rpmGenPath(NULL, dn, sp->source);
81  rc = Unlink(fn);
82  fn = _free(fn);
83  }
84 }
85 
86 /*
87  * @todo Single use by %%doc in files.c prevents static.
88  */
89 rpmRC doScript(Spec spec, int what, const char *name, rpmiob iob, int test)
90 {
91  const char * rootURL = spec->rootURL;
92  const char * rootDir;
93  const char * scriptName = NULL;
94  const char * buildDirURL = rpmGenPath(rootURL, "%{_builddir}", "");
95  const char * buildScript;
96  const char * buildCmd = NULL;
97  const char * buildTemplate = NULL;
98  const char * buildPost = NULL;
99  const char * mTemplate = NULL;
100  const char * mCmd = NULL;
101  const char * mPost = NULL;
102  int argc = 0;
103  const char **argv = NULL;
104  FILE * fp = NULL;
105  urlinfo u = NULL;
106 
107  FD_t fd;
108  FD_t xfd;
109  pid_t pid;
110  pid_t child;
111  int status;
112  rpmRC rc;
113  size_t i;
114 
115  switch (what) {
116  case RPMBUILD_PREP:
117  name = "%prep";
118  iob = spec->prep;
119  mTemplate = "%{__spec_prep_template}";
120  mPost = "%{__spec_prep_post}";
121  mCmd = "%{__spec_prep_cmd}";
122  break;
123  case RPMBUILD_BUILD:
124  name = "%build";
125  iob = spec->build;
126  mTemplate = "%{__spec_build_template}";
127  mPost = "%{__spec_build_post}";
128  mCmd = "%{__spec_build_cmd}";
129  break;
130  case RPMBUILD_INSTALL:
131  name = "%install";
132  iob = spec->install;
133  mTemplate = "%{__spec_install_template}";
134  mPost = "%{__spec_install_post}";
135  mCmd = "%{__spec_install_cmd}";
136  break;
137  case RPMBUILD_CHECK:
138  name = "%check";
139  iob = spec->check;
140  mTemplate = "%{__spec_check_template}";
141  mPost = "%{__spec_check_post}";
142  mCmd = "%{__spec_check_cmd}";
143  break;
144  case RPMBUILD_CLEAN:
145  name = "%clean";
146  iob = spec->clean;
147  mTemplate = "%{__spec_clean_template}";
148  mPost = "%{__spec_clean_post}";
149  mCmd = "%{__spec_clean_cmd}";
150  break;
151  case RPMBUILD_RMBUILD:
152  name = "--clean";
153  mTemplate = "%{__spec_clean_template}";
154  mPost = "%{__spec_clean_post}";
155  mCmd = "%{__spec_clean_cmd}";
156  break;
157  /* support "%track" script/section */
158  case RPMBUILD_TRACK:
159  name = "%track";
160  iob = NULL;
161  if (spec->foo)
162  for (i = 0; i < spec->nfoo; i++) {
163  if (spec->foo[i].str == NULL || spec->foo[i].iob == NULL)
164  continue;
165  if (xstrcasecmp(spec->foo[i].str, "track"))
166  continue;
167  iob = spec->foo[i].iob;
168  /*@loopbreak@*/ break;
169  }
170  mTemplate = "%{__spec_track_template}";
171  mPost = "%{__spec_track_post}";
172  mCmd = "%{__spec_track_cmd}";
173  break;
174  case RPMBUILD_STRINGBUF:
175  default:
176  mTemplate = "%{___build_template}";
177  mPost = "%{___build_post}";
178  mCmd = "%{___build_cmd}";
179  break;
180  }
181  if (name == NULL) /* XXX shouldn't happen */
182  name = "???";
183 
184  if ((what != RPMBUILD_RMBUILD) && iob == NULL) {
185  rc = RPMRC_OK;
186  goto exit;
187  }
188 
189  if (rpmTempFile(rootURL, &scriptName, &fd) || fd == NULL || Ferror(fd)) {
190  rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
191  rc = RPMRC_FAIL;
192  goto exit;
193  }
194 
195  if (fdGetFp(fd) == NULL)
196  xfd = Fdopen(fd, "w.fpio");
197  else
198  xfd = fd;
199 
200  /*@-type@*/ /* FIX: cast? */
201  if ((fp = fdGetFp(xfd)) == NULL) {
202  rc = RPMRC_FAIL;
203  goto exit;
204  }
205  /*@=type@*/
206 
207  (void) urlPath(rootURL, &rootDir);
208  if (*rootDir == '\0') rootDir = "/";
209 
210  (void) urlPath(scriptName, &buildScript);
211 
212  buildTemplate = rpmExpand(mTemplate, NULL);
213  buildPost = rpmExpand(mPost, NULL);
214 
215  (void) fputs(buildTemplate, fp);
216 
217  /* support "%track" script/section */
218  if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir && what != RPMBUILD_TRACK)
219  fprintf(fp, "cd '%s'\n", spec->buildSubdir);
220 
221  if (what == RPMBUILD_RMBUILD) {
222  if (spec->buildSubdir)
223  fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
224  } else if (iob != NULL)
225  fprintf(fp, "%s", rpmiobStr(iob));
226 
227  (void) fputs(buildPost, fp);
228 
229  (void) Fclose(xfd);
230 
231  if (test) {
232  rc = RPMRC_OK;
233  goto exit;
234  }
235 
236 if (_build_debug)
237 fprintf(stderr, "*** rootURL %s buildDirURL %s\n", rootURL, buildDirURL);
238  if (buildDirURL && buildDirURL[0] != '/' &&
239  (urlSplit(buildDirURL, &u) != 0)) {
240  rc = RPMRC_FAIL;
241  goto exit;
242  }
243  if (u != NULL) {
244  switch (u->urltype) {
245  case URL_IS_HTTPS:
246  case URL_IS_HTTP:
247  case URL_IS_FTP:
248 if (_build_debug)
249 fprintf(stderr, "*** addMacros\n");
250  addMacro(spec->macros, "_remsh", NULL, "%{__remsh}", RMIL_SPEC);
251  addMacro(spec->macros, "_remhost", NULL, u->host, RMIL_SPEC);
252  if (strcmp(rootDir, "/"))
253  addMacro(spec->macros, "_remroot", NULL, rootDir, RMIL_SPEC);
254  break;
255  case URL_IS_UNKNOWN:
256  case URL_IS_DASH:
257  case URL_IS_PATH:
258  case URL_IS_HKP:
259  default:
260  break;
261  }
262  }
263 
264  buildCmd = rpmExpand(mCmd, " ", buildScript, NULL);
265  (void) poptParseArgvString(buildCmd, &argc, &argv);
266 
267  if (what != RPMBUILD_TRACK) /* support "%track" script/section */
268  rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
269  if (!(child = fork())) {
270 
271  /*@-mods@*/
272  errno = 0;
273  /*@=mods@*/
274  (void) execvp(argv[0], (char *const *)argv);
275 
276  rpmlog(RPMLOG_ERR, _("Exec of %s failed (%s): %s\n"),
277  scriptName, name, strerror(errno));
278 
279  _exit(-1);
280  }
281 
282  pid = waitpid(child, &status, 0);
283 
284  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
285  rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
286  scriptName, name);
287  rc = RPMRC_FAIL;
288  } else
289  rc = RPMRC_OK;
290 
291 exit:
292  if (scriptName) {
293 #if defined(RPM_VENDOR_OPENPKG) /* always-remove-tempfiles */
294  /* Unconditionally remove temporary files ("rpm-tmp.XXXXX") which
295  were generated for the executed scripts. In OpenPKG we run the
296  scripts in debug mode ("set -x") anyway, so we never need to
297  see the whole generated script -- not even if it breaks. Instead
298  we would just have temporary files staying around forever. */
299 #else
300  if (rc == RPMRC_OK)
301 #endif
302  (void) Unlink(scriptName);
303  scriptName = _free(scriptName);
304  }
305  if (u != NULL) {
306  switch (u->urltype) {
307  case URL_IS_HTTPS:
308  case URL_IS_HTTP:
309  case URL_IS_FTP:
310 if (_build_debug)
311 fprintf(stderr, "*** delMacros\n");
312  delMacro(spec->macros, "_remsh");
313  delMacro(spec->macros, "_remhost");
314  if (strcmp(rootDir, "/"))
315  delMacro(spec->macros, "_remroot");
316  break;
317  case URL_IS_UNKNOWN:
318  case URL_IS_DASH:
319  case URL_IS_PATH:
320  case URL_IS_HKP:
321  default:
322  break;
323  }
324  }
325  argv = _free(argv);
326  buildCmd = _free(buildCmd);
327  buildTemplate = _free(buildTemplate);
328  buildPost = _free(buildPost);
329  buildDirURL = _free(buildDirURL);
330 
331  return rc;
332 }
333 
334 rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
335 {
336  rpmRC rc = RPMRC_OK;
337 
338  if (!spec->recursing && spec->BACount) {
339  int x;
340  /* When iterating over BANames, do the source */
341  /* packaging on the first run, and skip RMSOURCE altogether */
342  if (spec->BASpecs != NULL)
343  for (x = 0; x < spec->BACount; x++) {
344  if ((rc = buildSpec(ts, spec->BASpecs[x],
345  (what & ~RPMBUILD_RMSOURCE) |
346  (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
347  test))) {
348  goto exit;
349  }
350  }
351  } else {
352  /* support "%track" script/section */
353  if ((what & RPMBUILD_TRACK) &&
354  (rc = doScript(spec, RPMBUILD_TRACK, NULL, NULL, test)))
355  goto exit;
356 
357  if ((what & RPMBUILD_PREP) &&
358  (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
359  goto exit;
360 
361  if ((what & RPMBUILD_BUILD) &&
362  (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
363  goto exit;
364 
365  if ((what & RPMBUILD_INSTALL) &&
366  (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
367  goto exit;
368 
369  if ((what & RPMBUILD_CHECK) &&
370  (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
371  goto exit;
372 
373  if ((what & RPMBUILD_PACKAGESOURCE) &&
374  (rc = processSourceFiles(spec)))
375  goto exit;
376 
377  if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
378  (what & RPMBUILD_FILECHECK)) &&
379  (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
380  goto exit;
381 
382  if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
383  (rc = packageSources(spec)))
384  return rc;
385 
386  if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
387  (rc = packageBinaries(spec)))
388  goto exit;
389 
390  if ((what & RPMBUILD_CLEAN) &&
391  (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
392  goto exit;
393 
394  if ((what & RPMBUILD_RMBUILD) &&
395  (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
396  goto exit;
397  }
398 
399  if (what & RPMBUILD_RMSOURCE)
400  doRmSource(spec);
401 
402  if (what & RPMBUILD_RMSPEC)
403  (void) Unlink(spec->specFile);
404 
405 #if defined(RPM_VENDOR_OPENPKG) /* auto-remove-source-directories */
406  /* In OpenPKG we use per-package %{_sourcedir} and %{_specdir}
407  definitions (macros have trailing ".../%{name}"). On removal of
408  source(s) and .spec file, this per-package directory would be kept
409  (usually <prefix>/RPM/SRC/<name>/), because RPM does not know about
410  this OpenPKG convention. So, let RPM try(!) to remove the two
411  directories (if they are empty) and just ignore removal failures
412  (if they are still not empty). */
413  if (what & RPMBUILD_RMSOURCE) {
414  const char *pn;
415  pn = rpmGetPath("%{_sourcedir}", NULL);
416  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
417  pn = _free(pn);
418  }
419  if (what & RPMBUILD_RMSPEC) {
420  const char *pn;
421  pn = rpmGetPath("%{_specdir}", NULL);
422  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
423  pn = _free(pn);
424  }
425 #endif
426 
427 exit:
428  if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
429  rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
430  rpmlogPrint(NULL);
431  }
432 
433  return rc;
434 }