lclint annotations and compiler cruft.
[platform/upstream/rpm.git] / build.c
1 #include "system.h"
2
3 #include "rpmbuild.h"
4 #include "build.h"
5 #include "install.h"
6
7 static int checkSpec(Header h)
8 {
9     char *rootdir = NULL;
10     rpmdb db = NULL;
11     int mode = O_RDONLY;
12     rpmTransactionSet ts;
13     struct rpmDependencyConflict * conflicts;
14     int numConflicts;
15     int rc;
16
17     if (!headerIsEntry(h, RPMTAG_REQUIREFLAGS))
18         return 0;
19
20     if (rpmdbOpen(rootdir, &db, mode, 0644)) {
21         const char *dn;
22         dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
23         rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
24         xfree(dn);
25         exit(EXIT_FAILURE);
26     }
27     ts = rpmtransCreateSet(db, rootdir);
28
29     rc = rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
30
31     rc = rpmdepCheck(ts, &conflicts, &numConflicts);
32     if (rc == 0 && conflicts) {
33         rpmMessage(RPMMESS_ERROR, _("failed build dependencies:\n"));
34         printDepProblems(stderr, conflicts, numConflicts);
35         rpmdepFreeConflicts(conflicts, numConflicts);
36         rc = 1;
37     }
38
39     if (ts)
40         rpmtransFree(ts);
41     if (db)
42         rpmdbClose(db);
43
44     return rc;
45 }
46
47 /*
48  * Kurwa, durni ameryka?ce sobe zawsze my?l?, ?e ca?y ?wiat mówi po
49  * angielsku...
50  */
51 /* XXX this is still a dumb test but at least it's i18n aware */
52 static int isSpecFile(const char *specfile)
53 {
54     char buf[256];
55     const char * s;
56     FD_t fd;
57     int count;
58     int checking;
59
60     if (fdFileno((fd = fdOpen(specfile, O_RDONLY, 0))) < 0) {
61         fprintf(stderr, _("Unable to open spec file: %s\n"), specfile);
62         return 0;
63     }
64     count = fdRead(fd, buf, sizeof(buf));
65     fdClose(fd);
66
67     checking = 1;
68     for (s = buf; count--; s++) {
69         switch (*s) {
70         case '\r':
71         case '\n':
72             checking = 1;
73             break;
74         case ':':
75             checking = 0;
76             break;
77         default:
78             if (checking && !(isprint(*s) || isspace(*s))) return 0;
79             break;
80         }
81     }
82     return 1;
83 }
84
85 static int buildForTarget(const char *arg, struct rpmBuildArguments *ba,
86         const char *passPhrase, int fromTarball, char *cookie,
87         int force, int nodeps)
88 {
89     int buildAmount = ba->buildAmount;
90     const char *buildRoot = ba->buildRootOverride;
91     int test = ba->noBuild;
92     FILE *f;
93     const char * specfile;
94     int res = 0;
95     struct stat statbuf;
96     char buf[BUFSIZ];
97     Spec spec = NULL;
98
99     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
100
101     if (fromTarball) {
102         const char *specDir;
103         const char * tmpSpecFile;
104         char * cmd, *s;
105
106         specDir = rpmGetPath("%{_specdir}", NULL);
107
108         {   char tfn[64];
109             strcpy(tfn, "rpm-spec.XXXXXX");
110             tmpSpecFile = rpmGetPath("%{_specdir}/", mktemp(tfn), NULL);
111         }
112
113         cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
114         sprintf(cmd, "gunzip < %s | tar xOvf - Specfile 2>&1 > %s",
115                         arg, tmpSpecFile);
116         if (!(f = popen(cmd, "r"))) {
117             fprintf(stderr, _("Failed to open tar pipe: %s\n"), 
118                         strerror(errno));
119             xfree(specDir);
120             xfree(tmpSpecFile);
121             return 1;
122         }
123         if ((!fgets(buf, sizeof(buf) - 1, f)) || !strchr(buf, '/')) {
124             /* Try again */
125             pclose(f);
126
127             sprintf(cmd, "gunzip < %s | tar xOvf - \\*.spec 2>&1 > %s", arg,
128                     tmpSpecFile);
129             if (!(f = popen(cmd, "r"))) {
130                 fprintf(stderr, _("Failed to open tar pipe: %s\n"), 
131                         strerror(errno));
132                 xfree(specDir);
133                 xfree(tmpSpecFile);
134                 return 1;
135             }
136             if (!fgets(buf, sizeof(buf) - 1, f)) {
137                 /* Give up */
138                 fprintf(stderr, _("Failed to read spec file from %s\n"), arg);
139                 unlink(tmpSpecFile);
140                 xfree(specDir);
141                 xfree(tmpSpecFile);
142                 return 1;
143             }
144         }
145         pclose(f);
146
147         cmd = s = buf;
148         while (*cmd) {
149             if (*cmd == '/') s = cmd + 1;
150             cmd++;
151         }
152
153         cmd = s;
154
155         /* remove trailing \n */
156         s = cmd + strlen(cmd) - 1;
157         *s = '\0';
158
159         s = alloca(strlen(specDir) + strlen(cmd) + 5);
160         sprintf(s, "%s/%s", specDir, cmd);
161         
162         if (rename(tmpSpecFile, s)) {
163             fprintf(stderr, _("Failed to rename %s to %s: %s\n"),
164                     tmpSpecFile, s, strerror(errno));
165             unlink(tmpSpecFile);
166             xfree(specDir);
167             xfree(tmpSpecFile);
168             return 1;
169         }
170
171         /* Make the directory which contains the tarball the source 
172            directory for this run */
173
174         if (*arg != '/') {
175             (void)getcwd(buf, BUFSIZ);
176             strcat(buf, "/");
177             strcat(buf, arg);
178         } else 
179             strcpy(buf, arg);
180
181         cmd = buf + strlen(buf) - 1;
182         while (*cmd != '/') cmd--;
183         *cmd = '\0';
184
185         addMacro(NULL, "_sourcedir", NULL, buf, RMIL_TARBALL);
186         xfree(specDir);
187         xfree(tmpSpecFile);
188         specfile = s;
189     } else if (arg[0] == '/') {
190         specfile = arg;
191     } else {
192         char *s = alloca(BUFSIZ);
193         (void)getcwd(s, BUFSIZ);
194         strcat(s, "/");
195         strcat(s, arg);
196         specfile = s;
197     }
198
199     stat(specfile, &statbuf);
200     if (! S_ISREG(statbuf.st_mode)) {
201         fprintf(stderr, _("File is not a regular file: %s\n"), specfile);
202         return 1;
203     }
204
205     /* Try to verify that the file is actually a specfile */
206     if (!isSpecFile(specfile)) {
207         fprintf(stderr, _("File %s does not appear to be a specfile.\n"),
208                 specfile);
209         return 1;
210     }
211     
212     /* Parse the spec file */
213 #define _anyarch(_f)    \
214 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
215     if (parseSpec(&spec, specfile, buildRoot, 0, passPhrase, cookie,
216         _anyarch(buildAmount), force)) {
217             return 1;
218     }
219 #undef  _anyarch
220
221     /* Assemble source header from parsed components */
222     initSourceHeader(spec);
223
224     /* Check build prerequisites */
225     if (!nodeps && checkSpec(spec->sourceHeader)) {
226         freeSpec(spec);
227         return 1;
228     }
229
230     if (buildSpec(spec, buildAmount, test)) {
231         freeSpec(spec);
232         return 1;
233     }
234     
235     if (fromTarball) unlink(specfile);
236
237     freeSpec(spec);
238     
239     return res;
240 }
241
242 int build(const char *arg, struct rpmBuildArguments *ba, const char *passPhrase,
243           int fromTarball, char *cookie, const char * rcfile, int force,
244           int nodeps)
245 {
246     char *t, *te;
247     int rc;
248     char *targets = ba->targets;
249
250     if (targets == NULL) {
251         rc =  buildForTarget(arg, ba, passPhrase, fromTarball, cookie,
252                 force, nodeps);
253         return rc;
254     }
255
256     /* parse up the build operators */
257
258     printf(_("Building target platforms: %s\n"), targets);
259
260     for (t = targets; *t != '\0'; t = te) {
261         char *target;
262         if ((te = strchr(t, ',')) == NULL)
263             te = t + strlen(t);
264         target = alloca(te-t+1);
265         strncpy(target, t, (te-t));
266         target[te-t] = '\0';
267         printf(_("Building for target %s\n"), target);
268
269         rpmReadConfigFiles(rcfile, target);
270         rc = buildForTarget(arg, ba, passPhrase, fromTarball, cookie,
271                 force, nodeps);
272         if (rc)
273             return rc;
274
275         freeMacros(NULL);
276     }
277
278     return 0;
279 }
280
281 #define POPT_USECATALOG         1000
282 #define POPT_NOLANG             1001
283 #define POPT_RMSOURCE           1002
284 #define POPT_RMBUILD            1003
285 #define POPT_BUILDROOT          1004
286 #define POPT_BUILDARCH          1005
287 #define POPT_BUILDOS            1006
288 #define POPT_TARGETPLATFORM     1007
289 #define POPT_NOBUILD            1008
290 #define POPT_SHORTCIRCUIT       1009
291 #define POPT_RMSPEC             1010
292
293 extern int noLang;
294 static int noBuild = 0;
295 static int useCatalog = 0;
296
297 static void buildArgCallback( /*@unused@*/ poptContext con,
298         /*@unused@*/ enum poptCallbackReason reason,
299         const struct poptOption * opt, const char * arg, const void * data)
300 {
301     struct rpmBuildArguments * rba = (struct rpmBuildArguments *) data;
302
303     switch (opt->val) {
304     case POPT_USECATALOG: rba->useCatalog = 1; break;
305     case POPT_NOBUILD: rba->noBuild = 1; break;
306     case POPT_NOLANG: rba->noLang = 1; break;
307     case POPT_SHORTCIRCUIT: rba->shortCircuit = 1; break;
308     case POPT_RMSOURCE: rba->buildAmount |= RPMBUILD_RMSOURCE; break;
309     case POPT_RMSPEC: rba->buildAmount |= RPMBUILD_RMSPEC; break;
310     case POPT_RMBUILD: rba->buildAmount |= RPMBUILD_RMBUILD; break;
311     case POPT_BUILDROOT:
312         if (rba->buildRootOverride) {
313             fprintf(stderr, _("buildroot already specified"));
314             exit(EXIT_FAILURE);
315             /*@notreached@*/
316         }
317         rba->buildRootOverride = xstrdup(arg);
318         break;
319     case POPT_BUILDARCH:
320         fprintf(stderr, _("--buildarch has been obsoleted.  Use the --target option instead.\n")); 
321         exit(EXIT_FAILURE);
322         /*@notreached@*/ break;
323     case POPT_BUILDOS:
324         fprintf(stderr, _("--buildos has been obsoleted.  Use the --target option instead.\n")); 
325         exit(EXIT_FAILURE);
326         /*@notreached@*/ break;
327     case POPT_TARGETPLATFORM:
328         if (rba->targets) {
329             int len = strlen(rba->targets) + strlen(arg) + 2;
330             rba->targets = xrealloc(rba->targets, len);
331             strcat(rba->targets, ",");
332         } else {
333             rba->targets = xmalloc(strlen(arg) + 1);
334             rba->targets[0] = '\0';
335         }
336         strcat(rba->targets, arg);
337         break;
338     }
339 }
340
341 struct poptOption rpmBuildPoptTable[] = {
342         { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
343                 buildArgCallback, 0, NULL, NULL },
344         { "buildarch", '\0', POPT_ARG_STRING, 0,  POPT_BUILDARCH,
345                 N_("override build architecture"), "ARCH" },
346         { "buildos", '\0', POPT_ARG_STRING, 0,  POPT_BUILDOS,
347                 N_("override build operating system"), "OS" },
348         { "buildroot", '\0', POPT_ARG_STRING, 0,  POPT_BUILDROOT,
349                 N_("override build root"), "DIRECTORY" },
350         { "clean", '\0', 0, 0, POPT_RMBUILD,
351                 N_("remove build tree when done"), NULL},
352         { "nobuild", '\0', 0, &noBuild,  POPT_NOBUILD,
353                 N_("do not execute any stages of the build"), NULL },
354         { "nolang", '\0', 0, &noLang, POPT_NOLANG,
355                 N_("do not accept I18N msgstr's from specfile"), NULL},
356         { "rmsource", '\0', 0, 0, POPT_RMSOURCE,
357                 N_("remove sources when done"), NULL},
358         { "rmspec", '\0', 0, 0, POPT_RMSPEC,
359                 N_("remove specfile when done"), NULL},
360         { "short-circuit", '\0', 0, 0,  POPT_SHORTCIRCUIT,
361                 N_("skip straight to specified stage (only for c,i)"), NULL },
362         { "target", '\0', POPT_ARG_STRING, 0,  POPT_TARGETPLATFORM,
363                 N_("override target platform"), "CPU-VENDOR-OS" },
364         { "usecatalog", '\0', 0, &useCatalog, POPT_USECATALOG,
365                 N_("lookup I18N strings in specfile catalog"), NULL},
366         { 0, 0, 0, 0, 0,        NULL, NULL }
367 };