Imported Upstream version 0.7.14
[platform/upstream/libsolv.git] / ext / repo_rpmdb_librpm.h
1 /*
2  * Copyright (c) 2018, SUSE Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * repo_rpmdb_librpm.h
10  *
11  * Use librpm to access the rpm database
12  *
13  */
14
15 #include <rpm/rpmts.h>
16 #include <rpm/rpmmacro.h>
17
18 struct rpmdbstate {
19   Pool *pool;
20   char *rootdir;
21
22   RpmHead *rpmhead;     /* header storage space */
23   unsigned int rpmheadsize;
24
25   int dbenvopened;      /* database environment opened */
26   const char *dbpath;   /* path to the database */
27
28   rpmts ts;
29   rpmdbMatchIterator mi;        /* iterator over packages database */
30 };
31
32 static inline int
33 access_rootdir(struct rpmdbstate *state, const char *dir, int mode)
34 {
35   if (state->rootdir)
36     {
37       char *path = solv_dupjoin(state->rootdir, dir, 0);
38       int r = access(path, mode);
39       free(path);
40       return r;
41     }
42   return access(dir, mode);
43 }
44
45 static void
46 detect_dbpath(struct rpmdbstate *state)
47 {
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";
51 }
52
53 static int
54 stat_database(struct rpmdbstate *state, struct stat *statbuf)
55 {
56   static const char *dbname[] = {
57     "/Packages",
58     "/Packages.db",
59     "/rpmdb.sqlite",
60     "/data.mdb",
61     "/Packages",                /* for error reporting */
62     0,
63   };
64   int i;
65
66 #ifdef HAVE_RPMDBFSTAT
67   if (state->dbenvopened == 1)
68     return rpmdbFStat(rpmtsGetRdb(state->ts), statbuf);
69 #endif
70   if (!state->dbpath)
71     detect_dbpath(state);
72   for (i = 0; ; i++)
73     {
74       char *dbpath = solv_dupjoin(state->rootdir, state->dbpath, dbname[i]);
75       if (!stat(dbpath, statbuf))
76         {
77           free(dbpath);
78           return 0;
79         }
80       if (errno != ENOENT || !dbname[i + 1])
81         {
82           int saved_errno = errno;
83           pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
84           solv_free(dbpath);
85           errno = saved_errno;
86           return -1;
87         }
88       solv_free(dbpath);
89     }
90   return 0;
91 }
92
93 static int
94 opendbenv(struct rpmdbstate *state)
95 {
96   rpmts ts;
97   char *dbpath;
98
99   if (!state->dbpath)
100     detect_dbpath(state);
101   dbpath = solv_dupjoin("_dbpath ", state->rootdir, state->dbpath);
102   rpmDefineMacro(NULL, dbpath, 0);
103   solv_free(dbpath);
104   ts = rpmtsCreate();
105   if (!ts)
106     {
107       pool_error(state->pool, 0, "rpmtsCreate failed");
108       delMacro(NULL, "_dbpath");
109       return 0;
110     }
111   if (rpmtsOpenDB(ts, O_RDONLY))
112     {
113       pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
114       rpmtsFree(ts);
115       delMacro(NULL, "_dbpath");
116       return 0;
117     }
118   delMacro(NULL, "_dbpath");
119   rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
120   state->ts = ts;
121   state->dbenvopened = 1;
122   return 1;
123 }
124
125 static void
126 closedbenv(struct rpmdbstate *state)
127 {
128   if (state->ts)
129     rpmtsFree(state->ts);
130   state->ts = 0;
131   state->dbenvopened = 0;
132 }
133
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)
138 {
139   const void * key;
140   size_t keylen, matchl = 0;
141   Id nameoff;
142
143   char *namedata = 0;
144   int namedatal = 0;
145   struct rpmdbentry *entries = 0;
146   int nentries = 0;
147
148   rpmdbIndexIterator ii;
149
150   *nentriesp = 0;
151   if (namedatap)
152     *namedatap = 0;
153
154   if (state->dbenvopened != 1 && !opendbenv(state))
155     return 0;
156
157   if (match)
158     matchl = strlen(match);
159   ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
160
161   while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
162     {
163       unsigned int i, npkgs;
164       if (match)
165         {
166           if (keylen != matchl || memcmp(key, match, keylen) != 0)
167             continue;
168         }
169       else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
170         continue;
171       nameoff = namedatal;
172       if (namedatap)
173        {
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;
178        }
179       npkgs = rpmdbIndexIteratorNumPkgs(ii);
180       for (i = 0; i < npkgs; i++)
181        {
182          entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
183          entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
184          entries[nentries].nameoff = nameoff;
185          nentries++;
186        }
187     }
188   rpmdbIndexIteratorFree(ii);
189   /* make sure that enteries is != 0 if there was no error */
190   if (!entries)
191     entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
192   *nentriesp = nentries;
193   if (namedatap)
194     *namedatap = namedata;
195   return entries;
196 }
197
198 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
199 static int headfromhdrblob(struct rpmdbstate *state, const unsigned char *data, unsigned int size);
200 #endif
201
202 /* retrive header by rpmdbid, returns 0 if not found, -1 on error */
203 static int
204 getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
205 {
206 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
207   const unsigned char *uh;
208   unsigned int uhlen;
209 #else
210   Header h;
211 #endif
212   rpmdbMatchIterator mi;
213   unsigned int offset = rpmdbid;
214
215   if (rpmdbid <= 0)
216     return pool_error(state->pool, -1, "illegal rpmdbid %d", rpmdbid);
217   if (state->dbenvopened != 1 && !opendbenv(state))
218     return -1;
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);
222   if (!uh)
223     {
224       rpmdbFreeIterator(mi);
225       return 0;
226     }
227   if (!headfromhdrblob(state, uh, uhlen))
228     {
229       rpmdbFreeIterator(mi);
230       return -1;
231     }
232 #else
233   h = rpmdbNextIterator(mi);
234   if (!h)
235     {
236       rpmdbFreeIterator(mi);
237       return 0;
238     }
239   if (!rpm_byrpmh(state, h))
240     {
241       rpmdbFreeIterator(mi);
242       return -1;
243     }
244 #endif
245   mi = rpmdbFreeIterator(mi);
246   return rpmdbid;
247 }
248
249 static int
250 count_headers(struct rpmdbstate *state)
251 {
252   int count;
253   rpmdbMatchIterator mi;
254
255   if (state->dbenvopened != 1 && !opendbenv(state))
256     return 0;
257   mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_NAME, NULL, 0);
258   count = rpmdbGetIteratorCount(mi);
259   rpmdbFreeIterator(mi);
260   return count;
261 }
262
263 static int
264 pkgdb_cursor_open(struct rpmdbstate *state)
265 {
266   state->mi = rpmdbInitIterator(rpmtsGetRdb(state->ts), RPMDBI_PACKAGES, NULL, 0);
267   return 0;
268 }
269
270 static void
271 pkgdb_cursor_close(struct rpmdbstate *state)
272 {
273   rpmdbFreeIterator(state->mi);
274   state->mi = 0;
275 }
276
277 static Id
278 pkgdb_cursor_getrpm(struct rpmdbstate *state)
279 {
280 #if defined(HAVE_RPMDBNEXTITERATORHEADERBLOB) && !defined(ENABLE_RPMPKG_LIBRPM)
281   const unsigned char *uh;
282   unsigned int uhlen;
283   while ((uh = rpmdbNextIteratorHeaderBlob(state->mi, &uhlen)) != 0)
284     {
285       Id dbid = rpmdbGetIteratorOffset(state->mi);
286       if (!headfromhdrblob(state, uh, uhlen))
287         continue;
288       return dbid;
289     }
290 #else
291   Header h;
292   while ((h = rpmdbNextIterator(state->mi)))
293     {
294       Id dbid = rpmdbGetIteratorOffset(state->mi);
295       if (!rpm_byrpmh(state, h))
296         continue;
297       return dbid;
298     }
299 #endif
300   return 0;
301 }
302
303 static int
304 hash_name_index(struct rpmdbstate *state, Chksum *chk)
305 {
306   rpmdbIndexIterator ii;
307   const void *key;
308   size_t keylen;
309
310   if (state->dbenvopened != 1 && !opendbenv(state))
311     return -1;
312   ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
313   if (!ii)
314     return -1;
315   while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
316     {
317       unsigned int i, npkgs = rpmdbIndexIteratorNumPkgs(ii);
318       solv_chksum_add(chk, key, (int)keylen);
319       for (i = 0; i < npkgs; i++)
320         {
321           unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i);
322           solv_chksum_add(chk, &offset, sizeof(offset));
323         }
324     }
325   rpmdbIndexIteratorFree(ii);
326   return 0;
327 }
328