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