rpm  5.4.14
build.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #define _RPMBC_INTERNAL
9 #include <rpmio_internal.h> /* XXX fdGetFp */
10 #include <rpmcb.h>
11 #include <rpmsq.h>
12 
13 #define _RPMTAG_INTERNAL
14 #include <rpmbuild.h>
15 #include "signature.h" /* XXX rpmTempFile */
16 
17 #include "debug.h"
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  rpmop op = NULL;
107  int ix = -1;
108 
109  FD_t fd;
110  FD_t xfd;
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  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
120  ix = RPMSCRIPT_PREP;
121  mTemplate = "%{__spec_prep_template}";
122  mPost = "%{__spec_prep_post}";
123  mCmd = "%{__spec_prep_cmd}";
124  break;
125  case RPMBUILD_BUILD:
126  name = "%build";
127  iob = spec->build;
128  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
129  ix = RPMSCRIPT_BUILD;
130  mTemplate = "%{__spec_build_template}";
131  mPost = "%{__spec_build_post}";
132  mCmd = "%{__spec_build_cmd}";
133  break;
134  case RPMBUILD_INSTALL:
135  name = "%install";
136  iob = spec->install;
137  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
138  ix = RPMSCRIPT_INSTALL;
139  mTemplate = "%{__spec_install_template}";
140  mPost = "%{__spec_install_post}";
141  mCmd = "%{__spec_install_cmd}";
142  break;
143  case RPMBUILD_CHECK:
144  name = "%check";
145  iob = spec->check;
146  op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
147  ix = RPMSCRIPT_CHECK;
148  mTemplate = "%{__spec_check_template}";
149  mPost = "%{__spec_check_post}";
150  mCmd = "%{__spec_check_cmd}";
151  break;
152  case RPMBUILD_CLEAN:
153  name = "%clean";
154  iob = spec->clean;
155  mTemplate = "%{__spec_clean_template}";
156  mPost = "%{__spec_clean_post}";
157  mCmd = "%{__spec_clean_cmd}";
158  break;
159  case RPMBUILD_RMBUILD:
160  name = "--clean";
161  mTemplate = "%{__spec_clean_template}";
162  mPost = "%{__spec_clean_post}";
163  mCmd = "%{__spec_clean_cmd}";
164  break;
165  /* support "%track" script/section */
166  case RPMBUILD_TRACK:
167  name = "%track";
168  iob = NULL;
169  if (spec->foo)
170  for (i = 0; i < spec->nfoo; i++) {
171  if (spec->foo[i].str == NULL || spec->foo[i].iob == NULL)
172  continue;
173  if (xstrcasecmp(spec->foo[i].str, "track"))
174  continue;
175  iob = spec->foo[i].iob;
176  /*@loopbreak@*/ break;
177  }
178  mTemplate = "%{__spec_track_template}";
179  mPost = "%{__spec_track_post}";
180  mCmd = "%{__spec_track_cmd}";
181  break;
182  case RPMBUILD_STRINGBUF:
183  default:
184  mTemplate = "%{___build_template}";
185  mPost = "%{___build_post}";
186  mCmd = "%{___build_cmd}";
187  break;
188  }
189 
190 assert(name != NULL);
191 
192  if ((what != RPMBUILD_RMBUILD) && iob == NULL) {
193  rc = RPMRC_OK;
194  goto exit;
195  }
196 
197  if (rpmTempFile(rootURL, &scriptName, &fd) || fd == NULL || Ferror(fd)) {
198  rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
199  rc = RPMRC_FAIL;
200  goto exit;
201  }
202 
203  if (fdGetFp(fd) == NULL)
204  xfd = Fdopen(fd, "w.fpio");
205  else
206  xfd = fd;
207 
208  /*@-type@*/ /* FIX: cast? */
209  if ((fp = fdGetFp(xfd)) == NULL) {
210  rc = RPMRC_FAIL;
211  goto exit;
212  }
213  /*@=type@*/
214 
215  (void) urlPath(rootURL, &rootDir);
216  if (*rootDir == '\0') rootDir = "/";
217 
218  (void) urlPath(scriptName, &buildScript);
219 
220  buildTemplate = rpmExpand(mTemplate, NULL);
221  buildPost = rpmExpand(mPost, NULL);
222 
223  (void) fputs(buildTemplate, fp);
224 
225  /* support "%track" script/section */
226  if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir && what != RPMBUILD_TRACK)
227  fprintf(fp, "cd '%s'\n", spec->buildSubdir);
228 
229  if (what == RPMBUILD_RMBUILD) {
230  if (spec->buildSubdir)
231  fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
232  } else if (iob != NULL)
233  fprintf(fp, "%s", rpmiobStr(iob));
234 
235  (void) fputs(buildPost, fp);
236 
237  (void) Fclose(xfd);
238 
239  if (test) {
240  rc = RPMRC_OK;
241  goto exit;
242  }
243 
244  if (buildDirURL && buildDirURL[0] != '/' &&
245  (urlSplit(buildDirURL, &u) != 0)) {
246  rc = RPMRC_FAIL;
247  goto exit;
248  }
249 
250  switch (urlType(u)) {
251  case URL_IS_HTTPS:
252  case URL_IS_HTTP:
253  case URL_IS_FTP:
254  addMacro(spec->macros, "_remsh", NULL, "%{__remsh}", RMIL_SPEC);
255  addMacro(spec->macros, "_remhost", NULL, u->host, RMIL_SPEC);
256  if (strcmp(rootDir, "/"))
257  addMacro(spec->macros, "_remroot", NULL, rootDir, RMIL_SPEC);
258  break;
259  case URL_IS_UNKNOWN:
260  case URL_IS_DASH:
261  case URL_IS_PATH:
262  case URL_IS_HKP:
263  case URL_IS_MONGO: /* XXX FIXME */
264  default:
265  break;
266  }
267 
268  buildCmd = rpmExpand(mCmd, " ", buildScript, NULL);
269  (void) poptParseArgvString(buildCmd, &argc, &argv);
270 
271  if (what != RPMBUILD_TRACK) /* support "%track" script/section */
272  rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
273 
274  /* Run the script with a stopwatch. */
275  if (op != NULL)
276  (void) rpmswEnter(op, 0);
277 
278  status = rpmsqExecve(argv);
279  if (ix >= 0 && ix < RPMSCRIPT_MAX)
280  spec->sstates[ix] =
282 
283  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
284  rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
285  scriptName, name);
286  rc = RPMRC_FAIL;
287  } else
288  rc = RPMRC_OK;
289 
290  if (op != NULL) {
291  static unsigned int scale = 1000;
292  (void) rpmswExit(op, 0);
293  if (ix >= 0 && ix < RPMSCRIPT_MAX)
294  spec->smetrics[ix] += op->usecs / scale;
295  }
296 
297 exit:
298  if (scriptName) {
299 #if defined(RPM_VENDOR_OPENPKG) /* always-remove-tempfiles */
300  /* Unconditionally remove temporary files ("rpm-tmp.XXXXX") which
301  were generated for the executed scripts. In OpenPKG we run the
302  scripts in debug mode ("set -x") anyway, so we never need to
303  see the whole generated script -- not even if it breaks. Instead
304  we would just have temporary files staying around forever. */
305 #else
306  if (rc == RPMRC_OK)
307 #endif
308  (void) Unlink(scriptName);
309  scriptName = _free(scriptName);
310  }
311 
312  switch (urlType(u)) {
313  case URL_IS_HTTPS:
314  case URL_IS_HTTP:
315  case URL_IS_FTP:
316  delMacro(spec->macros, "_remsh");
317  delMacro(spec->macros, "_remhost");
318  if (strcmp(rootDir, "/"))
319  delMacro(spec->macros, "_remroot");
320  break;
321  case URL_IS_UNKNOWN:
322  case URL_IS_DASH:
323  case URL_IS_PATH:
324  case URL_IS_HKP:
325  case URL_IS_MONGO: /* XXX FIXME */
326  default:
327  break;
328  }
329 
330  argv = _free(argv);
331  buildCmd = _free(buildCmd);
332  buildTemplate = _free(buildTemplate);
333  buildPost = _free(buildPost);
334  buildDirURL = _free(buildDirURL);
335  return rc;
336 }
337 
338 rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
339 {
340  rpmRC rc = RPMRC_OK;
341 
342  /* Generate a keypair lazily. */
343  if (spec->dig == NULL)
345 
346  if (!spec->recursing && spec->BACount) {
347  int x;
348  /* When iterating over BANames, do the source */
349  /* packaging on the first run, and skip RMSOURCE altogether */
350  if (spec->BASpecs != NULL)
351  for (x = 0; x < spec->BACount; x++) {
352  if ((rc = buildSpec(ts, spec->BASpecs[x],
353  (what & ~RPMBUILD_RMSOURCE) |
354  (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
355  test))) {
356  goto exit;
357  }
358  }
359  } else {
360  /* support "%track" script/section */
361  if ((what & RPMBUILD_TRACK) &&
362  (rc = doScript(spec, RPMBUILD_TRACK, NULL, NULL, test)))
363  goto exit;
364 
365  if ((what & RPMBUILD_PREP) &&
366  (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
367  goto exit;
368 
369  if ((what & RPMBUILD_BUILD) &&
370  (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
371  goto exit;
372 
373  if ((what & RPMBUILD_INSTALL) &&
374  (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
375  goto exit;
376 
377  if ((what & RPMBUILD_CHECK) &&
378  (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
379  goto exit;
380 
381  if ((what & RPMBUILD_PACKAGESOURCE) &&
382  (rc = processSourceFiles(spec)))
383  goto exit;
384 
385  if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
386  (what & RPMBUILD_FILECHECK)) &&
387  (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
388  goto exit;
389 
390  if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
391  (rc = packageSources(spec)))
392  return rc;
393 
394  if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
395  (rc = packageBinaries(spec)))
396  goto exit;
397 
398  if ((what & RPMBUILD_CLEAN) &&
399  (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
400  goto exit;
401 
402  if ((what & RPMBUILD_RMBUILD) &&
403  (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
404  goto exit;
405  }
406 
407  if (what & RPMBUILD_RMSOURCE)
408  doRmSource(spec);
409 
410  if (what & RPMBUILD_RMSPEC)
411  (void) Unlink(spec->specFile);
412 
413 #if defined(RPM_VENDOR_OPENPKG) /* auto-remove-source-directories */
414  /* In OpenPKG we use per-package %{_sourcedir} and %{_specdir}
415  definitions (macros have trailing ".../%{name}"). On removal of
416  source(s) and .spec file, this per-package directory would be kept
417  (usually <prefix>/RPM/SRC/<name>/), because RPM does not know about
418  this OpenPKG convention. So, let RPM try(!) to remove the two
419  directories (if they are empty) and just ignore removal failures
420  (if they are still not empty). */
421  if (what & RPMBUILD_RMSOURCE) {
422  const char *pn;
423  pn = rpmGetPath("%{_sourcedir}", NULL);
424  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
425  pn = _free(pn);
426  }
427  if (what & RPMBUILD_RMSPEC) {
428  const char *pn;
429  pn = rpmGetPath("%{_specdir}", NULL);
430  Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
431  pn = _free(pn);
432  }
433 #endif
434 
435 exit:
436  if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
437  rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
438  rpmlogPrint(NULL);
439  }
440 
441  return rc;
442 }
const char * getSourceDir(rpmfileAttrs attr)
Return the macro directory location from source file flags.
Definition: build.c:24
rpmiob build
Definition: rpmspec.h:188
rpmRC doScript(Spec spec, int what, const char *name, rpmiob iob, int test)
Run a build script, assembled from spec file scriptlet section.
Definition: build.c:89
rpmlog(RPMLOG_ERR,"%s\n", buf)
rpmiob clean
Definition: rpmspec.h:194
rpmtime_t usecs
Definition: rpmsw.h:43
URL control structure.
Definition: rpmurl.h:52
const char * rootURL
Definition: rpmspec.h:120
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3371
const char * specFile
Definition: rpmspec.h:116
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
int rc
Definition: poptALL.c:670
urltype urlType(void *_u)
Definition: url.c:424
rpmiob check
Definition: rpmspec.h:192
void addMacro(MacroContext mc, const char *n, const char *o, const char *b, int level)
Add macro to context.
Definition: macro.c:2722
struct Source * sources
Definition: rpmspec.h:162
int processSourceFiles(Spec spec)
Post-build processing for source package.
Definition: files.c:2751
const char * host
Definition: rpmurl.h:63
argv
Definition: rpmmtree.c:3679
struct Source * next
Definition: rpmspec.h:52
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:60
static void doRmSource(Spec spec)
Definition: build.c:59
rpmiob prep
Definition: rpmspec.h:186
delMacro(mc, n)
const char * source
Definition: rpmspec.h:48
Definition: rpmspec.h:44
rpmRC packageBinaries(Spec spec)
Generate binary package(s).
Definition: pack.c:1156
char * alloca()
pgpDig pgpDigNew(pgpVSFlags vsflags, pgpPubkeyAlgo pubkey_algo)
Create a container for parsed OpenPGP packates.
Definition: rpmpgp.c:1205
enum rpmRC_e rpmRC
RPM return codes.
Definition: signature.c:616
goto exit
Definition: db3.c:1903
memset(_r, 0, sizeof(*_r))
assert(key->size==sizeof(hdrNum))
int ix
Definition: rpmps-py.c:174
int Rmdir(const char *path)
rmdir(2) clone.
Definition: rpmrpc.c:141
int recursing
Definition: rpmspec.h:149
fprintf(stderr,"--> %s(%p,%p,%p) sig %p sigp %p\n", __FUNCTION__, dig, t, rsactx, sig, sigp)
int rpmlogGetNrecs(void)
Return number of messages.
Definition: rpmlog.c:23
int rpmTempFile(const char *prefix, const char **fnptr, void *fdptr)
Return file handle for a temporaray file.
Definition: signature.c:30
MacroContext macros
Definition: rpmspec.h:177
void rpmswExit(op, 0)
rpmuint32_t sstates[RPMSCRIPT_MAX]
Definition: rpmspec.h:182
rpmRC processBinaryFiles(Spec spec, int installSpecialDoc, int test)
Post-build processing for binary package(s).
Definition: files.c:3174
rpmuint32_t smetrics[RPMSCRIPT_MAX]
Definition: rpmspec.h:183
The FD_t File Handle data structure.
const char * rpmGenPath(const char *urlroot, const char *urlmdir, const char *urlfile)
Merge 3 args into path, any or all of which may be a url.
Definition: macro.c:3417
Generate and verify rpm package signatures.
The structure used to store values parsed from a spec file.
Definition: rpmspec.h:113
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3178
const char * buildSubdir
Definition: rpmspec.h:118
* op
Definition: rpmps-py.c:266
size_t nfoo
Definition: rpmspec.h:198
node fd
Definition: rpmfd-py.c:124
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2532
Cumulative statistics for an operation.
Definition: rpmsw.h:39
enum rpmfileAttrs_e rpmfileAttrs
File Attributes.
int BACount
Definition: rpmspec.h:148
fts u
Definition: rpmmtree.c:3828
#define RMIL_SPEC
Definition: rpmmacro.h:61
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2942
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:112
int urlSplit(const char *url, urlinfo *uret)
Parse URL string into a control structure.
Definition: url.c:476
return strcmp(ame->name, bme->name)
Spec * BASpecs
Definition: rpmspec.h:145
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
This is the only module users of librpmbuild should need to include.
int xstrcasecmp(const char *s1, const char *s2)
Locale insensitive strcasecmp(3).
Definition: strcasecmp.c:9
rpmRC packageSources(Spec spec)
Generate source package.
Definition: pack.c:1308
FD_t Fdopen(FD_t ofd, const char *fmode)
Definition: rpmio.c:2716
#define F_OK
Definition: system.h:231
static void * fdGetFp(FD_t fd)
return NULL
Definition: poptALL.c:613
int rpmsqExecve(const char **argv)
Execute a command, returning its status.
void rpmlogPrint(FILE *f)
Print all rpmError() messages.
Definition: rpmlog.c:53
static void
Print copy of spec file, filling in Group/Description/Summary from specspo.
Definition: spec.c:737
static const char * name
#define _(Text)
Definition: system.h:29
rpmiob install
Definition: rpmspec.h:190
status
Definition: rpmsq.c:792
void rpmswEnter(op, 0)
tagStore_t foo
Definition: rpmspec.h:200
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
int i
Definition: spec.c:743
void * dig
Definition: rpmspec.h:202
int flags
Definition: rpmspec.h:49
size_t fn
Definition: macro.c:1698
rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
Build stages state machine driver.
Definition: build.c:338
Spec spec
Definition: spec-py.c:121
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397