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 */
25 int dbenvopened; /* database environment opened */
26 int is_ostree; /* read-only db that lives in /usr/share/rpm */
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_ostree(struct rpmdbstate *state)
48 state->is_ostree = access_rootdir(state, "/var/lib/rpm", W_OK) == -1 &&
49 access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 ? 1 : -1;
53 stat_database(struct rpmdbstate *state, struct stat *statbuf)
55 static const char *dbname[] = {
60 "Packages", /* for error reporting */
65 #ifdef HAVE_RPMDBFSTAT
66 if (state->dbenvopened == 1)
67 return rpmdbFStat(rpmtsGetRdb(state->ts), statbuf);
69 if (!state->is_ostree)
73 char *dbpath = solv_dupjoin(state->rootdir, state->is_ostree > 0 ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname[i]);
74 if (!stat(dbpath, statbuf))
79 if (errno != ENOENT || !dbname[i + 1])
81 int saved_errno = errno;
82 pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
93 opendbenv(struct rpmdbstate *state)
95 const char *rootdir = state->rootdir;
99 dbpath = solv_dupjoin("_dbpath ", rootdir, state->is_ostree > 0 ? "/usr/share/rpm" : "/var/lib/rpm");
100 rpmDefineMacro(NULL, dbpath, 0);
105 pool_error(state->pool, 0, "rpmtsCreate failed");
106 delMacro(NULL, "_dbpath");
109 if (rpmtsOpenDB(ts, O_RDONLY))
111 pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
113 delMacro(NULL, "_dbpath");
116 delMacro(NULL, "_dbpath");
117 rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
119 state->dbenvopened = 1;
124 closedbenv(struct rpmdbstate *state)
127 rpmtsFree(state->ts);
129 state->dbenvopened = 0;
132 /* get the rpmdbids of all installed packages from the Name index database.
133 * This is much faster then querying the big Packages database */
134 static struct rpmdbentry *
135 getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
138 size_t keylen, matchl = 0;
143 struct rpmdbentry *entries = 0;
146 rpmdbIndexIterator ii;
152 if (state->dbenvopened != 1 && !opendbenv(state))
156 matchl = strlen(match);
157 ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
159 while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
161 unsigned int i, npkgs;
164 if (keylen != matchl || memcmp(key, match, keylen) != 0)
167 else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
172 namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
173 memcpy(namedata + namedatal, key, keylen);
174 namedata[namedatal + keylen] = 0;
175 namedatal += keylen + 1;
177 npkgs = rpmdbIndexIteratorNumPkgs(ii);
178 for (i = 0; i < npkgs; i++)
180 entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
181 entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
182 entries[nentries].nameoff = nameoff;
186 rpmdbIndexIteratorFree(ii);
187 /* make sure that enteries is != 0 if there was no error */
189 entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
190 *nentriesp = nentries;
192 *namedatap = namedata;
196 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
198 rpm_byrpmhdrblob(struct rpmdbstate *state, const unsigned char *data, unsigned int size)
200 unsigned int dsize, cnt, len;
203 return pool_error(state->pool, 0, "corrupt rpm database (size)");
205 dsize = getu32(data + 4);
206 if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
207 return pool_error(state->pool, 0, "corrupt rpm database (cnt/dcnt)");
208 if (8 + cnt * 16 + dsize > size)
209 return pool_error(state->pool, 0, "corrupt rpm database (data size)");
210 len = 16 * cnt + dsize;
211 if (len + 1 > state->rpmheadsize)
213 state->rpmheadsize = len + 128;
214 state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
216 rpmhead = state->rpmhead;
217 memcpy(rpmhead->data, data + 8, len);
218 rpmhead->data[len] = 0;
220 rpmhead->dcnt = dsize;
221 rpmhead->dp = rpmhead->data + cnt * 16;
226 /* retrive header by rpmdbid, returns 0 if not found, -1 on error */
228 getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
230 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
231 const unsigned char *uh;
236 rpmdbMatchIterator mi;
237 unsigned int offset = rpmdbid;
240 return pool_error(state->pool, -1, "illegal rpmdbid %d", rpmdbid);
241 if (state->dbenvopened != 1 && !opendbenv(state))
243 mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, &offset, sizeof(offset));
244 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
245 uh = rpmdbNextIteratorHeaderBlob(mi, &uhlen);
248 rpmdbFreeIterator(mi);
251 if (!rpm_byrpmhdrblob(state, uh, uhlen))
253 rpmdbFreeIterator(mi);
257 h = rpmdbNextIterator(mi);
260 rpmdbFreeIterator(mi);
263 if (!rpm_byrpmh(state, h))
265 rpmdbFreeIterator(mi);
269 mi = rpmdbFreeIterator(mi);
274 count_headers(struct rpmdbstate *state)
277 rpmdbMatchIterator mi;
279 if (state->dbenvopened != 1 && !opendbenv(state))
281 mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_NAME, NULL, 0);
282 count = rpmdbGetIteratorCount(mi);
283 rpmdbFreeIterator(mi);
288 pkgdb_cursor_open(struct rpmdbstate *state)
290 state->mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, NULL, 0);
295 pkgdb_cursor_close(struct rpmdbstate *state)
297 rpmdbFreeIterator(state->mi);
302 pkgdb_cursor_getrpm(struct rpmdbstate *state)
304 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
305 const unsigned char *uh;
307 while ((uh = rpmdbNextIteratorHeaderBlob(state->mi, &uhlen)) != 0)
309 Id dbid = rpmdbGetIteratorOffset(state->mi);
310 if (!rpm_byrpmhdrblob(state, uh, uhlen))
316 while ((h = rpmdbNextIterator(state->mi)))
318 Id dbid = rpmdbGetIteratorOffset(state->mi);
319 if (!rpm_byrpmh(state, h))
328 hash_name_index(struct rpmdbstate *state, Chksum *chk)
330 rpmdbIndexIterator ii;
334 if (state->dbenvopened != 1 && !opendbenv(state))
336 ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
339 while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
341 unsigned int i, npkgs = rpmdbIndexIteratorNumPkgs(ii);
342 solv_chksum_add(chk, key, (int)keylen);
343 for (i = 0; i < npkgs; i++)
345 unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i);
346 solv_chksum_add(chk, &offset, sizeof(offset));
349 rpmdbIndexIteratorFree(ii);