#include "config.h" #include #include #include #include #include /* for mkdir(2) !?! */ #include #if HAVE_ALLOCA_H #include #endif #include "messages.h" #include "rpmdb.h" #include "rpmlib.h" int rpmdbRebuild(char * rootdir) { rpmdb olddb, newdb; char * dbpath, * newdbpath; int recnum; Header h; int failed = 0; rpmMessage(RPMMESS_DEBUG, "rebuilding database in rootdir %s\n", rootdir); dbpath = rpmGetVar(RPMVAR_DBPATH); if (!dbpath) { rpmMessage(RPMMESS_DEBUG, "no dbpath has been set"); return 1; } newdbpath = alloca(strlen(dbpath) + 50 + strlen(rootdir)); sprintf(newdbpath, "%s/%s/rebuilddb.%d", rootdir, dbpath, (int) getpid()); if (!access(newdbpath, F_OK)) { rpmError(RPMERR_MKDIR, "temporary database %s already exists", newdbpath); } rpmMessage(RPMMESS_DEBUG, "creating directory: %s\n", newdbpath); if (mkdir(newdbpath, 0755)) { rpmError(RPMERR_MKDIR, "error creating directory %s: %s", newdbpath, strerror(errno)); } sprintf(newdbpath, "%s/rebuilddb.%d", dbpath, (int) getpid()); rpmMessage(RPMMESS_DEBUG, "opening old database\n"); if (openDatabase(rootdir, dbpath, &olddb, O_RDONLY, 0644, 0)) { return 1; } rpmMessage(RPMMESS_DEBUG, "opening new database\n"); if (openDatabase(rootdir, newdbpath, &newdb, O_RDWR | O_CREAT, 0644, 0)) { return 1; } recnum = rpmdbFirstRecNum(olddb); while (recnum > 0) { if (!(h = rpmdbGetRecord(olddb, recnum))) { rpmError(RPMERR_INTERNAL, "cannot read database record at %d", recnum); failed = 1; break; } /* let's sanity check this record a bit, otherwise just skip it */ if (headerIsEntry(h, RPMTAG_NAME) && headerIsEntry(h, RPMTAG_VERSION) && headerIsEntry(h, RPMTAG_RELEASE) && headerIsEntry(h, RPMTAG_RELEASE) && headerIsEntry(h, RPMTAG_BUILDTIME)) { if (rpmdbAdd(newdb, h)) { rpmError(RPMERR_INTERNAL, "cannot add record originally at %d", recnum); failed = 1; break; } } else { rpmError(RPMERR_INTERNAL, "record number %d in database is bad " "-- skipping it", recnum); } recnum = rpmdbNextRecNum(olddb, recnum); } rpmdbClose(olddb); rpmdbClose(newdb); if (failed) { rpmMessage(RPMMESS_NORMAL, "failed to rebuild database; original database " "remains in place\n"); rpmdbRemoveDatabase(rootdir, newdbpath); return 1; } else { if (rpmdbMoveDatabase(rootdir, newdbpath, dbpath)) { rpmMessage(RPMMESS_ERROR, "failed to replace old database with new " "database!\n"); rpmMessage(RPMMESS_ERROR, "replaces files in %s with files from %s " "to recover", dbpath, newdbpath); return 1; } rmdir(newdbpath); } return 0; }