summaryrefslogtreecommitdiff
path: root/lib/rebuilddb.c
blob: 70b79750e5afd48fba57136a0cdabe8a9e66e00d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "system.h"

#include "rpmlib.h"

#include "rpmdb.h"

int rpmdbRebuild(const char * rootdir) {
    rpmdb olddb, newdb;
    const char * dbpath = NULL;
    const char * newdbpath = NULL;
    int recnum; 
    Header h;
    int failed = 0;
    int rc = 0;
    char tfn[64];

    rpmMessage(RPMMESS_DEBUG, _("rebuilding database in rootdir %s\n"), rootdir);

    dbpath = rpmGetPath("%{_dbpath}", NULL);
    if (!dbpath || dbpath[0] == '%') {
	rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
	return 1;
    }

    sprintf(tfn, "rebuilddb.%d", (int) getpid());
    newdbpath = rpmGetPath(rootdir, dbpath, tfn, NULL);

    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));
    }

    /* XXX WTFO? */
    xfree(newdbpath);
    newdbpath = rpmGetPath(dbpath, tfn, NULL);

    rpmMessage(RPMMESS_DEBUG, _("opening old database\n"));
    if (openDatabase(rootdir, dbpath, &olddb, O_RDONLY, 0644, 
		     RPMDB_FLAG_MINIMAL)) {
	rc = 1;
	goto exit;
    }

    rpmMessage(RPMMESS_DEBUG, _("opening new database\n"));
    if (openDatabase(rootdir, newdbpath, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
	rc = 1;
	goto exit;
    }

    recnum = rpmdbFirstRecNum(olddb);
    while (recnum > 0) {
	if ((h = rpmdbGetRecord(olddb, recnum)) == NULL) {
	    rpmError(RPMERR_INTERNAL,
			_("record number %d in database is bad -- skipping it"),
			recnum);
	    break;
	} else {
	    /* 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);
	rc = 1;
	goto exit;
    } 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);
	    rc = 1;
	    goto exit;
	}
	if (rmdir(newdbpath))
	    rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
			newdbpath, strerror(errno));
    }
    rc = 0;

exit:
    if (dbpath)		xfree(dbpath);
    if (newdbpath)	xfree(newdbpath);

    return rc;
}