summaryrefslogtreecommitdiff
path: root/lib/rebuilddb.c
blob: e359141b830300719f55be8939e08ad27c85d2a5 (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
#include "config.h"

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>	/* for mkdir(2) !?! */
#include <unistd.h>

#if HAVE_ALLOCA_H
#include <alloca.h>
#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;
}