2 * Copyright (c) 2018, SUSE Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Use librpm to access the rpm database
15 #include <rpm/rpmts.h>
16 #include <rpm/rpmmacro.h>
22 RpmHead *rpmhead; /* header storage space */
23 unsigned int rpmheadsize;
25 int dbenvopened; /* database environment opened */
26 const char *dbpath; /* path to the database */
29 rpmdbMatchIterator mi; /* iterator over packages database */
33 access_rootdir(struct rpmdbstate *state, const char *dir, int mode)
37 char *path = solv_dupjoin(state->rootdir, dir, 0);
38 int r = access(path, mode);
42 return access(dir, mode);
46 detect_dbpath(struct rpmdbstate *state)
48 state->dbpath = access_rootdir(state, "/var/lib/rpm", W_OK) == -1
49 && (access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 || access_rootdir(state, "/usr/share/rpm/rpmdb.sqlite", R_OK) == 0)
50 ? "/usr/share/rpm" : "/var/lib/rpm";
54 stat_database(struct rpmdbstate *state, struct stat *statbuf)
56 static const char *dbname[] = {
61 "/Packages", /* for error reporting */
66 #ifdef HAVE_RPMDBFSTAT
67 if (state->dbenvopened == 1)
68 return rpmdbFStat(rpmtsGetRdb(state->ts), statbuf);
74 char *dbpath = solv_dupjoin(state->rootdir, state->dbpath, dbname[i]);
75 if (!stat(dbpath, statbuf))
80 if (errno != ENOENT || !dbname[i + 1])
82 int saved_errno = errno;
83 pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
94 opendbenv(struct rpmdbstate *state)
100 detect_dbpath(state);
101 dbpath = solv_dupjoin("_dbpath ", state->rootdir, state->dbpath);
102 rpmDefineMacro(NULL, dbpath, 0);
107 pool_error(state->pool, 0, "rpmtsCreate failed");
108 delMacro(NULL, "_dbpath");
111 if (rpmtsOpenDB(ts, O_RDONLY))
113 pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
115 delMacro(NULL, "_dbpath");
118 delMacro(NULL, "_dbpath");
119 rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
121 state->dbenvopened = 1;
126 closedbenv(struct rpmdbstate *state)
129 rpmtsFree(state->ts);
131 state->dbenvopened = 0;
134 /* get the rpmdbids of all installed packages from the Name index database.
135 * This is much faster then querying the big Packages database */
136 static struct rpmdbentry *
137 getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
140 size_t keylen, matchl = 0;
145 struct rpmdbentry *entries = 0;
148 rpmdbIndexIterator ii;
154 if (state->dbenvopened != 1 && !opendbenv(state))
158 matchl = strlen(match);
159 ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
161 while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
163 unsigned int i, npkgs;
166 if (keylen != matchl || memcmp(key, match, keylen) != 0)
169 else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
174 namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
175 memcpy(namedata + namedatal, key, keylen);
176 namedata[namedatal + keylen] = 0;
177 namedatal += keylen + 1;
179 npkgs = rpmdbIndexIteratorNumPkgs(ii);
180 for (i = 0; i < npkgs; i++)
182 entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
183 entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
184 entries[nentries].nameoff = nameoff;
188 rpmdbIndexIteratorFree(ii);
189 /* make sure that enteries is != 0 if there was no error */
191 entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
192 *nentriesp = nentries;
194 *namedatap = namedata;
198 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
199 static int headfromhdrblob(struct rpmdbstate *state, const unsigned char *data, unsigned int size);
202 /* retrive header by rpmdbid, returns 0 if not found, -1 on error */
204 getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
206 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
207 const unsigned char *uh;
212 rpmdbMatchIterator mi;
213 unsigned int offset = rpmdbid;
216 return pool_error(state->pool, -1, "illegal rpmdbid %d", rpmdbid);
217 if (state->dbenvopened != 1 && !opendbenv(state))
219 mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, &offset, sizeof(offset));
220 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
221 uh = rpmdbNextIteratorHeaderBlob(mi, &uhlen);
224 rpmdbFreeIterator(mi);
227 if (!headfromhdrblob(state, uh, uhlen))
229 rpmdbFreeIterator(mi);
233 h = rpmdbNextIterator(mi);
236 rpmdbFreeIterator(mi);
239 if (!rpm_byrpmh(state, h))
241 rpmdbFreeIterator(mi);
245 mi = rpmdbFreeIterator(mi);
250 count_headers(struct rpmdbstate *state)
253 rpmdbMatchIterator mi;
255 if (state->dbenvopened != 1 && !opendbenv(state))
257 mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_NAME, NULL, 0);
258 count = rpmdbGetIteratorCount(mi);
259 rpmdbFreeIterator(mi);
264 pkgdb_cursor_open(struct rpmdbstate *state)
266 state->mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, NULL, 0);
271 pkgdb_cursor_close(struct rpmdbstate *state)
273 rpmdbFreeIterator(state->mi);
278 pkgdb_cursor_getrpm(struct rpmdbstate *state)
280 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
281 const unsigned char *uh;
283 while ((uh = rpmdbNextIteratorHeaderBlob(state->mi, &uhlen)) != 0)
285 Id dbid = rpmdbGetIteratorOffset(state->mi);
286 if (!headfromhdrblob(state, uh, uhlen))
292 while ((h = rpmdbNextIterator(state->mi)))
294 Id dbid = rpmdbGetIteratorOffset(state->mi);
295 if (!rpm_byrpmh(state, h))
304 hash_name_index(struct rpmdbstate *state, Chksum *chk)
306 rpmdbIndexIterator ii;
310 if (state->dbenvopened != 1 && !opendbenv(state))
312 ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
315 while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
317 unsigned int i, npkgs = rpmdbIndexIteratorNumPkgs(ii);
318 solv_chksum_add(chk, key, (int)keylen);
319 for (i = 0; i < npkgs; i++)
321 unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i);
322 solv_chksum_add(chk, &offset, sizeof(offset));
325 rpmdbIndexIteratorFree(ii);