63f1e330748eba6f4770a3489ce0d45e74c6de21
[platform/upstream/rpm.git] / rpmbuild.c
1 #include "system.h"
2 const char *__progname;
3
4 #define _AUTOHELP
5
6 #include <sys/wait.h>
7 #if HAVE_MCHECK_H
8 #include <mcheck.h>
9 #endif
10
11 #include <rpm/rpmcli.h>
12 #include <rpm/rpmlib.h>                 /* RPMSIGTAG, rpmReadPackageFile .. */
13 #include <rpm/rpmbuild.h>
14 #include <rpm/rpmlog.h>
15 #include <rpm/rpmfileutil.h>
16 #include <rpm/rpmdb.h>
17 #include <rpm/rpmps.h>
18 #include <rpm/rpmts.h>
19 #include "lib/signature.h"
20 #include "build.h"
21
22 #include "debug.h"
23
24 enum modes {
25     MODE_BUILD          = (1 <<  4),
26     MODE_REBUILD        = (1 <<  5),
27     MODE_RECOMPILE      = (1 <<  8),
28     MODE_TARBUILD       = (1 << 11),
29 #define MODES_BT (MODE_BUILD | MODE_TARBUILD | MODE_REBUILD | MODE_RECOMPILE)
30
31     MODE_UNKNOWN        = 0
32 };
33
34 #define MODES_FOR_DBPATH        (MODES_BT)
35 #define MODES_FOR_NODEPS        (MODES_BT)
36 #define MODES_FOR_TEST          (MODES_BT)
37 #define MODES_FOR_ROOT          (MODES_BT)
38
39 static int quiet;
40
41 /* the structure describing the options we take and the defaults */
42 static struct poptOption optionsTable[] = {
43
44  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
45         N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
46         NULL },
47
48  { "quiet", '\0', 0, &quiet, 0,                 NULL, NULL},
49
50  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
51         N_("Common options for all rpm modes and executables:"),
52         NULL },
53
54    POPT_AUTOALIAS
55    POPT_AUTOHELP
56    POPT_TABLEEND
57 };
58
59 #ifdef __MINT__
60 /* MiNT cannot dynamically increase the stack.  */
61 long _stksize = 64 * 1024L;
62 #endif
63
64 RPM_GNUC_NORETURN
65 static void argerror(const char * desc)
66 {
67     fprintf(stderr, _("%s: %s\n"), __progname, desc);
68     exit(EXIT_FAILURE);
69 }
70
71 static void printVersion(FILE * fp)
72 {
73     fprintf(fp, _("RPM version %s\n"), rpmEVR);
74 }
75
76 static void printBanner(FILE * fp)
77 {
78     fprintf(fp, _("Copyright (C) 1998-2002 - Red Hat, Inc.\n"));
79     fprintf(fp, _("This program may be freely redistributed under the terms of the GNU GPL\n"));
80 }
81
82 static void printUsage(poptContext con, FILE * fp, int flags)
83 {
84     printVersion(fp);
85     printBanner(fp);
86     fprintf(fp, "\n");
87
88     if (rpmIsVerbose())
89         poptPrintHelp(con, fp, flags);
90     else
91         poptPrintUsage(con, fp, flags);
92 }
93
94 int main(int argc, char *argv[])
95 {
96     rpmts ts = NULL;
97     enum modes bigMode = MODE_UNKNOWN;
98     BTA_t ba = &rpmBTArgs;
99     char * passPhrase = "";
100
101     int arg;
102     const char *optArg, *poptCtx;
103     pid_t pipeChild = 0;
104     poptContext optCon;
105     int ec = 0;
106     int status;
107     int p[2];
108         
109 #if HAVE_MCHECK_H && HAVE_MTRACE
110     mtrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
111 #endif
112     setprogname(argv[0]);       /* Retrofit glibc __progname */
113
114     /* XXX glibc churn sanity */
115     if (__progname == NULL) {
116         if ((__progname = strrchr(argv[0], '/')) != NULL) __progname++;
117         else __progname = argv[0];
118     }
119
120     /* Set the major mode based on argv[0] */
121     if (rstreq(__progname, "rpmbuild")) bigMode = MODE_BUILD;
122
123 #if defined(ENABLE_NLS)
124     /* set up the correct locale */
125     (void) setlocale(LC_ALL, "" );
126
127     bindtextdomain(PACKAGE, LOCALEDIR);
128     textdomain(PACKAGE);
129 #endif
130
131     rpmSetVerbosity(RPMLOG_NOTICE);     /* XXX silly use by showrc */
132
133     /* Only build has it's own set of aliases, everything else uses rpm */
134     poptCtx = "rpmbuild";
135
136     /* Make a first pass through the arguments, looking for --rcfile */
137     /* We need to handle that before dealing with the rest of the arguments. */
138     /* XXX popt argv definition should be fixed instead of casting... */
139     optCon = poptGetContext(poptCtx, argc, (const char **)argv, optionsTable, 0);
140     {
141         char *poptfile = rpmGenPath(rpmConfigDir(), LIBRPMALIAS_FILENAME, NULL);
142         (void) poptReadConfigFile(optCon, poptfile);
143         free(poptfile);
144     }
145     (void) poptReadDefaultConfig(optCon, 1);
146     poptSetExecPath(optCon, rpmConfigDir(), 1);
147
148     while ((arg = poptGetNextOpt(optCon)) > 0) {
149         optArg = poptGetOptArg(optCon);
150
151         switch (arg) {
152         default:
153             fprintf(stderr, _("Internal error in argument processing (%d) :-(\n"), arg);
154             exit(EXIT_FAILURE);
155         }
156     }
157
158     if (arg < -1) {
159         fprintf(stderr, "%s: %s\n", 
160                 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
161                 poptStrerror(arg));
162         exit(EXIT_FAILURE);
163     }
164
165     rpmcliConfigured();
166
167     switch (ba->buildMode) {
168     case 'b':   bigMode = MODE_BUILD;           break;
169     case 't':   bigMode = MODE_TARBUILD;        break;
170     case 'B':   bigMode = MODE_REBUILD;         break;
171     case 'C':   bigMode = MODE_RECOMPILE;       break;
172     }
173
174     if ((ba->buildAmount & RPMBUILD_RMSOURCE) && bigMode == MODE_UNKNOWN)
175         bigMode = MODE_BUILD;
176
177     if ((ba->buildAmount & RPMBUILD_RMSPEC) && bigMode == MODE_UNKNOWN)
178         bigMode = MODE_BUILD;
179
180     if (ba->buildRootOverride && bigMode != MODE_BUILD &&
181         bigMode != MODE_REBUILD && bigMode != MODE_TARBUILD) {
182         argerror("--buildroot may only be used during package builds");
183     }
184     
185     if (rpmcliRootDir && rpmcliRootDir[1] && (bigMode & ~MODES_FOR_ROOT))
186         argerror(_("--root (-r) may only be specified during "
187                  "installation, erasure, querying, and "
188                  "database rebuilds"));
189
190     if (rpmcliRootDir) {
191         switch (urlIsURL(rpmcliRootDir)) {
192         default:
193             if (bigMode & MODES_FOR_ROOT)
194                 break;
195         case URL_IS_UNKNOWN:
196             if (rpmcliRootDir[0] != '/')
197                 argerror(_("arguments to --root (-r) must begin with a /"));
198             break;
199         }
200     }
201
202     if (quiet)
203         rpmSetVerbosity(RPMLOG_WARNING);
204
205     if (ba->sign) {
206         if (bigMode == MODE_REBUILD || bigMode == MODE_BUILD ||
207             bigMode == MODE_TARBUILD)
208         {
209             const char ** av;
210             struct stat sb;
211             int errors = 0;
212
213             if ((av = poptGetArgs(optCon)) == NULL) {
214                 fprintf(stderr, _("no files to sign\n"));
215                 errors++;
216             } else
217             while (*av) {
218                 if (stat(*av, &sb)) {
219                     fprintf(stderr, _("cannot access file %s\n"), *av);
220                     errors++;
221                 }
222                 av++;
223             }
224
225             if (errors) {
226                 ec = errors;
227                 goto exit;
228             }
229
230             if (poptPeekArg(optCon)) {
231                 int sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY);
232                 switch (sigTag) {
233                   case 0:
234                     break;
235                   case RPMSIGTAG_PGP:
236                   case RPMSIGTAG_GPG:
237                   case RPMSIGTAG_DSA:
238                   case RPMSIGTAG_RSA:
239                     passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
240                     if (passPhrase == NULL) {
241                         fprintf(stderr, _("Pass phrase check failed\n"));
242                         ec = EXIT_FAILURE;
243                         goto exit;
244                     }
245                     fprintf(stderr, _("Pass phrase is good.\n"));
246                     passPhrase = xstrdup(passPhrase);
247                     break;
248                   default:
249                     fprintf(stderr,
250                             _("Invalid %%_signature spec in macro file.\n"));
251                     ec = EXIT_FAILURE;
252                     goto exit;
253                     break;
254                 }
255             }
256         } else {
257             argerror(_("--sign may only be used during package building"));
258         }
259     } else {
260         /* Make rpmLookupSignatureType() return 0 ("none") from now on */
261         (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
262     }
263
264     if (rpmcliPipeOutput) {
265         if (pipe(p) < 0) {
266             fprintf(stderr, _("creating a pipe for --pipe failed: %m\n"));
267             goto exit;
268         }
269
270         if (!(pipeChild = fork())) {
271             (void) signal(SIGPIPE, SIG_DFL);
272             (void) close(p[1]);
273             (void) dup2(p[0], STDIN_FILENO);
274             (void) close(p[0]);
275             (void) execl("/bin/sh", "/bin/sh", "-c", rpmcliPipeOutput, NULL);
276             fprintf(stderr, _("exec failed\n"));
277         }
278
279         (void) close(p[0]);
280         (void) dup2(p[1], STDOUT_FILENO);
281         (void) close(p[1]);
282     }
283         
284     ts = rpmtsCreate();
285     (void) rpmtsSetRootDir(ts, rpmcliRootDir);
286     switch (bigMode) {
287     case MODE_REBUILD:
288     case MODE_RECOMPILE:
289     {   const char * pkg;
290
291         while (!rpmIsVerbose())
292             rpmIncreaseVerbosity();
293
294         if (!poptPeekArg(optCon))
295             argerror(_("no packages files given for rebuild"));
296
297         ba->buildAmount =
298             RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | RPMBUILD_CHECK;
299         if (bigMode == MODE_REBUILD) {
300             ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
301             ba->buildAmount |= RPMBUILD_RMSOURCE;
302             ba->buildAmount |= RPMBUILD_RMSPEC;
303             ba->buildAmount |= RPMBUILD_CLEAN;
304             ba->buildAmount |= RPMBUILD_RMBUILD;
305         }
306
307         while ((pkg = poptGetArg(optCon))) {
308             char * specFile = NULL;
309
310             ba->cookie = NULL;
311             ec = rpmInstallSource(ts, pkg, &specFile, &ba->cookie);
312             if (ec == 0) {
313                 ba->rootdir = rpmcliRootDir;
314                 ba->passPhrase = passPhrase;
315                 ec = build(ts, specFile, ba, rpmcliRcfile);
316             }
317             ba->cookie = _free(ba->cookie);
318             specFile = _free(specFile);
319
320             if (ec)
321                 break;
322         }
323
324     }   break;
325
326     case MODE_BUILD:
327     case MODE_TARBUILD:
328     {   const char * pkg;
329         if (!quiet) while (!rpmIsVerbose())
330             rpmIncreaseVerbosity();
331        
332         switch (ba->buildChar) {
333         case 'a':
334             ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
335         case 'b':
336             ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
337             ba->buildAmount |= RPMBUILD_CLEAN;
338             if ((ba->buildChar == 'b') && ba->shortCircuit)
339                 break;
340         case 'i':
341             ba->buildAmount |= RPMBUILD_INSTALL;
342             ba->buildAmount |= RPMBUILD_CHECK;
343             if ((ba->buildChar == 'i') && ba->shortCircuit)
344                 break;
345         case 'c':
346             ba->buildAmount |= RPMBUILD_BUILD;
347             if ((ba->buildChar == 'c') && ba->shortCircuit)
348                 break;
349         case 'p':
350             ba->buildAmount |= RPMBUILD_PREP;
351             break;
352             
353         case 'l':
354             ba->buildAmount |= RPMBUILD_FILECHECK;
355             break;
356         case 's':
357             ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
358             break;
359         }
360
361         if (!poptPeekArg(optCon)) {
362             if (bigMode == MODE_BUILD)
363                 argerror(_("no spec files given for build"));
364             else
365                 argerror(_("no tar files given for build"));
366         }
367
368         while ((pkg = poptGetArg(optCon))) {
369             ba->rootdir = rpmcliRootDir;
370             ba->passPhrase = passPhrase;
371             ba->cookie = NULL;
372             ec = build(ts, pkg, ba, rpmcliRcfile);
373             if (ec)
374                 break;
375             rpmFreeMacros(NULL);
376             (void) rpmReadConfigFiles(rpmcliRcfile, NULL);
377         }
378     }   break;
379
380     case MODE_UNKNOWN:
381         if (poptPeekArg(optCon) != NULL || argc <= 1 || rpmIsVerbose()) {
382             printUsage(optCon, stderr, 0);
383             ec = argc;
384         }
385         break;
386     }
387
388 exit:
389
390     ts = rpmtsFree(ts);
391
392     optCon = poptFreeContext(optCon);
393     rpmFreeMacros(NULL);
394         rpmFreeMacros(rpmCLIMacroContext);
395     rpmFreeRpmrc();
396
397     if (pipeChild) {
398         (void) fclose(stdout);
399         (void) waitpid(pipeChild, &status, 0);
400     }
401
402     /* keeps memory leak checkers quiet */
403     rpmlogClose();
404
405     freeNames();
406     ba->buildRootOverride = _free(ba->buildRootOverride);
407     ba->targets = _free(ba->targets);
408
409 #if HAVE_MCHECK_H && HAVE_MTRACE
410     muntrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
411 #endif
412
413     /* XXX Avoid exit status overflow. Status 255 is special to xargs(1) */
414     if (ec > 254) ec = 254;
415
416     return ec;
417 }