Log message adjustments
[platform/upstream/rpm.git] / lib / rpminstall.c
1 /** \ingroup rpmcli
2  * \file lib/rpminstall.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/rpmcli.h>
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmlib.h>         /* rpmReadPackageFile, vercmp etc */
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmds.h>
12 #include <rpm/rpmts.h>
13 #include <rpm/rpmlog.h>
14 #include <rpm/rpmfileutil.h>
15 #include <rpm/idtx.h>
16
17 #include "lib/manifest.h"
18 #include "debug.h"
19
20 int rpmcliPackagesTotal = 0;
21 int rpmcliHashesCurrent = 0;
22 int rpmcliHashesTotal = 0;
23 int rpmcliProgressCurrent = 0;
24 int rpmcliProgressTotal = 0;
25
26 /**
27  * Print a CLI progress bar.
28  * @todo Unsnarl isatty(STDOUT_FILENO) from the control flow.
29  * @param amount        current
30  * @param total         final
31  */
32 static void printHash(const rpm_off_t amount, const rpm_off_t total)
33 {
34     int hashesNeeded;
35
36     rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
37
38     if (rpmcliHashesCurrent != rpmcliHashesTotal) {
39         float pct = (total ? (((float) amount) / total) : 1.0);
40         hashesNeeded = (rpmcliHashesTotal * pct) + 0.5;
41         while (hashesNeeded > rpmcliHashesCurrent) {
42             if (isatty (STDOUT_FILENO)) {
43                 int i;
44                 for (i = 0; i < rpmcliHashesCurrent; i++)
45                     (void) putchar ('#');
46                 for (; i < rpmcliHashesTotal; i++)
47                     (void) putchar (' ');
48                 fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
49                 for (i = 0; i < (rpmcliHashesTotal + 6); i++)
50                     (void) putchar ('\b');
51             } else
52                 fprintf(stdout, "#");
53
54             rpmcliHashesCurrent++;
55         }
56         (void) fflush(stdout);
57
58         if (rpmcliHashesCurrent == rpmcliHashesTotal) {
59             int i;
60             rpmcliProgressCurrent++;
61             if (isatty(STDOUT_FILENO)) {
62                 for (i = 1; i < rpmcliHashesCurrent; i++)
63                     (void) putchar ('#');
64                 pct = (rpmcliProgressTotal
65                     ? (((float) rpmcliProgressCurrent) / rpmcliProgressTotal)
66                     : 1);
67                 fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
68             }
69             fprintf(stdout, "\n");
70         }
71         (void) fflush(stdout);
72     }
73 }
74
75 void * rpmShowProgress(const void * arg,
76                         const rpmCallbackType what,
77                         const rpm_off_t amount,
78                         const rpm_off_t total,
79                         fnpyKey key,
80                         void * data)
81 {
82     Header h = (Header) arg;
83     char * s;
84     int flags = (int) ((long)data);
85     void * rc = NULL;
86     const char * filename = (const char *)key;
87     static FD_t fd = NULL;
88     int xx;
89
90     switch (what) {
91     case RPMCALLBACK_INST_OPEN_FILE:
92         if (filename == NULL || filename[0] == '\0')
93             return NULL;
94         fd = Fopen(filename, "r.ufdio");
95         /* FIX: still necessary? */
96         if (fd == NULL || Ferror(fd)) {
97             rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), filename,
98                         Fstrerror(fd));
99             if (fd != NULL) {
100                 xx = Fclose(fd);
101                 fd = NULL;
102             }
103         } else
104             fd = fdLink(fd, RPMDBG_M("persist (showProgress)"));
105         return (void *)fd;
106         break;
107
108     case RPMCALLBACK_INST_CLOSE_FILE:
109         /* FIX: still necessary? */
110         fd = fdFree(fd, RPMDBG_M("persist (showProgress)"));
111         if (fd != NULL) {
112             xx = Fclose(fd);
113             fd = NULL;
114         }
115         break;
116
117     case RPMCALLBACK_INST_START:
118         rpmcliHashesCurrent = 0;
119         if (h == NULL || !(flags & INSTALL_LABEL))
120             break;
121         /* @todo Remove headerSprintf() on a progress callback. */
122         if (flags & INSTALL_HASH) {
123             s = headerSprintf(h, "%{NAME}",
124                                 rpmTagTable, rpmHeaderFormats, NULL);
125             if (isatty (STDOUT_FILENO))
126                 fprintf(stdout, "%4d:%-23.23s", rpmcliProgressCurrent + 1, s);
127             else
128                 fprintf(stdout, "%-28.28s", s);
129             (void) fflush(stdout);
130             s = _free(s);
131         } else {
132             s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
133                                   rpmTagTable, rpmHeaderFormats, NULL);
134             fprintf(stdout, "%s\n", s);
135             (void) fflush(stdout);
136             s = _free(s);
137         }
138         break;
139
140     case RPMCALLBACK_TRANS_PROGRESS:
141     case RPMCALLBACK_INST_PROGRESS:
142         if (flags & INSTALL_PERCENT)
143             fprintf(stdout, "%%%% %f\n", (double) (total
144                                 ? ((((float) amount) / total) * 100)
145                                 : 100.0));
146         else if (flags & INSTALL_HASH)
147             printHash(amount, total);
148         (void) fflush(stdout);
149         break;
150
151     case RPMCALLBACK_TRANS_START:
152         rpmcliHashesCurrent = 0;
153         rpmcliProgressTotal = 1;
154         rpmcliProgressCurrent = 0;
155         if (!(flags & INSTALL_LABEL))
156             break;
157         if (flags & INSTALL_HASH)
158             fprintf(stdout, "%-28s", _("Preparing..."));
159         else
160             fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
161         (void) fflush(stdout);
162         break;
163
164     case RPMCALLBACK_TRANS_STOP:
165         if (flags & INSTALL_HASH)
166             printHash(1, 1);    /* Fixes "preparing..." progress bar */
167         rpmcliProgressTotal = rpmcliPackagesTotal;
168         rpmcliProgressCurrent = 0;
169         break;
170
171     case RPMCALLBACK_REPACKAGE_START:
172         rpmcliHashesCurrent = 0;
173         rpmcliProgressTotal = total;
174         rpmcliProgressCurrent = 0;
175         if (!(flags & INSTALL_LABEL))
176             break;
177         if (flags & INSTALL_HASH)
178             fprintf(stdout, "%-28s\n", _("Repackaging..."));
179         else
180             fprintf(stdout, "%s\n", _("Repackaging erased files..."));
181         (void) fflush(stdout);
182         break;
183
184     case RPMCALLBACK_REPACKAGE_PROGRESS:
185         if (amount && (flags & INSTALL_HASH))
186             printHash(1, 1);    /* Fixes "preparing..." progress bar */
187         break;
188
189     case RPMCALLBACK_REPACKAGE_STOP:
190         rpmcliProgressTotal = total;
191         rpmcliProgressCurrent = total;
192         if (flags & INSTALL_HASH)
193             printHash(1, 1);    /* Fixes "preparing..." progress bar */
194         rpmcliProgressTotal = rpmcliPackagesTotal;
195         rpmcliProgressCurrent = 0;
196         if (!(flags & INSTALL_LABEL))
197             break;
198         if (flags & INSTALL_HASH)
199             fprintf(stdout, "%-28s\n", _("Upgrading..."));
200         else
201             fprintf(stdout, "%s\n", _("Upgrading packages..."));
202         (void) fflush(stdout);
203         break;
204
205     case RPMCALLBACK_UNINST_PROGRESS:
206         break;
207     case RPMCALLBACK_UNINST_START:
208         break;
209     case RPMCALLBACK_UNINST_STOP:
210         break;
211     case RPMCALLBACK_UNPACK_ERROR:
212         break;
213     case RPMCALLBACK_CPIO_ERROR:
214         break;
215     case RPMCALLBACK_SCRIPT_ERROR:
216         break;
217     case RPMCALLBACK_UNKNOWN:
218     default:
219         break;
220     }
221
222     return rc;
223 }       
224
225 typedef const char * str_t;
226
227 struct rpmEIU {
228     Header h;
229     FD_t fd;
230     int numFailed;
231     int numPkgs;
232     char ** pkgURL;
233     str_t * fnp;
234     char * pkgState;
235     int prevx;
236     int pkgx;
237     int numRPMS;
238     int numSRPMS;
239     str_t * sourceURL;
240     int isSource;
241     int argc;
242     char ** argv;
243     rpmRelocation * relocations;
244     rpmRC rpmrc;
245 };
246
247 /** @todo Generalize --freshen policies. */
248 int rpmInstall(rpmts ts,
249                 struct rpmInstallArguments_s * ia,
250                 const char ** fileArgv)
251 {
252     struct rpmEIU * eiu = memset(alloca(sizeof(*eiu)), 0, sizeof(*eiu));
253     rpmps ps;
254     rpmprobFilterFlags probFilter;
255     rpmRelocation * relocations;
256     char * fileURL = NULL;
257     int stopInstall = 0;
258     char ** av = NULL;
259     rpmVSFlags vsflags, ovsflags, tvsflags;
260     int ac = 0;
261     int rc;
262     int xx;
263     int i;
264
265     if (fileArgv == NULL) goto exit;
266
267     rpmcliPackagesTotal = 0;
268
269     if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
270         ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
271
272     (void) rpmtsSetFlags(ts, ia->transFlags);
273
274     probFilter = ia->probFilter;
275     relocations = ia->relocations;
276
277     if (ia->installInterfaceFlags & INSTALL_UPGRADE)
278         vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
279     else
280         vsflags = rpmExpandNumeric("%{?_vsflags_install}");
281     if (ia->qva_flags & VERIFY_DIGEST)
282         vsflags |= _RPMVSF_NODIGESTS;
283     if (ia->qva_flags & VERIFY_SIGNATURE)
284         vsflags |= _RPMVSF_NOSIGNATURES;
285     if (ia->qva_flags & VERIFY_HDRCHK)
286         vsflags |= RPMVSF_NOHDRCHK;
287     ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
288
289     {   int notifyFlags;
290         notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
291         xx = rpmtsSetNotifyCallback(ts,
292                         rpmShowProgress, (void *) ((long)notifyFlags));
293     }
294
295     if ((eiu->relocations = relocations) != NULL) {
296         while (eiu->relocations->oldPath)
297             eiu->relocations++;
298         if (eiu->relocations->newPath == NULL)
299             eiu->relocations = NULL;
300     }
301
302     /* Build fully globbed list of arguments in argv[argc]. */
303     for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
304         char * fn;
305         av = _free(av); ac = 0;
306         fn = rpmEscapeSpaces(*eiu->fnp);
307         rc = rpmGlob(fn, &ac, &av);
308         fn = _free(fn);
309         if (rc || ac == 0) {
310             rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
311             continue;
312         }
313
314         eiu->argv = xrealloc(eiu->argv, (eiu->argc+ac+1) * sizeof(*eiu->argv));
315         memcpy(eiu->argv+eiu->argc, av, ac * sizeof(*av));
316         eiu->argc += ac;
317         eiu->argv[eiu->argc] = NULL;
318     }
319     av = _free(av);     ac = 0;
320
321 restart:
322     /* Allocate sufficient storage for next set of args. */
323     if (eiu->pkgx >= eiu->numPkgs) {
324         eiu->numPkgs = eiu->pkgx + eiu->argc;
325         eiu->pkgURL = xrealloc(eiu->pkgURL,
326                         (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL));
327         memset(eiu->pkgURL + eiu->pkgx, 0,
328                         ((eiu->argc + 1) * sizeof(*eiu->pkgURL)));
329         eiu->pkgState = xrealloc(eiu->pkgState,
330                         (eiu->numPkgs + 1) * sizeof(*eiu->pkgState));
331         memset(eiu->pkgState + eiu->pkgx, 0,
332                         ((eiu->argc + 1) * sizeof(*eiu->pkgState)));
333     }
334
335     /* Retrieve next set of args, cache on local storage. */
336     for (i = 0; i < eiu->argc; i++) {
337         fileURL = _free(fileURL);
338         fileURL = eiu->argv[i];
339         eiu->argv[i] = NULL;
340
341 #ifdef  NOTYET
342 if (fileURL[0] == '=') {
343     rpmds this = rpmdsSingle(RPMTAG_REQUIRENAME, fileURL+1, NULL, 0);
344
345     xx = rpmtsSolve(ts, this, NULL);
346     if (ts->suggests && ts->nsuggests > 0) {
347         fileURL = _free(fileURL);
348         fileURL = ts->suggests[0];
349         ts->suggests[0] = NULL;
350         while (ts->nsuggests-- > 0) {
351             if (ts->suggests[ts->nsuggests] == NULL)
352                 continue;
353             ts->suggests[ts->nsuggests] = _free(ts->suggests[ts->nsuggests]);
354         }
355         ts->suggests = _free(ts->suggests);
356         rpmlog(RPMLOG_DEBUG, "Adding goal: %s\n", fileURL);
357         eiu->pkgURL[eiu->pkgx] = fileURL;
358         fileURL = NULL;
359         eiu->pkgx++;
360     }
361     this = rpmdsFree(this);
362 } else
363 #endif
364
365         switch (urlIsURL(fileURL)) {
366         case URL_IS_HTTPS:
367         case URL_IS_HTTP:
368         case URL_IS_FTP:
369         {   char *tfn;
370
371             if (rpmIsVerbose())
372                 fprintf(stdout, _("Retrieving %s\n"), fileURL);
373
374             {   char tfnbuf[64];
375                 const char * rootDir = rpmtsRootDir(ts);
376                 if (!(rootDir && * rootDir))
377                     rootDir = "";
378                 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
379 #if defined(HAVE_MKSTEMP)
380                 (void) close(mkstemp(tfnbuf));
381 #else
382                 (void) mktemp(tfnbuf);
383 #endif
384                 tfn = rpmGenPath(rootDir, "%{_tmppath}/", tfnbuf);
385             }
386
387             /* XXX undefined %{name}/%{version}/%{release} here */
388             /* XXX %{_tmpdir} does not exist */
389             rpmlog(RPMLOG_DEBUG, " ... as %s\n", tfn);
390             rc = urlGetFile(fileURL, tfn);
391             if (rc < 0) {
392                 rpmlog(RPMLOG_ERR,
393                         _("skipping %s - transfer failed - %s\n"),
394                         fileURL, ftpStrerror(rc));
395                 eiu->numFailed++;
396                 eiu->pkgURL[eiu->pkgx] = NULL;
397                 tfn = _free(tfn);
398                 break;
399             }
400             eiu->pkgState[eiu->pkgx] = 1;
401             eiu->pkgURL[eiu->pkgx] = tfn;
402             eiu->pkgx++;
403         }   break;
404         case URL_IS_PATH:
405         case URL_IS_DASH:       /* WRONG WRONG WRONG */
406         case URL_IS_HKP:        /* WRONG WRONG WRONG */
407         default:
408             eiu->pkgURL[eiu->pkgx] = fileURL;
409             fileURL = NULL;
410             eiu->pkgx++;
411             break;
412         }
413     }
414     fileURL = _free(fileURL);
415
416     if (eiu->numFailed) goto exit;
417
418     /* Continue processing file arguments, building transaction set. */
419     for (eiu->fnp = (const char**) eiu->pkgURL+eiu->prevx;
420          *eiu->fnp != NULL;
421          eiu->fnp++, eiu->prevx++)
422     {
423         const char * fileName;
424
425         rpmlog(RPMLOG_DEBUG, "============== %s\n", *eiu->fnp);
426         (void) urlPath(*eiu->fnp, &fileName);
427
428         /* Try to read the header from a package file. */
429         eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
430         if (eiu->fd == NULL || Ferror(eiu->fd)) {
431             rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
432                         Fstrerror(eiu->fd));
433             if (eiu->fd != NULL) {
434                 xx = Fclose(eiu->fd);
435                 eiu->fd = NULL;
436             }
437             eiu->numFailed++; *eiu->fnp = NULL;
438             continue;
439         }
440
441         /* Read the header, verifying signatures (if present). */
442         tvsflags = rpmtsSetVSFlags(ts, vsflags);
443         eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h);
444         tvsflags = rpmtsSetVSFlags(ts, tvsflags);
445         xx = Fclose(eiu->fd);
446         eiu->fd = NULL;
447
448         switch (eiu->rpmrc) {
449         case RPMRC_FAIL:
450             rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), *eiu->fnp);
451             eiu->numFailed++; *eiu->fnp = NULL;
452             continue;
453             break;
454         case RPMRC_NOTFOUND:
455             goto maybe_manifest;
456             break;
457         case RPMRC_NOTTRUSTED:
458         case RPMRC_NOKEY:
459         case RPMRC_OK:
460         default:
461             break;
462         }
463
464         eiu->isSource = headerIsSource(eiu->h);
465
466         if (eiu->isSource) {
467             rpmlog(RPMLOG_DEBUG, "\tadded source package [%d]\n",
468                 eiu->numSRPMS);
469             eiu->sourceURL = xrealloc(eiu->sourceURL,
470                                 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
471             eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
472             *eiu->fnp = NULL;
473             eiu->numSRPMS++;
474             eiu->sourceURL[eiu->numSRPMS] = NULL;
475             continue;
476         }
477
478         if (eiu->relocations) {
479             const char ** paths;
480             rpmTagType pft;
481             rpm_count_t c;
482
483             if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
484                                        (rpm_data_t *) &paths, &c) && (c == 1))
485             {
486                 eiu->relocations->oldPath = xstrdup(paths[0]);
487                 paths = headerFreeData(paths, pft);
488             } else {
489                 const char * name;
490                 xx = headerNVR(eiu->h, &name, NULL, NULL);
491                 rpmlog(RPMLOG_ERR,
492                                _("package %s is not relocatable\n"), name);
493                 eiu->numFailed++;
494                 goto exit;
495             }
496         }
497
498         /* On --freshen, verify package is installed and newer */
499         if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
500             rpmdbMatchIterator mi;
501             const char * name;
502             Header oldH;
503             int count;
504
505             xx = headerNVR(eiu->h, &name, NULL, NULL);
506             mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0);
507             count = rpmdbGetIteratorCount(mi);
508             while ((oldH = rpmdbNextIterator(mi)) != NULL) {
509                 if (rpmVersionCompare(oldH, eiu->h) < 0)
510                     continue;
511                 /* same or newer package already installed */
512                 count = 0;
513                 break;
514             }
515             mi = rpmdbFreeIterator(mi);
516             if (count == 0) {
517                 eiu->h = headerFree(eiu->h);
518                 continue;
519             }
520             /* Package is newer than those currently installed. */
521         }
522
523         rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName,
524                         (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
525                         relocations);
526
527         /* XXX reference held by transaction set */
528         eiu->h = headerFree(eiu->h);
529         if (eiu->relocations)
530             eiu->relocations->oldPath = _constfree(eiu->relocations->oldPath);
531
532         switch(rc) {
533         case 0:
534             rpmlog(RPMLOG_DEBUG, "\tadded binary package [%d]\n",
535                         eiu->numRPMS);
536             break;
537         case 1:
538             rpmlog(RPMLOG_ERR,
539                             _("error reading from file %s\n"), *eiu->fnp);
540             eiu->numFailed++;
541             goto exit;
542             break;
543         case 2:
544             rpmlog(RPMLOG_ERR,
545                             _("file %s requires a newer version of RPM\n"),
546                             *eiu->fnp);
547             eiu->numFailed++;
548             goto exit;
549             break;
550         default:
551             eiu->numFailed++;
552             goto exit;
553             break;
554         }
555
556         eiu->numRPMS++;
557         continue;
558
559 maybe_manifest:
560         /* Try to read a package manifest. */
561         eiu->fd = Fopen(*eiu->fnp, "r.fpio");
562         if (eiu->fd == NULL || Ferror(eiu->fd)) {
563             rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
564                         Fstrerror(eiu->fd));
565             if (eiu->fd != NULL) {
566                 xx = Fclose(eiu->fd);
567                 eiu->fd = NULL;
568             }
569             eiu->numFailed++; *eiu->fnp = NULL;
570             break;
571         }
572
573         /* Read list of packages from manifest. */
574 /* FIX: *eiu->argv can be NULL */
575         rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
576         if (rc != RPMRC_OK)
577             rpmlog(RPMLOG_NOTICE, _("%s: not an rpm package (or package manifest): %s\n"),
578                         *eiu->fnp, Fstrerror(eiu->fd));
579         xx = Fclose(eiu->fd);
580         eiu->fd = NULL;
581
582         /* If successful, restart the query loop. */
583         if (rc == RPMRC_OK) {
584             eiu->prevx++;
585             goto restart;
586         }
587
588         eiu->numFailed++; *eiu->fnp = NULL;
589         break;
590     }
591
592     rpmlog(RPMLOG_DEBUG, "found %d source and %d binary packages\n",
593                 eiu->numSRPMS, eiu->numRPMS);
594
595     if (eiu->numFailed) goto exit;
596
597     if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
598
599         if (rpmtsCheck(ts)) {
600             eiu->numFailed = eiu->numPkgs;
601             stopInstall = 1;
602         }
603
604         ps = rpmtsProblems(ts);
605         if (!stopInstall && rpmpsNumProblems(ps) > 0) {
606             rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
607             rpmpsPrint(NULL, ps);
608             eiu->numFailed = eiu->numPkgs;
609             stopInstall = 1;
610
611             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST))
612                 rpmtsPrintSuggests(ts);
613
614         }
615         ps = rpmpsFree(ps);
616     }
617
618     if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
619         if (rpmtsOrder(ts)) {
620             eiu->numFailed = eiu->numPkgs;
621             stopInstall = 1;
622         }
623     }
624
625     if (eiu->numRPMS && !stopInstall) {
626
627         rpmcliPackagesTotal += eiu->numSRPMS;
628
629         rpmlog(RPMLOG_DEBUG, "installing binary packages\n");
630
631         /* Drop added/available package indices and dependency sets. */
632         rpmtsClean(ts);
633
634         rc = rpmtsRun(ts, NULL, probFilter);
635         ps = rpmtsProblems(ts);
636
637         if (rc < 0) {
638             eiu->numFailed += eiu->numRPMS;
639         } else if (rc > 0) {
640             eiu->numFailed += rc;
641             if (rpmpsNumProblems(ps) > 0)
642                 rpmpsPrint(stderr, ps);
643         }
644         ps = rpmpsFree(ps);
645     }
646
647     if (eiu->numSRPMS && !stopInstall) {
648         if (eiu->sourceURL != NULL)
649         for (i = 0; i < eiu->numSRPMS; i++) {
650             rpmdbCheckSignals();
651             if (eiu->sourceURL[i] == NULL) continue;
652             eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
653             if (eiu->fd == NULL || Ferror(eiu->fd)) {
654                 rpmlog(RPMLOG_ERR, _("cannot open file %s: %s\n"),
655                            eiu->sourceURL[i], Fstrerror(eiu->fd));
656                 if (eiu->fd != NULL) {
657                     xx = Fclose(eiu->fd);
658                     eiu->fd = NULL;
659                 }
660                 continue;
661             }
662
663             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
664                 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
665                 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
666             }
667
668             xx = Fclose(eiu->fd);
669             eiu->fd = NULL;
670         }
671     }
672
673 exit:
674     if (eiu->pkgURL != NULL)
675     for (i = 0; i < eiu->numPkgs; i++) {
676         if (eiu->pkgURL[i] == NULL) continue;
677         if (eiu->pkgState[i] == 1)
678             (void) unlink(eiu->pkgURL[i]);
679         eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
680     }
681     eiu->pkgState = _free(eiu->pkgState);
682     eiu->pkgURL = _free(eiu->pkgURL);
683     eiu->argv = _free(eiu->argv);
684
685     rpmtsEmpty(ts);
686
687     return eiu->numFailed;
688 }
689
690 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
691                 const char ** argv)
692 {
693     int count;
694     const char ** arg;
695     int numFailed = 0;
696     int stopUninstall = 0;
697     int numPackages = 0;
698     rpmVSFlags vsflags, ovsflags;
699     rpmps ps;
700
701     if (argv == NULL) return 0;
702
703     vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
704     if (ia->qva_flags & VERIFY_DIGEST)
705         vsflags |= _RPMVSF_NODIGESTS;
706     if (ia->qva_flags & VERIFY_SIGNATURE)
707         vsflags |= _RPMVSF_NOSIGNATURES;
708     if (ia->qva_flags & VERIFY_HDRCHK)
709         vsflags |= RPMVSF_NOHDRCHK;
710     ovsflags = rpmtsSetVSFlags(ts, vsflags);
711
712     if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
713         ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
714
715     /* XXX suggest mechanism only meaningful when installing */
716     ia->transFlags |= RPMTRANS_FLAG_NOSUGGEST;
717
718     (void) rpmtsSetFlags(ts, ia->transFlags);
719
720 #ifdef  NOTYET  /* XXX no callbacks on erase yet */
721     {   int notifyFlags, xx;
722         notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
723         xx = rpmtsSetNotifyCallback(ts,
724                         rpmShowProgress, (void *) ((long)notifyFlags));
725     }
726 #endif
727
728     for (arg = argv; *arg; arg++) {
729         rpmdbMatchIterator mi;
730
731         /* XXX HACK to get rpmdbFindByLabel out of the API */
732         mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
733         if (mi == NULL) {
734             rpmlog(RPMLOG_ERR, _("package %s is not installed\n"), *arg);
735             numFailed++;
736         } else {
737             Header h;   /* XXX iterator owns the reference */
738             count = 0;
739             while ((h = rpmdbNextIterator(mi)) != NULL) {
740                 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
741
742                 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
743                     rpmlog(RPMLOG_ERR, _("\"%s\" specifies multiple packages\n"),
744                         *arg);
745                     numFailed++;
746                     break;
747                 }
748                 if (recOffset) {
749                     (void) rpmtsAddEraseElement(ts, h, recOffset);
750                     numPackages++;
751                 }
752             }
753         }
754         mi = rpmdbFreeIterator(mi);
755     }
756
757     if (numFailed) goto exit;
758
759     if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
760
761         if (rpmtsCheck(ts)) {
762             numFailed = numPackages;
763             stopUninstall = 1;
764         }
765
766         ps = rpmtsProblems(ts);
767         if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
768             rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
769             rpmpsPrint(NULL, ps);
770             numFailed += numPackages;
771             stopUninstall = 1;
772         }
773         ps = rpmpsFree(ps);
774     }
775
776     if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
777         if (rpmtsOrder(ts)) {
778             numFailed += numPackages;
779             stopUninstall = 1;
780         }
781     }
782
783     if (numPackages && !stopUninstall) {
784         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
785
786         /* Drop added/available package indices and dependency sets. */
787         rpmtsClean(ts);
788
789         numPackages = rpmtsRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES));
790         ps = rpmtsProblems(ts);
791         if (rpmpsNumProblems(ps) > 0)
792             rpmpsPrint(NULL, ps);
793         numFailed += numPackages;
794         stopUninstall = 1;
795         ps = rpmpsFree(ps);
796     }
797
798 exit:
799     rpmtsEmpty(ts);
800
801     return numFailed;
802 }
803
804 int rpmInstallSource(rpmts ts, const char * arg,
805                 char ** specFilePtr, char ** cookie)
806 {
807     FD_t fd;
808     int rc;
809
810
811     fd = Fopen(arg, "r.ufdio");
812     if (fd == NULL || Ferror(fd)) {
813         rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
814         if (fd != NULL) (void) Fclose(fd);
815         return 1;
816     }
817
818     if (rpmIsVerbose())
819         fprintf(stdout, _("Installing %s\n"), arg);
820
821     {
822         rpmVSFlags ovsflags =
823                 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
824         rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
825         rc = (rpmrc == RPMRC_OK ? 0 : 1);
826         ovsflags = rpmtsSetVSFlags(ts, ovsflags);
827     }
828     if (rc != 0) {
829         rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), arg);
830         if (specFilePtr && *specFilePtr)
831             *specFilePtr = _free(*specFilePtr);
832         if (cookie && *cookie)
833             *cookie = _free(*cookie);
834     }
835
836     (void) Fclose(fd);
837
838     return rc;
839 }
840
841 /** @todo Transaction handling, more, needs work. */
842 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
843 {
844     int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
845     unsigned thistid = 0xffffffff;
846     unsigned prevtid;
847     time_t tid;
848     IDTX itids = NULL;
849     IDTX rtids = NULL;
850     IDT rp;
851     int nrids = 0;
852     IDT ip;
853     int niids = 0;
854     int rc = 0;
855     rpmVSFlags vsflags, ovsflags;
856     int numAdded;
857     int numRemoved;
858     rpmps ps;
859     int _unsafe_rollbacks = 0;
860     rpmtransFlags transFlags = ia->transFlags;
861
862     if (argv != NULL && *argv != NULL) {
863         rc = -1;
864         goto exit;
865     }
866
867     _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
868
869     vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
870     if (ia->qva_flags & VERIFY_DIGEST)
871         vsflags |= _RPMVSF_NODIGESTS;
872     if (ia->qva_flags & VERIFY_SIGNATURE)
873         vsflags |= _RPMVSF_NOSIGNATURES;
874     if (ia->qva_flags & VERIFY_HDRCHK)
875         vsflags |= RPMVSF_NOHDRCHK;
876     vsflags |= RPMVSF_NEEDPAYLOAD;      /* XXX no legacy signatures */
877     ovsflags = rpmtsSetVSFlags(ts, vsflags);
878
879     (void) rpmtsSetFlags(ts, transFlags);
880
881     /*  Make the transaction a rollback transaction.  In a rollback
882      *  a best effort is what we want 
883      */
884     rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
885
886     itids = IDTXload(ts, RPMTAG_INSTALLTID);
887     if (itids != NULL) {
888         ip = itids->idt;
889         niids = itids->nidt;
890     } else {
891         ip = NULL;
892         niids = 0;
893     }
894
895     {   char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
896         if (globstr == NULL || *globstr == '%') {
897             globstr = _free(globstr);
898             rc = -1;
899             goto exit;
900         }
901         rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
902
903         if (rtids != NULL) {
904             rp = rtids->idt;
905             nrids = rtids->nidt;
906         } else {
907             rp = NULL;
908             nrids = 0;
909         }
910         globstr = _free(globstr);
911     }
912
913     {   int notifyFlags, xx;
914         notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
915         xx = rpmtsSetNotifyCallback(ts,
916                         rpmShowProgress, (void *) ((long)notifyFlags));
917     }
918
919     /* Run transactions until rollback goal is achieved. */
920     do {
921         prevtid = thistid;
922         rc = 0;
923         rpmcliPackagesTotal = 0;
924         numAdded = 0;
925         numRemoved = 0;
926         ia->installInterfaceFlags &= ~ifmask;
927
928         /* Find larger of the remaining install/erase transaction id's. */
929         thistid = 0;
930         if (ip != NULL && ip->val.u32 > thistid)
931             thistid = ip->val.u32;
932         if (rp != NULL && rp->val.u32 > thistid)
933             thistid = rp->val.u32;
934
935         /* If we've achieved the rollback goal, then we're done. */
936         if (thistid == 0 || thistid < ia->rbtid)
937             break;
938
939         /* If we've reached the (configured) rollback goal, then we're done. */
940         if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
941             break;
942
943         rpmtsEmpty(ts);
944         (void) rpmtsSetFlags(ts, transFlags);
945
946         /* Install the previously erased packages for this transaction. */
947         while (rp != NULL && rp->val.u32 == thistid) {
948
949             rpmlog(RPMLOG_DEBUG, "\t+++ install %s\n",
950                         (rp->key ? rp->key : "???"));
951
952             rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
953                                0, ia->relocations);
954             if (rc != 0)
955                 goto exit;
956
957             numAdded++;
958             rpmcliPackagesTotal++;
959             if (!(ia->installInterfaceFlags & ifmask))
960                 ia->installInterfaceFlags |= INSTALL_UPGRADE;
961
962 #ifdef  NOTYET
963             rp->h = headerFree(rp->h);
964 #endif
965             nrids--;
966             if (nrids > 0)
967                 rp++;
968             else
969                 rp = NULL;
970         }
971
972         /* Erase the previously installed packages for this transaction. */
973         while (ip != NULL && ip->val.u32 == thistid) {
974
975             rpmlog(RPMLOG_DEBUG,
976                         "\t--- erase h#%u\n", ip->instance);
977
978             rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
979             if (rc != 0)
980                 goto exit;
981
982             numRemoved++;
983
984             if (_unsafe_rollbacks)
985                 rpmcliPackagesTotal++;
986
987             if (!(ia->installInterfaceFlags & ifmask)) {
988                 ia->installInterfaceFlags |= INSTALL_ERASE;
989                 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
990             }
991
992 #ifdef  NOTYET
993             ip->instance = 0;
994 #endif
995             niids--;
996             if (niids > 0)
997                 ip++;
998             else
999                 ip = NULL;
1000         }
1001
1002         /* Anything to do? */
1003         if (rpmcliPackagesTotal <= 0)
1004             break;
1005
1006         tid = (time_t)thistid;
1007         rpmlog(RPMLOG_NOTICE,
1008                 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1009                         numAdded, numRemoved, ctime(&tid), thistid);
1010
1011         rc = rpmtsCheck(ts);
1012         ps = rpmtsProblems(ts);
1013         if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1014             rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
1015             rpmpsPrint(NULL, ps);
1016             ps = rpmpsFree(ps);
1017             goto exit;
1018         }
1019         ps = rpmpsFree(ps);
1020
1021         rc = rpmtsOrder(ts);
1022         if (rc != 0)
1023             goto exit;
1024
1025         /* Drop added/available package indices and dependency sets. */
1026         rpmtsClean(ts);
1027
1028         rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1029         ps = rpmtsProblems(ts);
1030         if (rc > 0 && rpmpsNumProblems(ps) > 0)
1031             rpmpsPrint(stderr, ps);
1032         ps = rpmpsFree(ps);
1033         if (rc)
1034             goto exit;
1035
1036         /* Clean up after successful rollback. */
1037         if (rtids && !rpmIsDebug()) {
1038             int i;
1039             rpmlog(RPMLOG_NOTICE, _("Cleaning up repackaged packages:\n"));
1040             if (rtids->idt)
1041             for (i = 0; i < rtids->nidt; i++) {
1042                 IDT rrp = rtids->idt + i;
1043                 if (rrp->val.u32 != thistid)
1044                     continue;
1045                 if (rrp->key) { /* XXX can't happen */
1046                     rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key);
1047                     (void) unlink(rrp->key);    /* XXX: Should check rc??? */
1048                 }
1049             }
1050         }
1051
1052
1053     } while (1);
1054
1055 exit:
1056     rtids = IDTXfree(rtids);
1057     itids = IDTXfree(itids);
1058
1059     rpmtsEmpty(ts);
1060     (void) rpmtsSetFlags(ts, transFlags);
1061
1062     return rc;
1063 }