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/rpmlib.h>
16 #include <rpm/rpmts.h>
17 #include <rpm/rpmmacro.h>
23 RpmHead *rpmhead; /* header storage space */
24 unsigned int rpmheadsize;
26 int dbenvopened; /* database environment opened */
27 const char *dbpath; /* path to the database */
28 int dbpath_allocated; /* do we need to free the path? */
31 rpmdbMatchIterator mi; /* iterator over packages database */
35 access_rootdir(struct rpmdbstate *state, const char *dir, int mode)
39 char *path = solv_dupjoin(state->rootdir, dir, 0);
40 int r = access(path, mode);
44 return access(dir, mode);
48 detect_dbpath(struct rpmdbstate *state)
50 state->dbpath = rpmExpand("%{?_dbpath}", NULL);
51 if (state->dbpath && *state->dbpath)
53 state->dbpath_allocated = 1;
56 solv_free((char *)state->dbpath);
57 state->dbpath = access_rootdir(state, "/var/lib/rpm", W_OK) == -1
58 && (access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 || access_rootdir(state, "/usr/share/rpm/rpmdb.sqlite", R_OK) == 0)
59 ? "/usr/share/rpm" : "/var/lib/rpm";
63 stat_database(struct rpmdbstate *state, struct stat *statbuf)
65 static const char *dbname[] = {
70 "/Packages", /* for error reporting */
75 #ifdef HAVE_RPMDBFSTAT
76 if (state->dbenvopened == 1)
77 return rpmdbFStat(rpmtsGetRdb(state->ts), statbuf);
83 char *dbpath = solv_dupjoin(state->rootdir, state->dbpath, dbname[i]);
84 if (!stat(dbpath, statbuf))
89 if (errno != ENOENT || !dbname[i + 1])
91 int saved_errno = errno;
92 pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
102 /* rpm-4.16.0 cannot read the database if _db_backend is not set */
103 #ifndef HAVE_RPMDBNEXTITERATORHEADERBLOB
107 static int db_backend_set;
113 db_backend = rpmExpand("%{?_db_backend}", NULL);
114 if (!db_backend || !*db_backend)
115 rpmReadConfigFiles(NULL, NULL);
116 solv_free(db_backend);
121 opendbenv(struct rpmdbstate *state)
127 detect_dbpath(state);
128 dbpath = solv_dupjoin("_dbpath ", state->rootdir, state->dbpath);
129 rpmDefineMacro(NULL, dbpath, 0);
134 pool_error(state->pool, 0, "rpmtsCreate failed");
135 delMacro(NULL, "_dbpath");
138 #ifndef HAVE_RPMDBNEXTITERATORHEADERBLOB
139 if (!strcmp(RPMVERSION, "4.16.0"))
142 if (rpmtsOpenDB(ts, O_RDONLY))
144 pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
146 delMacro(NULL, "_dbpath");
149 delMacro(NULL, "_dbpath");
150 rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
152 state->dbenvopened = 1;
157 closedbenv(struct rpmdbstate *state)
160 rpmtsFree(state->ts);
162 state->dbenvopened = 0;
165 /* get the rpmdbids of all installed packages from the Name index database.
166 * This is much faster then querying the big Packages database */
167 static struct rpmdbentry *
168 getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
171 size_t keylen, matchl = 0;
176 struct rpmdbentry *entries = 0;
179 rpmdbIndexIterator ii;
185 if (state->dbenvopened != 1 && !opendbenv(state))
189 matchl = strlen(match);
190 ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
192 while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
194 unsigned int i, npkgs;
197 if (keylen != matchl || memcmp(key, match, keylen) != 0)
200 else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
205 namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
206 memcpy(namedata + namedatal, key, keylen);
207 namedata[namedatal + keylen] = 0;
208 namedatal += keylen + 1;
210 npkgs = rpmdbIndexIteratorNumPkgs(ii);
211 for (i = 0; i < npkgs; i++)
213 entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
214 entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
215 entries[nentries].nameoff = nameoff;
219 rpmdbIndexIteratorFree(ii);
220 /* make sure that enteries is != 0 if there was no error */
222 entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
223 *nentriesp = nentries;
225 *namedatap = namedata;
229 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
230 static int headfromhdrblob(struct rpmdbstate *state, const unsigned char *data, unsigned int size);
233 /* retrive header by rpmdbid, returns 0 if not found, -1 on error */
235 getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
237 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
238 const unsigned char *uh;
243 rpmdbMatchIterator mi;
244 unsigned int offset = rpmdbid;
247 return pool_error(state->pool, -1, "illegal rpmdbid %d", rpmdbid);
248 if (state->dbenvopened != 1 && !opendbenv(state))
250 mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, &offset, sizeof(offset));
251 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
252 uh = rpmdbNextIteratorHeaderBlob(mi, &uhlen);
255 rpmdbFreeIterator(mi);
258 if (!headfromhdrblob(state, uh, uhlen))
260 rpmdbFreeIterator(mi);
264 h = rpmdbNextIterator(mi);
267 rpmdbFreeIterator(mi);
270 if (!rpm_byrpmh(state, h))
272 rpmdbFreeIterator(mi);
276 mi = rpmdbFreeIterator(mi);
281 count_headers(struct rpmdbstate *state)
284 rpmdbMatchIterator mi;
286 if (state->dbenvopened != 1 && !opendbenv(state))
288 mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_NAME, NULL, 0);
289 count = rpmdbGetIteratorCount(mi);
290 rpmdbFreeIterator(mi);
295 pkgdb_cursor_open(struct rpmdbstate *state)
297 state->mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, NULL, 0);
302 pkgdb_cursor_close(struct rpmdbstate *state)
304 rpmdbFreeIterator(state->mi);
309 pkgdb_cursor_getrpm(struct rpmdbstate *state)
311 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
312 const unsigned char *uh;
314 while ((uh = rpmdbNextIteratorHeaderBlob(state->mi, &uhlen)) != 0)
316 Id dbid = rpmdbGetIteratorOffset(state->mi);
317 if (!headfromhdrblob(state, uh, uhlen))
323 while ((h = rpmdbNextIterator(state->mi)))
325 Id dbid = rpmdbGetIteratorOffset(state->mi);
326 if (!rpm_byrpmh(state, h))
335 hash_name_index(struct rpmdbstate *state, Chksum *chk)
337 rpmdbIndexIterator ii;
341 if (state->dbenvopened != 1 && !opendbenv(state))
343 ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
346 while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
348 unsigned int i, npkgs = rpmdbIndexIteratorNumPkgs(ii);
349 solv_chksum_add(chk, key, (int)keylen);
350 for (i = 0; i < npkgs; i++)
352 unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i);
353 solv_chksum_add(chk, &offset, sizeof(offset));
356 rpmdbIndexIteratorFree(ii);