Imported Upstream version 0.7.8
[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   int rpmheadsize;
24
25   int dbenvopened;      /* database environment opened */
26   int pkgdbopened;      /* package database openend */
27   int is_ostree;        /* read-only db that lives in /usr/share/rpm */
28
29   rpmts ts;
30   rpmdbMatchIterator mi;        /* iterator over packages database */
31 };
32
33 static int
34 stat_database(struct rpmdbstate *state, struct stat *statbuf)
35 {
36   static const char *dbname[] = {
37     "Packages",
38     "Packages.db",
39     "rpmdb.sqlite",
40     "data.mdb",
41     "Packages",         /* for error reporting */
42     0,
43   };
44   int i;
45
46   for (i = 0; ; i++)
47     {
48       char *dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname[i]);
49       if (!stat(dbpath, statbuf))
50         {
51           free(dbpath);
52           return 0;
53         }
54       if (errno != ENOENT || !dbname[i + 1])
55         {
56           pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
57           solv_free(dbpath);
58           return -1;
59         }
60       solv_free(dbpath);
61     }
62   return 0;
63 }
64
65 static int
66 opendbenv(struct rpmdbstate *state)
67 {
68   const char *rootdir = state->rootdir;
69   rpmts ts;
70   char *dbpath;
71   dbpath = solv_dupjoin("_dbpath ", rootdir, "/var/lib/rpm");
72   if (access(dbpath + 8, W_OK) == -1)
73     {
74       free(dbpath);
75       dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0);
76       if (access(dbpath, R_OK) == 0)
77         state->is_ostree = 1;
78       free(dbpath);
79       dbpath = solv_dupjoin("_dbpath ", rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
80     }
81   rpmDefineMacro(NULL, dbpath, 0);
82   solv_free(dbpath);
83   ts = rpmtsCreate();
84   if (!ts)
85     {
86       pool_error(state->pool, 0, "rpmtsCreate failed");
87       delMacro(NULL, "_dbpath");
88       return 0;
89     }
90   if (rpmtsOpenDB(ts, O_RDONLY))
91     {
92       pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
93       rpmtsFree(ts);
94       delMacro(NULL, "_dbpath");
95       return 0;
96     }
97   delMacro(NULL, "_dbpath");
98   rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
99   state->ts = ts;
100   state->dbenvopened = 1;
101   state->pkgdbopened = 1;
102   return 1;
103 }
104
105 static void
106 closedbenv(struct rpmdbstate *state)
107 {
108   if (state->ts)
109     rpmtsFree(state->ts);
110   state->ts = 0;
111   state->pkgdbopened = 0;
112   state->dbenvopened = 0;
113 }
114
115 static int
116 openpkgdb(struct rpmdbstate *state)
117 {
118   /* already done in opendbenv */
119   return 1;
120 }
121
122 static void
123 closepkgdb(struct rpmdbstate *state)
124 {
125 }
126
127 /* get the rpmdbids of all installed packages from the Name index database.
128  * This is much faster then querying the big Packages database */
129 static struct rpmdbentry *
130 getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
131 {
132   const void * key;
133   size_t keylen, matchl = 0;
134   Id nameoff;
135
136   char *namedata = 0;
137   int namedatal = 0;
138   struct rpmdbentry *entries = 0;
139   int nentries = 0;
140
141   rpmdbIndexIterator ii;
142   int i;
143
144   *nentriesp = 0;
145   if (namedatap)
146     *namedatap = 0;
147
148   if (state->dbenvopened != 1 && !opendbenv(state))
149     return 0;
150
151   if (match)
152     matchl = strlen(match);
153   ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
154
155   while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
156     {
157       if (match)
158         {
159           if (keylen != matchl || memcmp(key, match, keylen) != 0)
160             continue;
161         }
162       else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
163         continue;
164       nameoff = namedatal;
165       if (namedatap)
166        {
167          namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
168          memcpy(namedata + namedatal, key, keylen);
169          namedata[namedatal + keylen] = 0;
170          namedatal += keylen + 1;
171        }
172       for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++)
173        {
174          entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
175          entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
176          entries[nentries].nameoff = nameoff;
177          nentries++;
178        }
179     }
180   rpmdbIndexIteratorFree(ii);
181   /* make sure that enteries is != 0 if there was no error */
182   if (!entries)
183     entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
184   *nentriesp = nentries;
185   if (namedatap)
186     *namedatap = namedata;
187   return entries;
188 }
189
190 /* retrive header by rpmdbid, returns 0 if not found, -1 on error */
191 static int
192 getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
193 {
194   Header h;
195   rpmdbMatchIterator mi;
196   unsigned int offset = rpmdbid;
197
198   if (state->dbenvopened != 1 && !opendbenv(state))
199     return -1;
200   mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, &offset, sizeof(offset));
201   h = rpmdbNextIterator(mi);
202   if (!h)
203     {
204       rpmdbFreeIterator(mi);
205       return 0;
206     }
207   if (!rpm_byrpmh(state, h))
208     {
209       rpmdbFreeIterator(mi);
210       return -1;
211     }
212   mi = rpmdbFreeIterator(mi);
213   return 1;
214 }
215
216 static int
217 count_headers(struct rpmdbstate *state)
218 {
219   int count;
220   rpmdbMatchIterator mi;
221
222   if (state->dbenvopened != 1 && !opendbenv(state))
223     return 0;
224   mi = rpmtsInitIterator(state->ts, RPMDBI_NAME, NULL, 0);
225   count = rpmdbGetIteratorCount(mi);
226   rpmdbFreeIterator(mi);
227   return count;
228 }
229
230 static int
231 pkgdb_cursor_open(struct rpmdbstate *state)
232 {
233   state->mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, NULL, 0);
234   return 0;
235 }
236
237 static void
238 pkgdb_cursor_close(struct rpmdbstate *state)
239 {
240   rpmdbFreeIterator(state->mi);
241   state->mi = 0;
242 }
243
244 static Id
245 pkgdb_cursor_getrpm(struct rpmdbstate *state)
246 {
247   Header h;
248   while ((h = rpmdbNextIterator(state->mi)))
249     {
250       Id dbid = rpmdbGetIteratorOffset(state->mi);
251       if (!rpm_byrpmh(state, h))
252         continue;
253       return dbid;
254     }
255   return 0;
256 }
257