Imported Upstream version 0.6.31
[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)
115 {
116   const void * key;
117   size_t keylen;
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   if (state->dbenvopened != 1 && !opendbenv(state))
129     return 0;
130
131   ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
132
133   *nentriesp = 0;
134   if (namedatap)
135     *namedatap = 0;
136
137   while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
138     {
139
140       if (keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
141        continue;
142       nameoff = namedatal;
143       if (namedatap)
144        {
145          namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
146          memcpy(namedata + namedatal, key, keylen);
147          namedata[namedatal + keylen] = 0;
148          namedatal += keylen + 1;
149        }
150       for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++)
151        {
152          entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
153          entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
154          entries[nentries].nameoff = nameoff;
155          nentries++;
156        }
157     }
158   rpmdbIndexIteratorFree(ii);
159   /* make sure that enteries is != 0 if there was no error */
160   if (!entries)
161     entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
162   *nentriesp = nentries;
163   if (namedatap)
164     *namedatap = namedata;
165   return entries;
166 }
167
168 /* retrive header by rpmdbid, returns 0 if not found, -1 on error */
169 static int
170 getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
171 {
172   Header h;
173   rpmdbMatchIterator mi;
174   unsigned int offset = rpmdbid;
175
176   if (state->dbenvopened != 1 && !opendbenv(state))
177     return -1;
178   mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, &offset, sizeof(offset));
179   h = rpmdbNextIterator(mi);
180   if (!h)
181     {
182       rpmdbFreeIterator(mi);
183       return 0;
184     }
185   if (!rpm_byrpmh(state, h))
186     {
187       rpmdbFreeIterator(mi);
188       return -1;
189     }
190   mi = rpmdbFreeIterator(mi);
191   return 1;
192 }
193
194 static int
195 count_headers(struct rpmdbstate *state)
196 {
197   int count;
198   rpmdbMatchIterator mi;
199
200   if (state->dbenvopened != 1 && !opendbenv(state))
201     return 0;
202   mi = rpmtsInitIterator(state->ts, RPMDBI_NAME, NULL, 0);
203   count = rpmdbGetIteratorCount(mi);
204   rpmdbFreeIterator(mi);
205   return count;
206 }
207
208 static int
209 pkgdb_cursor_open(struct rpmdbstate *state)
210 {
211   state->mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, NULL, 0);
212   return 0;
213 }
214
215 static void
216 pkgdb_cursor_close(struct rpmdbstate *state)
217 {
218   rpmdbFreeIterator(state->mi);
219   state->mi = 0;
220 }
221
222 static Id
223 pkgdb_cursor_getrpm(struct rpmdbstate *state)
224 {
225   Header h;
226   while ((h = rpmdbNextIterator(state->mi)))
227     {
228       Id dbid = rpmdbGetIteratorOffset(state->mi);
229       if (!rpm_byrpmh(state, h))
230         continue;
231       return dbid;
232     }
233   return 0;
234 }
235