rpm 5.3.7

lib/rpminstall.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmiotypes.h>
00009 #include <poptIO.h>
00010 
00011 #include <rpmtag.h>
00012 #define _RPMEVR_INTERNAL        /* XXX expose rpmVersionCompare prototype */
00013 #include <rpmevr.h>
00014 #include "rpmdb.h"
00015 #ifdef  NOTYET
00016 #include "rpmds.h"              /* XXX ts->suggests, +foo -foo =foo args */
00017 #endif
00018 
00019 #include "rpmte.h"              /* XXX rpmtsPrint() */
00020 #define _RPMTS_INTERNAL         /* XXX ts->suggests */
00021 #include <rpmts.h>
00022 
00023 #include "manifest.h"
00024 #define _RPMGI_INTERNAL         /* XXX "+bing" args need gi->h. */
00025 #include "rpmgi.h"
00026 
00027 #include <rpmlib.h>
00028 
00029 #include <rpmcli.h>
00030 #define _RPMROLLBACK_INTERNAL
00031 #include <rpmrollback.h>
00032 
00033 #include "debug.h"
00034 
00035 /*@access FD_t @*/      /* XXX void * arg */
00036 /*@access rpmts @*/     /* XXX ts->suggests */
00037 /*@access rpmgi @*/     /* XXX gi->h */
00038 /*@access fnpyKey @*/   /* XXX cast */
00039 
00040 /*@unchecked@*/
00041 int rpmcliPackagesTotal = 0;
00042 /*@unchecked@*/
00043 int rpmcliHashesCurrent = 0;
00044 /*@unchecked@*/
00045 int rpmcliHashesTotal = 0;
00046 /*@unchecked@*/
00047 rpmuint64_t rpmcliProgressCurrent = 0;
00048 /*@unchecked@*/
00049 rpmuint64_t rpmcliProgressTotal = 0;
00050 
00057 static void printHash(const rpmuint64_t amount, const rpmuint64_t total)
00058         /*@globals rpmcliHashesCurrent, rpmcliHashesTotal,
00059                 rpmcliProgressCurrent, fileSystem @*/
00060         /*@modifies rpmcliHashesCurrent, rpmcliHashesTotal,
00061                 rpmcliProgressCurrent, fileSystem @*/
00062 {
00063     int hashesNeeded;
00064 
00065     rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
00066 
00067     if (rpmcliHashesCurrent != rpmcliHashesTotal) {
00068         float pct = (float) (total ? (((float) amount) / total) : 1);
00069         hashesNeeded = (int)((rpmcliHashesTotal * pct) + 0.5);
00070         while (hashesNeeded > rpmcliHashesCurrent) {
00071             if (isatty (STDOUT_FILENO)) {
00072                 int i;
00073                 for (i = 0; i < rpmcliHashesCurrent; i++)
00074                     (void) putchar ('#');
00075                 for (; i < rpmcliHashesTotal; i++)
00076                     (void) putchar (' ');
00077                 fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
00078                 for (i = 0; i < (rpmcliHashesTotal + 6); i++)
00079                     (void) putchar ('\b');
00080             } else
00081                 fprintf(stdout, "#");
00082 
00083             rpmcliHashesCurrent++;
00084         }
00085         (void) fflush(stdout);
00086 
00087         if (rpmcliHashesCurrent == rpmcliHashesTotal) {
00088             int i;
00089             rpmcliProgressCurrent++;
00090             if (isatty(STDOUT_FILENO)) {
00091                 for (i = 1; i < rpmcliHashesCurrent; i++)
00092                     (void) putchar ('#');
00093                 pct = (float) (rpmcliProgressTotal
00094                     ? (((float) rpmcliProgressCurrent) / rpmcliProgressTotal)
00095                     : 1);
00096                 fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
00097             }
00098             fprintf(stdout, "\n");
00099         }
00100         (void) fflush(stdout);
00101     }
00102 }
00103 
00104 void * rpmShowProgress(/*@null@*/ const void * arg,
00105                         const rpmCallbackType what,
00106                         const rpmuint64_t amount,
00107                         const rpmuint64_t total,
00108                         /*@null@*/ fnpyKey key,
00109                         /*@null@*/ void * data)
00110         /*@globals rpmcliHashesCurrent, rpmcliProgressCurrent, rpmcliProgressTotal,
00111                 rpmGlobalMacroContext, fileSystem @*/
00112         /*@modifies rpmcliHashesCurrent, rpmcliProgressCurrent, rpmcliProgressTotal,
00113                 rpmGlobalMacroContext, fileSystem @*/
00114 {
00115 /*@-abstract -castexpose @*/
00116     Header h = (Header) arg;
00117 /*@=abstract =castexpose @*/
00118     const char * s;
00119     int flags = (int) ((long)data);
00120     void * rc = NULL;
00121 /*@-abstract -assignexpose @*/
00122     const char * filename = (const char *)key;
00123 /*@=abstract =assignexpose @*/
00124     static FD_t fd = NULL;
00125     int xx;
00126 
00127     switch (what) {
00128     case RPMCALLBACK_INST_OPEN_FILE:
00129         if (filename == NULL || filename[0] == '\0')
00130             return NULL;
00131         fd = Fopen(filename, "r%{?_rpmgio}");
00132 
00133         /* XXX Retry once to handle http:// server timeout reopen's. */
00134         if (Ferror(fd)) {
00135             int ut = urlPath(filename, NULL);
00136             if (ut == URL_IS_HTTP || ut == URL_IS_HTTPS) {
00137                 /* XXX HACK: Fclose(fd) no workie here. */
00138                 fd = Fopen(filename, "r%{?_rpmgio}");
00139             }
00140         }
00141 
00142         if (fd == NULL || Ferror(fd)) {
00143             rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), filename,
00144                         Fstrerror(fd));
00145             if (fd != NULL) {
00146                 xx = Fclose(fd);
00147                 fd = NULL;
00148             }
00149         } else
00150             fd = fdLink(fd, "persist (showProgress)");
00151 
00152 #if defined(POSIX_FADV_WILLNEED)
00153         (void) Fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
00154 #endif
00155 
00156 /*@+voidabstract@*/
00157         return (void *)fd;
00158 /*@=voidabstract@*/
00159         /*@notreached@*/ break;
00160 
00161     case RPMCALLBACK_INST_CLOSE_FILE:
00162         /*@-type@*/ /* FIX: still necessary? */
00163         fd = fdFree(fd, "persist (showProgress)");
00164         /*@=type@*/
00165         if (fd != NULL) {
00166             xx = Fclose(fd);
00167             fd = NULL;
00168         }
00169         break;
00170 
00171     case RPMCALLBACK_INST_START:
00172         rpmcliHashesCurrent = 0;
00173         if (h == NULL || !(flags & INSTALL_LABEL))
00174             break;
00175         /* @todo Remove headerSprintf() on a progress callback. */
00176         if (flags & INSTALL_HASH) {
00177             s = headerSprintf(h, "%{NAME}",
00178                                 NULL, rpmHeaderFormats, NULL);
00179             if (isatty (STDOUT_FILENO))
00180                 fprintf(stdout, "%4d:%-23.23s", (int)rpmcliProgressCurrent + 1, s);
00181             else
00182                 fprintf(stdout, "%-28.28s", s);
00183             (void) fflush(stdout);
00184             s = _free(s);
00185         } else {
00186             char * t = rpmExpand("%{?___NVRA}%{!?___NVRA:%%{NAME}-%%{VERSION}-%%{RELEASE}}", NULL);
00187             s = headerSprintf(h, t, NULL, rpmHeaderFormats, NULL);
00188             fprintf(stdout, "%s\n", s);
00189             (void) fflush(stdout);
00190             s = _free(s);
00191             t = _free(t);
00192         }
00193         break;
00194 
00195     case RPMCALLBACK_TRANS_PROGRESS:
00196     case RPMCALLBACK_INST_PROGRESS:
00197 /*@+relaxtypes@*/
00198         if (flags & INSTALL_PERCENT)
00199             fprintf(stdout, "%%%% %f\n", (double) (total
00200                                 ? ((((float) amount) / total) * 100)
00201                                 : 100.0));
00202         else if (flags & INSTALL_HASH)
00203             printHash(amount, total);
00204 /*@=relaxtypes@*/
00205         (void) fflush(stdout);
00206         break;
00207 
00208     case RPMCALLBACK_TRANS_START:
00209         rpmcliHashesCurrent = 0;
00210         rpmcliProgressTotal = 1;
00211         rpmcliProgressCurrent = 0;
00212         if (!(flags & INSTALL_LABEL))
00213             break;
00214         if (flags & INSTALL_HASH)
00215             fprintf(stdout, "%-28s", _("Preparing..."));
00216         else
00217             fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
00218         (void) fflush(stdout);
00219         break;
00220 
00221     case RPMCALLBACK_TRANS_STOP:
00222         if (flags & INSTALL_HASH)
00223             printHash(1, 1);    /* Fixes "preparing..." progress bar */
00224         rpmcliProgressTotal = rpmcliPackagesTotal;
00225         rpmcliProgressCurrent = 0;
00226         break;
00227 
00228     case RPMCALLBACK_REPACKAGE_START:
00229         rpmcliHashesCurrent = 0;
00230         rpmcliProgressTotal = total;
00231         rpmcliProgressCurrent = 0;
00232         if (!(flags & INSTALL_LABEL))
00233             break;
00234         if (flags & INSTALL_HASH)
00235             fprintf(stdout, "%-28s\n", _("Repackaging..."));
00236         else
00237             fprintf(stdout, "%s\n", _("Repackaging erased files..."));
00238         (void) fflush(stdout);
00239         break;
00240 
00241     case RPMCALLBACK_REPACKAGE_PROGRESS:
00242         if (amount && (flags & INSTALL_HASH))
00243             printHash(1, 1);    /* Fixes "preparing..." progress bar */
00244         break;
00245 
00246     case RPMCALLBACK_REPACKAGE_STOP:
00247         rpmcliProgressTotal = total;
00248         rpmcliProgressCurrent = total;
00249         if (flags & INSTALL_HASH)
00250             printHash(1, 1);    /* Fixes "preparing..." progress bar */
00251         rpmcliProgressTotal = rpmcliPackagesTotal;
00252         rpmcliProgressCurrent = 0;
00253         if (!(flags & INSTALL_LABEL))
00254             break;
00255         if (flags & INSTALL_HASH)
00256             fprintf(stdout, "%-28s\n", _("Upgrading..."));
00257         else
00258             fprintf(stdout, "%s\n", _("Upgrading packages..."));
00259         (void) fflush(stdout);
00260         break;
00261 
00262     case RPMCALLBACK_UNINST_PROGRESS:
00263         break;
00264     case RPMCALLBACK_UNINST_START:
00265         break;
00266     case RPMCALLBACK_UNINST_STOP:
00267         break;
00268     case RPMCALLBACK_UNPACK_ERROR:
00269         break;
00270     case RPMCALLBACK_CPIO_ERROR:
00271         break;
00272     case RPMCALLBACK_SCRIPT_ERROR:
00273         break;
00274     case RPMCALLBACK_UNKNOWN:
00275     default:
00276         break;
00277     }
00278 
00279     return rc;
00280 }
00281 
00282 int rpmcliInstallProblems(rpmts ts, const char * msg, int rc)
00283         /*@globals fileSystem @*/
00284         /*@modifies ts, fileSystem @*/
00285 {
00286     rpmps ps = rpmtsProblems(ts);
00287 
00288     if (rc && rpmpsNumProblems(ps) > 0) {
00289         if (msg)
00290             rpmlog(RPMLOG_ERR, "%s:\n", msg);
00291         rpmpsPrint(NULL, ps);
00292     }
00293     ps = rpmpsFree(ps);
00294     return rc;
00295 }
00296 
00297 int rpmcliInstallSuggests(rpmts ts)
00298 {
00299     if (ts->suggests != NULL && ts->nsuggests > 0) {
00300         const char * s;
00301         int i;
00302 
00303         rpmlog(RPMLOG_NOTICE, _("    Suggested resolutions:\n"));
00304         for (i = 0; i < ts->nsuggests && (s = ts->suggests[i]) != NULL;
00305             ts->suggests[i++] = s = _free(s))
00306         {
00307             rpmlog(RPMLOG_NOTICE, "\t%s\n", s);
00308         }
00309         ts->suggests = _free(ts->suggests);
00310     }
00311     return 0;
00312 }
00313 
00314 int rpmcliInstallCheck(rpmts ts)
00315 {
00316 /*@-evalorder@*/
00317     return rpmcliInstallProblems(ts, _("Failed dependencies"), rpmtsCheck(ts));
00318 /*@=evalorder@*/
00319 }
00320 
00321 int rpmcliInstallOrder(rpmts ts)
00322 {
00323 /*@-evalorder@*/
00324     return rpmcliInstallProblems(ts, _("Ordering problems"), rpmtsOrder(ts));
00325 /*@=evalorder@*/
00326 }
00327 
00328 int rpmcliInstallRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
00329 {
00330 /*@-evalorder@*/
00331     return rpmcliInstallProblems(ts, _("Install/Erase problems"),
00332                         rpmtsRun(ts, okProbs, ignoreSet));
00333 /*@=evalorder@*/
00334 }
00335 
00336 static rpmRC rpmcliEraseElement(rpmts ts, const char * arg)
00337         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00338         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
00339 {
00340     rpmmi mi;
00341     Header h;
00342     rpmRC rc = RPMRC_OK;
00343     int xx;
00344 
00345     mi = rpmtsInitIterator(ts, RPMTAG_NVRA, arg, 0);
00346     if (mi == NULL)
00347         return RPMRC_NOTFOUND;
00348 
00349     while ((h = rpmmiNext(mi)) != NULL) {
00350         uint32_t hdrNum = rpmmiInstance(mi);
00351 
00352         if (hdrNum == 0) {      /* XXX can't happen. */
00353             rc = RPMRC_FAIL;
00354             break;
00355         }
00356         xx = rpmtsAddEraseElement(ts, h, hdrNum);
00357     }
00358     mi = rpmmiFree(mi);
00359 
00360     return 0;
00361 }
00362 
00363 static const char * rpmcliWalkFirst(ARGV_t av, miRE mire)
00364         /*@globals fileSystem, internalState @*/
00365         /*@modifies mire, fileSystem, internalState @*/
00366 {
00367     /* XXX use global ftsOpts? */
00368     /* XXX changing FTS_LOGICAL to FTS_PHYSICAL prevents symlink follow. */
00369     /* XXX FTS_NOCHDIR is automatically assumed for URI's */
00370     int _ftsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
00371     FTS * ftsp = NULL;
00372     FTSENT * fts;
00373     const char * fn = NULL;
00374     int fts_level = 1;
00375     int xx;
00376 
00377     if (av != NULL && av[0] != NULL)
00378         ftsp = Fts_open((char *const *)av, _ftsOpts, NULL);
00379     if (ftsp != NULL)
00380     while((fts = Fts_read(ftsp)) != NULL) {
00381         switch (fts->fts_info) {
00382         /* No-op conditions. */
00383         case FTS_D:             /* preorder directory */
00384         case FTS_DP:            /* postorder directory */
00385             /* XXX Don't recurse downwards, all elements should be files. */
00386             if (fts_level > 0 && fts->fts_level >= fts_level)
00387                 xx = Fts_set(ftsp, fts, FTS_SKIP);
00388             /*@fallthrough@*/
00389         case FTS_DOT:           /* dot or dot-dot */
00390             continue;
00391             /*@notreached@*/ /*@switchbreak@*/ break;
00392         case FTS_F:             /* regular file */
00393             if (mireRegexec(mire, fts->fts_accpath, 0) < 0)
00394                 continue;
00395             /*@switchbreak@*/ break;
00396         /* Error conditions. */
00397         case FTS_NS:            /* stat(2) failed */
00398         case FTS_DNR:           /* unreadable directory */
00399         case FTS_ERR:           /* error; errno is set */
00400         case FTS_DC:            /* directory that causes cycles */
00401         case FTS_DEFAULT:       /* none of the above */
00402         case FTS_INIT:          /* initialized only */
00403         case FTS_NSOK:          /* no stat(2) requested */
00404         case FTS_SL:            /* symbolic link */
00405         case FTS_SLNONE:        /* symbolic link without target */
00406         case FTS_W:             /* whiteout object */
00407         default:
00408             goto exit;
00409             /*@notreached@*/ /*@switchbreak@*/ break;
00410         }
00411 
00412         /* Stop on first file that matches. */
00413         fn = xstrdup(fts->fts_accpath);
00414         break;
00415     }
00416 
00417 exit:
00418     xx = Fts_close(ftsp);
00419     return fn;
00420 }
00421 
00422 static const char * rpmcliInstallElementPath(/*@unused@*/ rpmts ts,
00423                 const char * arg)
00424         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00425         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00426 {
00427     /* A glob pattern list to match repository directories. */
00428     const char * fn = rpmExpand(
00429         "%{?_rpmgi_pattern_glob}"
00430         "%{!?_rpmgi_pattern_glob:.}",
00431         NULL
00432     );
00433     /* A regex pattern list to match candidate *.rpm files. */
00434     const char * mirePattern = rpmExpand(
00435         "%{?_rpmgi_pattern_regex:%{_rpmgi_pattern_regex ", arg, "}}"
00436         "%{!?_rpmgi_pattern_regex:", arg, "-[^-]+-[^-]+\\.[^.]+\\.rpm$}",
00437         NULL
00438     );
00439     miRE mire = mireNew(RPMMIRE_REGEX, 0);
00440     ARGV_t dav = NULL;
00441     int dac = 0;
00442     ARGV_t av = NULL;
00443     int xx = mireRegcomp(mire, mirePattern);
00444     int i;
00445 
00446     /* Get list of candidate repository patterns. */
00447     xx = argvSplit(&dav, fn, ":");
00448     fn = _free(fn);
00449     if (xx || dav == NULL)
00450         goto exit;
00451 
00452     dac = argvCount(dav);
00453     for (i = 0; i < dac; i++) {
00454         ARGV_t nav = NULL;
00455         int nac = 0;
00456 
00457         /* Make sure only directory paths are matched. */
00458         fn = rpmGetPath(dav[i], "/", NULL);
00459         xx = rpmGlob(fn, &nac, &nav);
00460 
00461         if (nav != NULL)
00462         for (i = 0; i < nac; i++) {
00463             const char * t = nav[i];
00464             size_t nt = strlen(t);
00465 
00466             /* Make sure that final directory paths have trailing '/' */
00467             if (!(nt > 0 && t[nt-1] == '/'))
00468                 continue;
00469 
00470             t = rpmExpand(t, "/", NULL);
00471             nav[i] = _free(nav[i]);
00472             nav[i] = t;
00473         }
00474 
00475         /* Append matches to list of repository directories. */
00476         if (nac > 0 && nav != NULL)
00477             xx = argvAppend(&av, nav);
00478         nav = argvFree(nav);
00479         nac = 0;
00480         fn = _free(fn);
00481     }
00482 
00483     /* Walk (possibly multi-root'd) directories, until 1st match is found. */
00484     fn = rpmcliWalkFirst(av, mire);
00485 
00486 exit:
00487     av = argvFree(av);
00488     dav = argvFree(dav);
00489     mire = mireFree(mire);
00490     mirePattern = _free(mirePattern);
00491 
00492     return fn;
00493 }
00494 
00495 /*@-redef@*/    /* XXX Add rpmfi methods to make rpmRelocation opaque. */
00496 struct rpmRelocation_s {
00497 /*@only@*/ /*@null@*/
00498     const char * oldPath;       
00499 /*@only@*/ /*@null@*/
00500     const char * newPath;       
00501 };
00502 /*@=redef@*/
00503 
00505 int rpmcliInstall(rpmts ts, QVA_t ia, const char ** argv)
00506 {
00507     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00508     ARGV_t avfn = NULL;
00509     int acfn = 0;
00510     int numFailed = 0;
00511     int numRPMS = 0;
00512     rpmRelocation relocations = NULL;
00513     rpmVSFlags vsflags, ovsflags;
00514     rpmRC rpmrc;
00515     int rc;
00516     int xx;
00517 
00518     if (argv == NULL) goto exit;
00519 
00520     (void) rpmtsSetGoal(ts, TSM_INSTALL);
00521     rpmcliPackagesTotal = 0;
00522 
00523     if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
00524         ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
00525 
00526     (void) rpmtsSetFlags(ts, ia->transFlags);
00527     (void) rpmtsSetDFlags(ts, ia->depFlags);
00528 
00529     /* Display and set autorollback goal. */
00530     if (rpmExpandNumeric("%{?_rollback_transaction_on_failure}")) {
00531         if (ia->arbtid) {
00532             time_t ttid = (time_t)ia->arbtid;
00533             rpmlog(RPMLOG_DEBUG, D_("Autorollback Goal: %-24.24s (0x%08x)\n"),
00534                 ctime(&ttid), ia->arbtid);
00535             rpmtsSetARBGoal(ts, ia->arbtid);
00536         }
00537     }
00538 
00539     if (ia->installInterfaceFlags & INSTALL_UPGRADE)
00540         vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
00541     else
00542         vsflags = rpmExpandNumeric("%{?_vsflags_install}");
00543     if (ia->qva_flags & VERIFY_DIGEST)
00544         vsflags |= _RPMVSF_NODIGESTS;
00545     if (ia->qva_flags & VERIFY_SIGNATURE)
00546         vsflags |= _RPMVSF_NOSIGNATURES;
00547     if (ia->qva_flags & VERIFY_HDRCHK)
00548         vsflags |= RPMVSF_NOHDRCHK;
00549     ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
00550 
00551     {   int notifyFlags;
00552         notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
00553         xx = rpmtsSetNotifyCallback(ts,
00554                         rpmShowProgress, (void *) ((long)notifyFlags));
00555     }
00556 
00557     if ((relocations = ia->relocations) != NULL) {
00558         while (relocations->oldPath)
00559             relocations++;
00560         if (relocations->newPath == NULL)
00561             relocations = NULL;
00562     }
00563 
00564  {      /* start-of-transaction-build */
00565     int tag = (ia->qva_source == RPMQV_FTSWALK)
00566         ? RPMDBI_FTSWALK : RPMDBI_ARGLIST;
00567     rpmgi gi = rpmgiNew(ts, tag, NULL, 0);
00568     rpmgiFlags _giFlags = RPMGI_NONE;
00569     const char * fn = NULL;;
00570 
00571 /*@-mods@*/
00572     if (rpmioFtsOpts == 0)
00573         rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
00574 /*@=mods@*/
00575     rc = rpmgiSetArgs(gi, argv, rpmioFtsOpts, _giFlags);
00576     while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK) {
00577         Header h;
00578 
00579         fn = _free(fn);
00580         fn = xstrdup(rpmgiHdrPath(gi));
00581 
00582         /* === Check for "+bing" lookaside paths within install transaction. */
00583         if (fn[0] == '+') {
00584             const char * nfn;
00585             addMacro(NULL, "NEVRA", NULL, &fn[1], RMIL_GLOBAL);
00586             nfn = rpmcliInstallElementPath(ts, &fn[1]);
00587             delMacro(NULL, "NEVRA");
00588             if (nfn == NULL) {
00589                 rpmlog(RPMLOG_ERR, _("package \"%s\" cannot be found\n"), fn);
00590                 numFailed++;    /* XXX multiple erasures? */
00591                 continue;
00592             }
00593             fn = _free(fn);
00594             fn = nfn;
00595             /* XXX hack into rpmgi innards for now ... */
00596             h = rpmgiReadHeader(gi, fn);
00597             if (h != NULL)
00598                 gi->h = headerLink(h);
00599             (void)headerFree(h);
00600             h = NULL;
00601         }
00602 
00603         /* === Check for "-bang" erasures within install transaction. */
00604         if (fn[0] == '-') {
00605             switch (rpmcliEraseElement(ts, &fn[1])) {
00606             case RPMRC_OK:
00607                 numRPMS++;      /* XXX multiple erasures? */
00608                 /*@switchbreak@*/ break;
00609             case RPMRC_NOTFOUND:
00610             default:
00611                 rpmlog(RPMLOG_ERR, _("package \"%s\" cannot be erased\n"), fn);
00612                 numFailed++;    /* XXX multiple erasures? */
00613                 goto exit;
00614                 /*@notreached@*/ /*@switchbreak@*/ break;
00615             }
00616             continue;
00617         }
00618 
00619         h = rpmgiHeader(gi);
00620         if (h == NULL) {
00621             numFailed++;
00622             continue;
00623         }
00624 
00625         /* === Check for relocatable package. */
00626         if (relocations) {
00627             he->tag = RPMTAG_PREFIXES;
00628             xx = headerGet(h, he, 0);
00629             if (xx && he->c == 1) {
00630                 relocations->oldPath = xstrdup(he->p.argv[0]);
00631                 he->p.ptr = _free(he->p.ptr);
00632             } else {
00633                 he->p.ptr = _free(he->p.ptr);
00634                 he->tag = RPMTAG_NVRA;
00635                 xx = headerGet(h, he, 0);
00636                 rpmlog(RPMLOG_ERR,
00637                                _("package %s is not relocatable\n"), he->p.str);
00638                 he->p.ptr = _free(he->p.ptr);
00639                 numFailed++;
00640                 goto exit;
00641                 /*@notreached@*/
00642             }
00643         }
00644 
00645         /* === On --freshen, verify package is installed and newer. */
00646         if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
00647             rpmmi mi;
00648             Header oldH;
00649             int count;
00650 
00651             he->tag = RPMTAG_NAME;
00652             xx = headerGet(h, he, 0);
00653 assert(xx != 0 && he->p.str != NULL);
00654             mi = rpmtsInitIterator(ts, RPMTAG_NAME, he->p.str, 0);
00655             he->p.ptr = _free(he->p.ptr);
00656             count = rpmmiCount(mi);
00657             while ((oldH = rpmmiNext(mi)) != NULL) {
00658                 if (rpmVersionCompare(oldH, h) < 0)
00659                     /*@innercontinue@*/ continue;
00660                 /* same or newer package already installed */
00661                 count = 0;
00662                 /*@innerbreak@*/ break;
00663             }
00664             mi = rpmmiFree(mi);
00665             if (count == 0)
00666                 continue;
00667             /* Package is newer than those currently installed. */
00668         }
00669 
00670         /* === Add binary package to transaction set. */
00671         xx = argvAdd(&avfn, fn);
00672         rc = rpmtsAddInstallElement(ts, h, (fnpyKey)avfn[acfn++],
00673                         (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
00674                         ia->relocations);
00675 
00676         if (relocations)
00677             relocations->oldPath = _free(relocations->oldPath);
00678 
00679         numRPMS++;
00680     }
00681 
00682     fn = _free(fn);
00683     gi = rpmgiFree(gi);
00684 
00685  }      /* end-of-transaction-build */
00686 
00687     /* XXX exit if the iteration failed. */
00688     if (rpmrc == RPMRC_FAIL) numFailed = numRPMS;
00689     if (numFailed) goto exit;
00690 
00691     if (numRPMS) {
00692         if (!(ia->installInterfaceFlags & INSTALL_NODEPS)
00693          && (rc = rpmcliInstallCheck(ts)) != 0) {
00694             numFailed = numRPMS;
00695             (void) rpmcliInstallSuggests(ts);
00696         }
00697 
00698         if (!(ia->installInterfaceFlags & INSTALL_NOORDER)
00699          && (rc = rpmcliInstallOrder(ts)) != 0)
00700             numFailed = numRPMS;
00701 
00702         /* Drop added/available package indices and dependency sets. */
00703         rpmtsClean(ts);
00704 
00705         /* XXX Avoid empty transaction msg, run iff there are elements. */
00706         if (numFailed == 0 && rpmtsNElements(ts) > 0
00707          && (rc = rpmcliInstallRun(ts, NULL, ia->probFilter)) != 0)
00708             numFailed += (rc < 0 ? numRPMS : rc);
00709     }
00710 
00711     if (numFailed) goto exit;
00712 
00713 exit:
00714     avfn = argvFree(avfn);
00715 
00716 #ifdef  NOTYET  /* XXX grrr, segfault in selabel_close */
00717     if (!(ia->transFlags & RPMTRANS_FLAG_NOCONTEXTS))
00718         matchpathcon_fini();
00719 #endif
00720 
00721     rpmtsEmpty(ts);
00722 
00723     return numFailed;
00724 }
00725 
00726 int rpmErase(rpmts ts, QVA_t ia, const char ** argv)
00727 {
00728     const char ** arg;
00729     int numFailed = 0;
00730     int numRPMS = 0;
00731     rpmVSFlags vsflags, ovsflags;
00732     int rc;
00733 
00734     if (argv == NULL) return 0;
00735 
00736     vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
00737     if (ia->qva_flags & VERIFY_DIGEST)
00738         vsflags |= _RPMVSF_NODIGESTS;
00739     if (ia->qva_flags & VERIFY_SIGNATURE)
00740         vsflags |= _RPMVSF_NOSIGNATURES;
00741     if (ia->qva_flags & VERIFY_HDRCHK)
00742         vsflags |= RPMVSF_NOHDRCHK;
00743     ovsflags = rpmtsSetVSFlags(ts, vsflags);
00744 
00745     if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
00746         ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
00747 
00748     (void) rpmtsSetFlags(ts, ia->transFlags);
00749     (void) rpmtsSetDFlags(ts, ia->depFlags);
00750 
00751     /* Display and set autorollback goal. */
00752     if (rpmExpandNumeric("%{?_rollback_transaction_on_failure}")) {
00753         if (ia->arbtid) {
00754             time_t ttid = (time_t)ia->arbtid;
00755             rpmlog(RPMLOG_DEBUG, D_("Autorollback Goal: %-24.24s (0x%08x)\n"),
00756                 ctime(&ttid), ia->arbtid);
00757             rpmtsSetARBGoal(ts, ia->arbtid);
00758         }
00759     }
00760 
00761 #ifdef  NOTYET  /* XXX no callbacks on erase yet */
00762     {   int notifyFlags;
00763         notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
00764         xx = rpmtsSetNotifyCallback(ts,
00765                         rpmShowProgress, (void *) ((long)notifyFlags));
00766     }
00767 #endif
00768 
00769     (void) rpmtsSetGoal(ts, TSM_ERASE);
00770 
00771     for (arg = argv; *arg; arg++) {
00772         rpmmi mi;
00773 
00774         /* XXX HACK to get rpmdbFindByLabel out of the API */
00775         mi = rpmtsInitIterator(ts, RPMTAG_NVRA, *arg, 0);
00776         if (mi == NULL) {
00777             rpmlog(RPMLOG_ERR, _("package %s is not installed\n"), *arg);
00778             numFailed++;
00779         } else {
00780             Header h;   /* XXX iterator owns the reference */
00781             int count = 0;
00782             while ((h = rpmmiNext(mi)) != NULL) {
00783                 uint32_t hdrNum = rpmmiInstance(mi);
00784 
00785                 if (!(count++ == 0 || (ia->installInterfaceFlags & INSTALL_ALLMATCHES))) {
00786                     rpmlog(RPMLOG_ERR, _("\"%s\" specifies multiple packages\n"),
00787                         *arg);
00788                     numFailed++;
00789                     /*@innerbreak@*/ break;
00790                 }
00791                 if (hdrNum) {
00792                     (void) rpmtsAddEraseElement(ts, h, hdrNum);
00793                     numRPMS++;
00794                 }
00795             }
00796         }
00797         mi = rpmmiFree(mi);
00798     }
00799 
00800     if (numFailed == 0 && numRPMS > 0) {
00801         if (!(ia->installInterfaceFlags & INSTALL_NODEPS)
00802          && (rc = rpmcliInstallCheck(ts)) != 0)
00803             numFailed = numRPMS;
00804 
00805         if (numFailed == 0
00806          && !(ia->installInterfaceFlags & INSTALL_NOORDER)
00807          && (rc = rpmcliInstallOrder(ts)) != 0)
00808             numFailed = numRPMS;
00809 
00810         /* Drop added/available package indices and dependency sets. */
00811         rpmtsClean(ts);
00812 
00813         if (numFailed == 0
00814          && (rc = rpmcliInstallRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES))) != 0)
00815             numFailed += (rc < 0 ? numRPMS : rc);
00816 
00817     }
00818 
00819     rpmtsEmpty(ts);
00820 
00821     return numFailed;
00822 }
00823 
00824 int rpmInstallSource(rpmts ts, const char * arg,
00825                 const char ** specFilePtr, const char ** cookie)
00826 {
00827     FD_t fd = Fopen(arg, "r%{?_rpmgio}");
00828     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00829 
00830     if (fd == NULL || Ferror(fd)) {
00831         rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
00832         goto exit;
00833     }
00834 
00835     if (rpmIsVerbose())
00836         fprintf(stdout, _("Installing %s\n"), arg);
00837 
00838     {   rpmVSFlags ovsflags =
00839                 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
00840         rc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
00841         ovsflags = rpmtsSetVSFlags(ts, ovsflags);
00842     }
00843     if (rc != RPMRC_OK)
00844         rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), arg);
00845 
00846 exit:
00847     if (fd != NULL) (void) Fclose(fd);
00848 
00849     return (rc == RPMRC_OK ? 0 : 1);
00850 }