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