Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

lib/rpminstall.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmlib.h>
00008 #include <rpmmacro.h>
00009 #include <rpmurl.h>
00010 
00011 #include "misc.h"
00012 #include "debug.h"
00013 
00014 /*@access Header@*/             /* XXX compared with NULL */
00015 /*@access FD_t@*/               /* XXX compared with NULL */
00016 
00017 /* Define if you want percentage progress in the hash bars when
00018  * writing to a tty (ordinary hash bars otherwise) --claudio
00019  */
00020 #define FANCY_HASH
00021 
00022 static int hashesPrinted = 0;
00023 
00024 #ifdef FANCY_HASH
00025 static int packagesTotal = 0;
00026 static int progressTotal = 0;
00027 static int progressCurrent = 0;
00028 #endif
00029 
00030 static void printHash(const unsigned long amount, const unsigned long total)
00031 {
00032     int hashesNeeded;
00033     int hashesTotal = 50;
00034 
00035 #ifdef FANCY_HASH
00036     if (isatty (STDOUT_FILENO))
00037        hashesTotal = 44;
00038 #endif
00039 
00040     if (hashesPrinted != hashesTotal) {
00041         hashesNeeded = hashesTotal * (total ? (((float) amount) / total) : 1);
00042         while (hashesNeeded > hashesPrinted) {
00043 #ifdef FANCY_HASH
00044            if (isatty (STDOUT_FILENO)) {
00045                int i;
00046                for (i = 0; i < hashesPrinted; i++) putchar ('#');
00047                for (; i < hashesTotal; i++) putchar (' ');
00048                printf ("(%3d%%)", (int)(100 * (total ? (((float) amount) / total) : 1)));
00049                for (i = 0; i < (hashesTotal + 6); i++) putchar ('\b');
00050            } else
00051 #endif
00052                fprintf(stdout, "#");
00053 
00054             fflush(stdout);
00055             hashesPrinted++;
00056         }
00057         fflush(stdout);
00058         hashesPrinted = hashesNeeded;
00059 
00060        if (hashesPrinted == hashesTotal) {
00061 #ifdef FANCY_HASH
00062            int i;
00063            progressCurrent++;
00064            for (i = 1; i < hashesPrinted; i++) putchar ('#');
00065            printf (" [%3d%%]\n", (int)(100 * (progressTotal ?
00066                (((float) progressCurrent) / progressTotal) : 1)));
00067 #else
00068            fprintf (stdout, "\n");
00069 #endif
00070        }
00071     }
00072 }
00073 
00074 static void * showProgress(const void * arg, const rpmCallbackType what, 
00075                            const unsigned long amount, 
00076                            const unsigned long total,
00077                            const void * pkgKey, void * data)
00078 {
00079     Header h = (Header) arg;
00080     char * s;
00081     int flags = (int) ((long)data);
00082     void * rc = NULL;
00083     const char * filename = pkgKey;
00084     static FD_t fd;
00085 
00086     switch (what) {
00087       case RPMCALLBACK_INST_OPEN_FILE:
00088         fd = Fopen(filename, "r.ufdio");
00089         fd = fdLink(fd, "persist (showProgress)");
00090         return fd;
00091 
00092       case RPMCALLBACK_INST_CLOSE_FILE:
00093         fd = fdFree(fd, "persist (showProgress)");
00094         if (fd) {
00095             Fclose(fd);
00096             fd = NULL;
00097         }
00098         break;
00099 
00100       case RPMCALLBACK_INST_START:
00101         hashesPrinted = 0;
00102         if (flags & INSTALL_LABEL) {
00103             if (flags & INSTALL_HASH) {
00104                 s = headerSprintf(h, "%{NAME}",
00105                                   rpmTagTable, rpmHeaderFormats, NULL);
00106 #ifdef FANCY_HASH
00107                if (isatty (STDOUT_FILENO))
00108                    fprintf(stdout, "%4d:%-23.23s", progressCurrent + 1, s);
00109               else
00110 #else
00111                    fprintf(stdout, "%-28s", s);
00112 #endif
00113                 fflush(stdout);
00114             } else {
00115                 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}", 
00116                                   rpmTagTable, rpmHeaderFormats, NULL);
00117                 fprintf(stdout, "%s\n", s);
00118             }
00119             free(s);
00120         }
00121         break;
00122 
00123       case RPMCALLBACK_TRANS_PROGRESS:
00124       case RPMCALLBACK_INST_PROGRESS:
00125         if (flags & INSTALL_PERCENT) {
00126             fprintf(stdout, "%%%% %f\n", (total
00127                                 ? ((float) ((((float) amount) / total) * 100))
00128                                 : 100.0));
00129             fflush(stdout);
00130         } else if (flags & INSTALL_HASH) {
00131             printHash(amount, total);
00132         }
00133         break;
00134 
00135       case RPMCALLBACK_TRANS_START:
00136        hashesPrinted = 0;
00137 #ifdef FANCY_HASH
00138        progressTotal = 1;
00139        progressCurrent = 0;
00140 #endif
00141        if (flags & INSTALL_LABEL) {
00142            if (flags & INSTALL_HASH) {
00143                fprintf(stdout, "%-28s", _("Preparing..."));
00144                fflush(stdout);
00145            } else {
00146                printf("%s\n", _("Preparing packages for installation..."));
00147            }
00148        }
00149        break;
00150 
00151       case RPMCALLBACK_TRANS_STOP:
00152        if (flags & INSTALL_HASH) {
00153            printHash(1, 1);            /* Fixes "preparing..." progress bar */
00154        }
00155 #ifdef FANCY_HASH
00156        progressTotal = packagesTotal;
00157        progressCurrent = 0;
00158 #endif
00159        break;
00160 
00161       case RPMCALLBACK_UNINST_PROGRESS:
00162       case RPMCALLBACK_UNINST_START:
00163       case RPMCALLBACK_UNINST_STOP:
00164         /* ignore */
00165         break;
00166     }
00167 
00168     return rc;
00169 }       
00170 
00172 int rpmInstall(const char * rootdir, const char ** fileArgv,
00173                 rpmtransFlags transFlags, 
00174                 rpmInstallInterfaceFlags interfaceFlags,
00175                 rpmprobFilterFlags probFilter, 
00176                 rpmRelocation * relocations)
00177 {
00178     rpmdb db = NULL;
00179     FD_t fd;
00180     int i;
00181     int mode, rc, major;
00182     const char ** pkgURL = NULL;
00183     const char ** tmppkgURL = NULL;
00184     const char ** fileURL;
00185     int numPkgs;
00186     int numTmpPkgs = 0, numRPMS = 0, numSRPMS = 0;
00187     int numFailed = 0;
00188     Header h;
00189     int isSource;
00190     rpmTransactionSet rpmdep = NULL;
00191     int numConflicts;
00192     int stopInstall = 0;
00193     int notifyFlags = interfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
00194     int dbIsOpen = 0;
00195     const char ** sourceURL;
00196     rpmRelocation * defaultReloc;
00197 
00198     if (transFlags & RPMTRANS_FLAG_TEST) 
00199         mode = O_RDONLY;
00200     else
00201         mode = O_RDWR | O_CREAT;        /* XXX can't O_EXCL */
00202 
00203     for (defaultReloc = relocations; defaultReloc && defaultReloc->oldPath;
00204          defaultReloc++);
00205     if (defaultReloc && !defaultReloc->newPath) defaultReloc = NULL;
00206 
00207     rpmMessage(RPMMESS_DEBUG, _("counting packages to install\n"));
00208     for (fileURL = fileArgv, numPkgs = 0; *fileURL; fileURL++, numPkgs++)
00209         ;
00210 
00211     rpmMessage(RPMMESS_DEBUG, _("found %d packages\n"), numPkgs);
00212 
00213     pkgURL = xcalloc( (numPkgs + 1), sizeof(*pkgURL) );
00214     tmppkgURL = xcalloc( (numPkgs + 1), sizeof(*tmppkgURL) );
00215 
00216     rpmMessage(RPMMESS_DEBUG, _("looking for packages to download\n"));
00217     for (fileURL = fileArgv, i = 0; *fileURL; fileURL++) {
00218 
00219         switch (urlIsURL(*fileURL)) {
00220         case URL_IS_FTP:
00221         case URL_IS_HTTP:
00222         {   int myrc;
00223             int j;
00224             const char *tfn;
00225             const char ** argv;
00226             int argc;
00227 
00228             myrc = rpmGlob(*fileURL, &argc, &argv);
00229             if (myrc) {
00230                 rpmMessage(RPMMESS_ERROR, 
00231                         _("skipping %s - rpmGlob failed(%d)\n"),
00232                         *fileURL, myrc);
00233                 numFailed++;
00234                 pkgURL[i] = NULL;
00235                 break;
00236             }
00237             if (argc > 1) {
00238                 numPkgs += argc - 1;
00239                 pkgURL = xrealloc(pkgURL, (numPkgs + 1) * sizeof(*pkgURL));
00240                 tmppkgURL = xrealloc(tmppkgURL, (numPkgs + 1) * sizeof(*tmppkgURL));
00241             }
00242 
00243             for (j = 0; j < argc; j++) {
00244 
00245                 if (rpmIsVerbose())
00246                     fprintf(stdout, _("Retrieving %s\n"), argv[j]);
00247 
00248                 {   char tfnbuf[64];
00249                     strcpy(tfnbuf, "rpm-xfer.XXXXXX");
00250                     /*@-unrecog@*/ mktemp(tfnbuf) /*@=unrecog@*/;
00251                     tfn = rpmGenPath(rootdir, "%{_tmppath}/", tfnbuf);
00252                 }
00253 
00254                 /* XXX undefined %{name}/%{version}/%{release} here */
00255                 /* XXX %{_tmpdir} does not exist */
00256                 rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
00257                 myrc = urlGetFile(argv[j], tfn);
00258                 if (myrc < 0) {
00259                     rpmMessage(RPMMESS_ERROR, 
00260                         _("skipping %s - transfer failed - %s\n"), 
00261                         argv[j], ftpStrerror(myrc));
00262                     numFailed++;
00263                     pkgURL[i] = NULL;
00264                     free((void *)tfn);
00265                 } else {
00266                     tmppkgURL[numTmpPkgs++] = pkgURL[i++] = tfn;
00267                 }
00268             }
00269             if (argv) {
00270                 for (j = 0; j < argc; j++)
00271                     free((void *)argv[j]);
00272                 free((void *)argv);
00273                 argv = NULL;
00274             }
00275         }   break;
00276         case URL_IS_PATH:
00277         default:
00278             pkgURL[i++] = *fileURL;
00279             break;
00280         }
00281     }
00282     pkgURL[i] = NULL;
00283     tmppkgURL[numTmpPkgs] = NULL;
00284 
00285     sourceURL = alloca(sizeof(*sourceURL) * i);
00286 
00287     rpmMessage(RPMMESS_DEBUG, _("retrieved %d packages\n"), numTmpPkgs);
00288 
00289     if (numFailed) goto errxit;
00290 
00296     for (fileURL = pkgURL; *fileURL; fileURL++) {
00297         const char * fileName;
00298         (void) urlPath(*fileURL, &fileName);
00299         fd = Fopen(*fileURL, "r.ufdio");
00300         if (fd == NULL || Ferror(fd)) {
00301             rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"), *fileURL,
00302                 Fstrerror(fd));
00303             if (fd) Fclose(fd);
00304             numFailed++;
00305             pkgURL[i] = NULL;
00306             continue;
00307         }
00308 
00309         rc = rpmReadPackageHeader(fd, &h, &isSource, &major, NULL);
00310 
00311         switch (rc) {
00312         case 1:
00313             Fclose(fd);
00314             rpmMessage(RPMMESS_ERROR, 
00315                         _("%s does not appear to be a RPM package\n"), 
00316                         *fileURL);
00317             numFailed++;
00318             pkgURL[i] = NULL;
00319             break;
00320         default:
00321             rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *fileURL);
00322             numFailed++;
00323             pkgURL[i] = NULL;
00324             break;
00325         case 0:
00326             if (isSource) {
00327                 sourceURL[numSRPMS++] = fileName;
00328                 Fclose(fd);
00329             } else {
00330                 if (!dbIsOpen) {
00331                     if (rpmdbOpen(rootdir, &db, mode, 0644)) {
00332                         const char *dn;
00333                         dn = rpmGetPath( (rootdir ? rootdir : ""), 
00334                                         "%{_dbpath}", NULL);
00335                         rpmMessage(RPMMESS_ERROR, 
00336                                 _("cannot open Packages database in %s\n"), dn);
00337                         free((void *)dn);
00338                         numFailed++;
00339                         pkgURL[i] = NULL;
00340                         break;
00341                     }
00342                     rpmdep = rpmtransCreateSet(db, rootdir);
00343                     dbIsOpen = 1;
00344                 }
00345 
00346                 if (defaultReloc) {
00347                     const char ** paths;
00348                     int c;
00349 
00350                     if (headerGetEntry(h, RPMTAG_PREFIXES, NULL,
00351                                        (void **) &paths, &c) && (c == 1)) {
00352                         defaultReloc->oldPath = xstrdup(paths[0]);
00353                         free((void *)paths);
00354                     } else {
00355                         const char * name;
00356                         headerNVR(h, &name, NULL, NULL);
00357                         rpmMessage(RPMMESS_ERROR, 
00358                                _("package %s is not relocateable\n"), name);
00359 
00360                         goto errxit;
00361                         /*@notreached@*/
00362                     }
00363                 }
00364 
00365                 /* On --freshen, verify package is installed and newer */
00366                 if (interfaceFlags & INSTALL_FRESHEN) {
00367                     rpmdbMatchIterator mi;
00368                     const char * name;
00369                     Header oldH;
00370                     int count;
00371 
00372                     headerNVR(h, &name, NULL, NULL);
00373                     mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00374                     count = rpmdbGetIteratorCount(mi);
00375                     while ((oldH = rpmdbNextIterator(mi)) != NULL) {
00376                         if (rpmVersionCompare(oldH, h) < 0)
00377                             continue;
00378                         /* same or newer package already installed */
00379                         count = 0;
00380                         break;
00381                     }
00382                     rpmdbFreeIterator(mi);
00383                     if (count == 0) {
00384                         headerFree(h);
00385                         Fclose(fd);
00386                         break;  /* XXX out of switch */
00387                     }
00388                     /* Package is newer than those currently installed. */
00389                 }
00390 
00391                 rc = rpmtransAddPackage(rpmdep, h, NULL, fileName,
00392                                (interfaceFlags & INSTALL_UPGRADE) != 0,
00393                                relocations);
00394 
00395                 headerFree(h);  /* XXX reference held by transaction set */
00396                 Fclose(fd);
00397 
00398                 switch(rc) {
00399                 case 0:
00400                         break;
00401                 case 1:
00402                         rpmMessage(RPMMESS_ERROR, 
00403                             _("error reading from file %s\n"), *fileURL);
00404                         goto errxit;
00405                         /*@notreached@*/ break;
00406                 case 2:
00407                         rpmMessage(RPMMESS_ERROR, 
00408                             _("file %s requires a newer version of RPM\n"),
00409                             *fileURL);
00410                         goto errxit;
00411                         /*@notreached@*/ break;
00412                 }
00413 
00414                 if (defaultReloc) {
00415                     free((void *)defaultReloc->oldPath);
00416                     defaultReloc->oldPath = NULL;
00417                 }
00418 
00419                 numRPMS++;
00420             }
00421             break;
00422         }
00423     }
00424 
00425     if (numFailed) goto errxit;
00426 
00427     rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"), 
00428                 numSRPMS, numRPMS);
00429 
00430     if (numRPMS && !(interfaceFlags & INSTALL_NODEPS)) {
00431         struct rpmDependencyConflict * conflicts;
00432         if (rpmdepCheck(rpmdep, &conflicts, &numConflicts)) {
00433             numFailed = numPkgs;
00434             stopInstall = 1;
00435         }
00436 
00437         if (!stopInstall && conflicts) {
00438             rpmMessage(RPMMESS_ERROR, _("failed dependencies:\n"));
00439             printDepProblems(stderr, conflicts, numConflicts);
00440             rpmdepFreeConflicts(conflicts, numConflicts);
00441             numFailed = numPkgs;
00442             stopInstall = 1;
00443         }
00444     }
00445 
00446     if (numRPMS && !(interfaceFlags & INSTALL_NOORDER)) {
00447         if (rpmdepOrder(rpmdep)) {
00448             numFailed = numPkgs;
00449             stopInstall = 1;
00450         }
00451     }
00452 
00453     if (numRPMS && !stopInstall) {
00454         rpmProblemSet probs = NULL;
00455 
00456 #ifdef FANCY_HASH
00457        packagesTotal = numRPMS;
00458 #endif
00459         rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
00460         rc = rpmRunTransactions(rpmdep, showProgress, (void *) ((long)notifyFlags), 
00461                                     NULL, &probs, transFlags, probFilter);
00462 
00463         if (rc < 0) {
00464             numFailed += numRPMS;
00465         } else if (rc > 0) {
00466             numFailed += rc;
00467             rpmProblemSetPrint(stderr, probs);
00468         }
00469 
00470         if (probs) rpmProblemSetFree(probs);
00471     }
00472 
00473     if (numRPMS && rpmdep) rpmtransFree(rpmdep);
00474 
00475     if (numSRPMS && !stopInstall) {
00476         for (i = 0; i < numSRPMS; i++) {
00477             fd = Fopen(sourceURL[i], "r.ufdio");
00478             if (fd == NULL || Ferror(fd)) {
00479                 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"), 
00480                            sourceURL[i], Fstrerror(fd));
00481                 if (fd) Fclose(fd);
00482                 continue;
00483             }
00484 
00485             if (!(transFlags & RPMTRANS_FLAG_TEST))
00486                 numFailed += rpmInstallSourcePackage(rootdir, fd, NULL,
00487                                 showProgress, (void *) ((long)notifyFlags), NULL);
00488 
00489             Fclose(fd);
00490         }
00491     }
00492 
00493     for (i = 0; i < numTmpPkgs; i++) {
00494         Unlink(tmppkgURL[i]);
00495         free((void *)tmppkgURL[i]);
00496     }
00497     free((void *)tmppkgURL);    tmppkgURL = NULL;
00498     free((void *)pkgURL);       pkgURL = NULL;
00499 
00500     /* FIXME how do we close our various fd's? */
00501 
00502     if (dbIsOpen) rpmdbClose(db);
00503 
00504     return numFailed;
00505 
00506 errxit:
00507     if (numRPMS && rpmdep) rpmtransFree(rpmdep);
00508     if (tmppkgURL) {
00509         for (i = 0; i < numTmpPkgs; i++)
00510             free((void *)tmppkgURL[i]);
00511         free((void *)tmppkgURL);
00512     }
00513     if (pkgURL)
00514         free((void *)pkgURL);
00515     if (dbIsOpen) rpmdbClose(db);
00516     return numPkgs;
00517 }
00518 
00519 int rpmErase(const char * rootdir, const char ** argv,
00520                 rpmtransFlags transFlags, 
00521                 rpmEraseInterfaceFlags interfaceFlags)
00522 {
00523     rpmdb db;
00524     int mode;
00525     int count;
00526     const char ** arg;
00527     int numFailed = 0;
00528     rpmTransactionSet rpmdep;
00529     struct rpmDependencyConflict * conflicts;
00530     int numConflicts;
00531     int stopUninstall = 0;
00532     int numPackages = 0;
00533     rpmProblemSet probs;
00534 
00535     if (transFlags & RPMTRANS_FLAG_TEST) 
00536         mode = O_RDONLY;
00537     else
00538         mode = O_RDWR | O_EXCL;
00539         
00540     if (rpmdbOpen(rootdir, &db, mode, 0644)) {
00541         const char *dn;
00542         dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
00543         rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
00544         free((void *)dn);
00545         return -1;
00546     }
00547 
00548     rpmdep = rpmtransCreateSet(db, rootdir);
00549     for (arg = argv; *arg; arg++) {
00550         rpmdbMatchIterator mi;
00551 
00552         /* XXX HACK to get rpmdbFindByLabel out of the API */
00553         mi = rpmdbInitIterator(db, RPMDBI_LABEL, *arg, 0);
00554         count = rpmdbGetIteratorCount(mi);
00555         if (count <= 0) {
00556             rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
00557             numFailed++;
00558         } else if (!(count == 1 || (interfaceFlags & UNINSTALL_ALLMATCHES))) {
00559             rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
00560                         *arg);
00561             numFailed++;
00562         } else {
00563             Header h;   /* XXX iterator owns the reference */
00564             while ((h = rpmdbNextIterator(mi)) != NULL) {
00565                 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
00566                 if (recOffset) {
00567                     rpmtransRemovePackage(rpmdep, recOffset);
00568                     numPackages++;
00569                 }
00570             }
00571         }
00572         rpmdbFreeIterator(mi);
00573     }
00574 
00575     if (!(interfaceFlags & UNINSTALL_NODEPS)) {
00576         if (rpmdepCheck(rpmdep, &conflicts, &numConflicts)) {
00577             numFailed = numPackages;
00578             stopUninstall = 1;
00579         }
00580 
00581         if (!stopUninstall && conflicts) {
00582             rpmMessage(RPMMESS_ERROR, _("removing these packages would break "
00583                               "dependencies:\n"));
00584             printDepProblems(stderr, conflicts, numConflicts);
00585             rpmdepFreeConflicts(conflicts, numConflicts);
00586             numFailed += numPackages;
00587             stopUninstall = 1;
00588         }
00589     }
00590 
00591     if (!stopUninstall) {
00592         numFailed += rpmRunTransactions(rpmdep, NULL, NULL, NULL, &probs,
00593                                         transFlags, 0);
00594     }
00595 
00596     rpmtransFree(rpmdep);
00597     rpmdbClose(db);
00598 
00599     return numFailed;
00600 }
00601 
00602 int rpmInstallSource(const char * rootdir, const char * arg,
00603                 const char ** specFile, char ** cookie)
00604 {
00605     FD_t fd;
00606     int rc;
00607 
00608     fd = Fopen(arg, "r.ufdio");
00609     if (fd == NULL || Ferror(fd)) {
00610         rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
00611         if (fd) Fclose(fd);
00612         return 1;
00613     }
00614 
00615     if (rpmIsVerbose())
00616         fprintf(stdout, _("Installing %s\n"), arg);
00617 
00618     rc = rpmInstallSourcePackage(rootdir, fd, specFile, NULL, NULL, 
00619                                  cookie);
00620     if (rc == 1) {
00621         rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
00622         if (specFile && *specFile) {
00623             free((void *)*specFile);
00624             *specFile = NULL;
00625         }
00626         if (cookie && *cookie) {
00627             free(*cookie);
00628             *cookie = NULL;
00629         }
00630     }
00631 
00632     Fclose(fd);
00633 
00634     return rc;
00635 }

Generated at Sun Apr 8 18:43:00 2001 for rpm by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000