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