00001
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <unistd.h>
00008 #include <fcntl.h>
00009 #include <string.h>
00010
00011 #include <glob.h>
00012 #include <dirent.h>
00013
00014 #include <rpmlib.h>
00015
00016 #include "hash.h"
00017 #include "upgrade.h"
00018
00019 #define MAXPKGS 1024
00020
00021 #define USEDEBUG 0
00022
00023 #define DEBUG(x) { \
00024 if (USEDEBUG) \
00025 printf x; \
00026 }
00027
00028 #if 0
00029 static void printMemStats(char *mess)
00030 {
00031 char buf[1024];
00032 printf("%s\n", mess);
00033 sprintf(buf, "cat /proc/%d/status | grep VmSize", getpid());
00034 system(buf);
00035 }
00036 #endif
00037
00038 int pkgCompare(void * first, void * second) {
00039 struct packageInfo ** a = first;
00040 struct packageInfo ** b = second;
00041
00042
00043 if (!(*a)->name) return 1;
00044 if (!(*b)->name) return -1;
00045
00046 return xstrcasecmp((*a)->name, (*b)->name);
00047 }
00048
00049
00050
00051
00052 static void compareFileList(int availFileCount, char **availBaseNames,
00053 char ** availDirNames, int * availDirIndexes,
00054 int instFileCount, char **instBaseNames,
00055 char ** instDirNames, int * instDirIndexes,
00056 struct hash_table *ht)
00057 {
00058 int installedX, availX, rc;
00059 char * availDir, * availBase;
00060 char * instDir, * instBase;
00061 static int i = 0;
00062
00063 availX = 0;
00064 installedX = 0;
00065 while (installedX < instFileCount) {
00066 instBase = instBaseNames[installedX];
00067 instDir = instDirNames[instDirIndexes[installedX]];
00068
00069 if (availX == availFileCount) {
00070
00071 DEBUG(("=> %d: %s%s\n", i++, instDir, instBase))
00072 if (strncmp(instDir, "/etc/rc.d/", 10))
00073 htAddToTable(ht, instDir, instBase);
00074 installedX++;
00075 } else {
00076 availBase = availBaseNames[availX];
00077 availDir = availDirNames[availDirIndexes[availX]];
00078
00079 rc = strcmp(availDir, instDir);
00080 if (!rc)
00081 rc = strcmp(availBase, instBase);
00082
00083 if (rc > 0) {
00084
00085 DEBUG(("=> %d: %s%s\n", i++, instDir, instBase))
00086 if (strncmp(instDir, "/etc/rc.d/", 10))
00087 htAddToTable(ht, instDir, instBase);
00088 installedX++;
00089 } else if (rc < 0) {
00090
00091 availX++;
00092 } else {
00093
00094 availX++;
00095 installedX++;
00096 }
00097 }
00098 }
00099 }
00100
00101 static void addLostFiles(rpmdb db, struct pkgSet *psp, struct hash_table *ht)
00102 {
00103 char *name;
00104 struct packageInfo **pack;
00105 struct packageInfo key;
00106 struct packageInfo *keyaddr = &key;
00107 char **installedFiles;
00108 char **installedDirs;
00109 int_32 * installedDirIndexes;
00110 int installedFileCount;
00111 Header h = NULL;
00112 rpmdbMatchIterator mi;
00113
00114 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
00115 while ((h = rpmdbNextIterator(mi)) != NULL) {
00116
00117 headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00118 if (name && !strcmp(name, "metroess")) {
00119
00120
00121 continue;
00122 }
00123 key.name = name;
00124
00125 pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
00126 sizeof(*psp->packages), (void *)pkgCompare);
00127 if (!pack) {
00128 if (headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00129 (const void **) &installedFiles, &installedFileCount)) {
00130 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00131 (const void **) &installedDirIndexes, NULL);
00132 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00133 (const void **) &installedDirs, NULL);
00134
00135 compareFileList(0, NULL, NULL, NULL, installedFileCount,
00136 installedFiles, installedDirs,
00137 installedDirIndexes, ht);
00138
00139 free(installedFiles);
00140 free(installedDirs);
00141 }
00142 }
00143 }
00144
00145 rpmdbFreeIterator(mi);
00146 }
00147
00148 static int findPackagesWithObsoletes(rpmdb db, struct pkgSet *psp)
00149 {
00150 int count, obsoletesCount;
00151 struct packageInfo **pip;
00152 char **obsoletes;
00153
00154 count = psp->numPackages;
00155 pip = psp->packages;
00156 while (count--) {
00157 if ((*pip)->selected) {
00158 pip++;
00159 continue;
00160 }
00161
00162 if (headerGetEntryMinMemory((*pip)->h, RPMTAG_OBSOLETENAME, NULL,
00163 (const void **) &obsoletes, &obsoletesCount)) {
00164 while (obsoletesCount--) {
00165 if (rpmdbCountPackages(db, obsoletes[obsoletesCount]) > 0) {
00166 (*pip)->selected = 1;
00167 break;
00168 }
00169 }
00170
00171 free(obsoletes);
00172 }
00173
00174 pip++;
00175 }
00176
00177 return 0;
00178 }
00179
00180 static void errorFunction(void)
00181 {
00182 }
00183
00184 static int findUpgradePackages(rpmdb db, struct pkgSet *psp,
00185 struct hash_table *ht)
00186 {
00187 int skipThis;
00188 Header h, installedHeader;
00189 char *name;
00190 int count;
00191 char **installedFiles, **availFiles;
00192 char **installedDirs, ** availDirs;
00193 int_32 * installedDirIndexes, * availDirIndexes;
00194 int installedFileCount, availFileCount;
00195 struct packageInfo **pip;
00196
00197 count = psp->numPackages;
00198 pip = psp->packages;
00199 while (count--) {
00200 h = (*pip)->h;
00201 name = NULL;
00202 headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00203 if (!name) {
00204
00205
00206 return(-1);
00207 }
00208
00209 DEBUG (("Avail: %s\n", name));
00210
00211 { rpmdbMatchIterator mi;
00212
00213 mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00214 skipThis = (mi ? 0 : 1);
00215 rpmErrorSetCallback(errorFunction);
00216 while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
00217 if (rpmVersionCompare(installedHeader, h) >= 0) {
00218
00219 DEBUG (("Already have newer version\n"))
00220 skipThis = 1;
00221 break;
00222 }
00223 }
00224 rpmdbFreeIterator(mi);
00225 rpmErrorSetCallback(NULL);
00226 if (! skipThis) {
00227 DEBUG (("No newer version installed\n"))
00228 }
00229 }
00230
00231 if (skipThis) {
00232 DEBUG (("DO NOT INSTALL\n"))
00233 } else {
00234 DEBUG (("UPGRADE\n"))
00235 (*pip)->selected = 1;
00236
00237 if (!headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00238 (const void **) &availFiles, &availFileCount)) {
00239 availFiles = NULL;
00240 availFileCount = 0;
00241 } else {
00242 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00243 (const void **) &availDirs, NULL);
00244 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00245 (const void **) &availDirIndexes, NULL);
00246 }
00247
00248 { rpmdbMatchIterator mi;
00249 mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00250 while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
00251 if (headerGetEntryMinMemory(installedHeader, RPMTAG_BASENAMES,
00252 NULL, (const void **) &installedFiles,
00253 &installedFileCount)) {
00254 headerGetEntryMinMemory(installedHeader, RPMTAG_DIRNAMES,
00255 NULL, (const void **) &installedDirs, NULL);
00256 headerGetEntryMinMemory(installedHeader, RPMTAG_DIRINDEXES,
00257 NULL, (const void **) &installedDirIndexes, NULL);
00258
00259 compareFileList(availFileCount, availFiles,
00260 availDirs, availDirIndexes,
00261 installedFileCount, installedFiles,
00262 installedDirs, installedDirIndexes,
00263 ht);
00264
00265 free(installedFiles);
00266 free(installedDirs);
00267 }
00268 }
00269 rpmdbFreeIterator(mi);
00270 }
00271
00272 if (availFiles) {
00273 free(availFiles);
00274 free(availDirs);
00275 }
00276 }
00277
00278 DEBUG (("\n\n"))
00279
00280 pip++;
00281 }
00282
00283 return 0;
00284 }
00285
00286 static int removeMovedFilesAlreadyHandled(struct pkgSet *psp,
00287 struct hash_table *ht)
00288 {
00289 char *name;
00290 int i, count;
00291 Header h;
00292 char **availFiles, ** availDirs;
00293 int_32 * availDirIndexes;
00294 int availFileCount;
00295 struct packageInfo **pip;
00296
00297 count = psp->numPackages;
00298 pip = psp->packages;
00299 while (count--) {
00300 h = (*pip)->h;
00301 if ((*pip)->selected) {
00302 name = NULL;
00303 headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00304
00305 if (headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00306 (const void **) &availFiles, &availFileCount)) {
00307
00308 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00309 (const void **) &availDirs, NULL);
00310 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00311 (const void **) &availDirIndexes, NULL);
00312
00313 for (i = 0; i < availFileCount; i++) {
00314 if (htInTable(ht, availDirs[availDirIndexes[i]],
00315 availFiles[i])) {
00316 htRemoveFromTable(ht, availDirs[availDirIndexes[i]],
00317 availFiles[i]);
00318 DEBUG (("File already in %s: %s%s\n", name,
00319 availDirs[availDirIndexes[i]], availFiles[i]))
00320 break;
00321 }
00322 }
00323
00324 free(availFiles);
00325 free(availDirs);
00326 }
00327 }
00328
00329 pip++;
00330 }
00331
00332 return 0;
00333 }
00334
00335 static int findPackagesWithRelocatedFiles(struct pkgSet *psp,
00336 struct hash_table *ht)
00337 {
00338 char *name;
00339 int i, count;
00340 Header h;
00341 char **availFiles, **availDirs;
00342 int_32 * availDirIndexes;
00343 int availFileCount;
00344 struct packageInfo **pip;
00345 int_16 * availFileModes;
00346
00347 count = psp->numPackages;
00348 pip = psp->packages;
00349 while (count--) {
00350 h = (*pip)->h;
00351 if (! (*pip)->selected) {
00352 name = NULL;
00353 headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00354
00355 if (headerGetEntry(h, RPMTAG_BASENAMES, NULL,
00356 (void **) &availFiles, &availFileCount)) {
00357 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00358 (const void **) &availDirs, NULL);
00359 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00360 (const void **) &availDirIndexes, NULL);
00361 headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL,
00362 (const void **) &availFileModes, NULL);
00363
00364 for (i = 0; i < availFileCount; i++) {
00365 if (S_ISDIR(availFileModes[i])) continue;
00366
00367 if (htInTable(ht, availDirs[availDirIndexes[i]],
00368 availFiles[i])) {
00369 htRemoveFromTable(ht, availDirs[availDirIndexes[i]],
00370 availFiles[i]);
00371 DEBUG (("Found file in %s: %s%s\n", name,
00372 availDirs[availDirIndexes[i]], availFiles[i]))
00373 (*pip)->selected = 1;
00374 }
00375 }
00376 free(availFiles);
00377 free(availDirs);
00378 }
00379 }
00380
00381 pip++;
00382 }
00383
00384 return 0;
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 static int unmarkPackagesAlreadyInstalled(rpmdb db, struct pkgSet *psp)
00407 {
00408 Header h, installedHeader;
00409 char *name;
00410 struct packageInfo **pip;
00411 int count;
00412
00413 count = psp->numPackages;
00414 pip = psp->packages;
00415 while (count--) {
00416 if ((*pip)->selected) {
00417 h = (*pip)->h;
00418
00419 name = NULL;
00420 headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00421 if (!name) {
00422
00423
00424 return(-1);
00425 }
00426 { rpmdbMatchIterator mi;
00427
00428 mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00429 rpmErrorSetCallback(errorFunction);
00430 while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
00431 if (rpmVersionCompare(installedHeader, h) >= 0) {
00432
00433 DEBUG (("Already have newer version\n"))
00434 (*pip)->selected = 0;
00435 break;
00436 }
00437 }
00438 rpmdbFreeIterator(mi);
00439 rpmErrorSetCallback(NULL);
00440 }
00441 }
00442
00443 pip++;
00444 }
00445
00446 return 0;
00447 }
00448
00449 static void emptyErrorCallback(void) {
00450 }
00451
00452 int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot)
00453 {
00454 rpmdb db;
00455 struct hash_table *hashTable;
00456 rpmErrorCallBackType old;
00457
00458
00459
00460
00461
00462 rpmSetVerbosity(RPMMESS_FATALERROR);
00463 old = rpmErrorSetCallback(emptyErrorCallback);
00464
00465 if (rpmdbOpen(installRoot, &db, O_RDONLY, 0644)) {
00466
00467
00468 return(-1);
00469 }
00470
00471 rpmErrorSetCallback(old);
00472 rpmSetVerbosity(RPMMESS_NORMAL);
00473
00474 hashTable = htNewTable(1103);
00475
00476
00477
00478 addLostFiles(db, psp, hashTable);
00479
00480
00481
00482
00483
00484
00485 if (findUpgradePackages(db, psp, hashTable)) {
00486 rpmdbClose(db);
00487 return(-1);
00488 }
00489
00490
00491
00492
00493
00494
00495 removeMovedFilesAlreadyHandled(psp, hashTable);
00496
00497
00498
00499 findPackagesWithRelocatedFiles(psp, hashTable);
00500
00501
00502
00503 findPackagesWithObsoletes(db, psp);
00504
00505
00506
00507 unmarkPackagesAlreadyInstalled(db, psp);
00508
00509
00510
00511 htFreeHashTable(hashTable);
00512
00513
00514
00515 rpmdbClose(db);
00516
00517 return 0;
00518 }