blob: c0b4d567fb0f0e84861eb60a892e567c14d391e7 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001/* OpenEmbedded RPM resolver utility
2
3 Written by: Paul Eggleton <paul.eggleton@linux.intel.com>
4
5 Copyright 2012 Intel Corporation
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20*/
21
22#include <ctype.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/stat.h>
28
29#include <rpmdb.h>
30#include <rpmtypes.h>
31#include <rpmtag.h>
32#include <rpmts.h>
33#include <rpmmacro.h>
34#include <rpmcb.h>
35#include <rpmlog.h>
36#include <argv.h>
37#include <mire.h>
38
39int debugmode;
40FILE *outf;
41
42int getPackageStr(rpmts ts, const char *NVRA, rpmTag tag, char **value)
43{
44 int rc = -1;
Patrick Williamsf1e5d692016-03-30 15:21:19 -050045 rpmmi mi = rpmmiInit(rpmtsGetRdb(ts), RPMTAG_NVRA, NVRA, 0);
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 Header h;
47 if ((h = rpmmiNext(mi)) != NULL) {
48 HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
49 he->tag = tag;
50 rc = (headerGet(h, he, 0) != 1);
51 if(rc==0)
52 *value = strdup((char *)he->p.ptr);
53 }
54 (void)rpmmiFree(mi);
55 return rc;
56}
57
58int loadTs(rpmts **ts, int *tsct, const char *dblistfn)
59{
60 int count = 0;
61 int sz = 5;
62 int rc = 0;
63 int listfile = 1;
64 struct stat st_buf;
65
66 rc = stat(dblistfn, &st_buf);
67 if(rc != 0) {
68 perror("stat");
69 return 1;
70 }
71 if(S_ISDIR(st_buf.st_mode))
72 listfile = 0;
73
74 if(listfile) {
75 if(debugmode)
76 printf("DEBUG: reading database list file '%s'\n", dblistfn);
77 *ts = malloc(sz * sizeof(rpmts));
78 FILE *f = fopen(dblistfn, "r" );
79 if(f) {
80 char line[2048];
81 while(fgets(line, sizeof(line), f)) {
82 int len = strlen(line) - 1;
83 if(len > 0)
84 // Trim trailing whitespace
85 while(len > 0 && isspace(line[len]))
86 line[len--] = '\0';
87
88 if(len > 0) {
89 // Expand array if needed
90 if(count == sz) {
91 sz += 5;
92 *ts = (rpmts *)realloc(*ts, sz);
93 }
94
95 if(debugmode)
96 printf("DEBUG: opening database '%s'\n", line);
97 char *dbpathm = malloc(strlen(line) + 10);
98 sprintf(dbpathm, "_dbpath %s", line);
99 rpmDefineMacro(NULL, dbpathm, RMIL_CMDLINE);
100 free(dbpathm);
101
102 rpmts tsi = rpmtsCreate();
103 (*ts)[count] = tsi;
104 rc = rpmtsOpenDB(tsi, O_RDONLY);
105 if( rc ) {
106 fprintf(stderr, "Failed to open database %s\n", line);
107 rc = -1;
108 break;
109 }
110
111 count++;
112 }
113 }
114 fclose(f);
115 *tsct = count;
116 }
117 else {
118 perror(dblistfn);
119 rc = -1;
120 }
121 }
122 else {
123 if(debugmode)
124 printf("DEBUG: opening database '%s'\n", dblistfn);
125 // Load from single database
126 *ts = malloc(sizeof(rpmts));
127 char *dbpathm = malloc(strlen(dblistfn) + 10);
128 sprintf(dbpathm, "_dbpath %s", dblistfn);
129 rpmDefineMacro(NULL, dbpathm, RMIL_CMDLINE);
130 free(dbpathm);
131
132 rpmts tsi = rpmtsCreate();
133 (*ts)[0] = tsi;
134 rc = rpmtsOpenDB(tsi, O_RDONLY);
135 if( rc ) {
136 fprintf(stderr, "Failed to open database %s\n", dblistfn);
137 rc = -1;
138 }
139 *tsct = 1;
140 }
141
142 return rc;
143}
144
145int processPackages(rpmts *ts, int tscount, const char *packagelistfn, int ignoremissing)
146{
147 int rc = 0;
148 int count = 0;
149 int sz = 100;
150 int i = 0;
151 int missing = 0;
152
153 FILE *f = fopen(packagelistfn, "r" );
154 if(f) {
155 char line[255];
156 while(fgets(line, sizeof(line), f)) {
157 int len = strlen(line) - 1;
158 if(len > 0)
159 // Trim trailing whitespace
160 while(len > 0 && isspace(line[len]))
161 line[len--] = '\0';
162
163 if(len > 0) {
164 int found = 0;
165 for(i=0; i<tscount; i++) {
166 ARGV_t keys = NULL;
167 rpmdb db = rpmtsGetRdb(ts[i]);
168 rc = rpmdbMireApply(db, RPMTAG_NAME,
169 RPMMIRE_STRCMP, line, &keys);
170 if (keys) {
171 int nkeys = argvCount(keys);
172 if( nkeys == 1 ) {
173 char *value = NULL;
174 rc = getPackageStr(ts[i], keys[0], RPMTAG_PACKAGEORIGIN, &value);
175 if(rc == 0)
176 fprintf(outf, "%s\n", value);
177 else
178 fprintf(stderr, "Failed to get package origin for %s\n", line);
179 found = 1;
180 }
181 else if( nkeys > 1 ) {
182 int keyindex = 0;
183 fprintf(stderr, "Multiple matches for %s:\n", line);
184 for( keyindex=0; keyindex<nkeys; keyindex++) {
185 char *value = NULL;
186 rc = getPackageStr(ts[i], keys[keyindex], RPMTAG_PACKAGEORIGIN, &value);
187 if(rc == 0)
188 fprintf(stderr, " %s\n", value);
189 else
190 fprintf(stderr, " (%s)\n", keys[keyindex]);
191 }
192 }
193 }
194 if(found)
195 break;
196 }
197
198 if( !found ) {
199 if( ignoremissing ) {
200 fprintf(stderr, "Unable to resolve package %s - ignoring\n", line);
201 }
202 else {
203 fprintf(stderr, "Unable to resolve package %s\n", line);
204 missing = 1;
205 }
206 }
207 }
208 count++;
209 }
210 fclose(f);
211
212 if( missing ) {
213 fprintf(stderr, "ERROR: some packages were missing\n");
214 rc = 1;
215 }
216 }
217 else {
218 perror(packagelistfn);
219 rc = -1;
220 }
221
222 return rc;
223}
224
225int lookupProvider(rpmts ts, const char *req, char **provider)
226{
227 int rc = 0;
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500228 rpmmi provmi = rpmmiInit(rpmtsGetRdb(ts), RPMTAG_PROVIDENAME, req, 0);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500229 if(provmi) {
230 Header h;
231 if ((h = rpmmiNext(provmi)) != NULL) {
232 HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
233 he->tag = RPMTAG_NAME;
234 rc = (headerGet(h, he, 0) != 1);
235 if(rc==0)
236 *provider = strdup((char *)he->p.ptr);
237 }
238 (void)rpmmiFree(provmi);
239 }
240 else {
241 rc = -1;
242 }
243 return rc;
244}
245
246int printDepList(rpmts *ts, int tscount)
247{
248 int rc = 0;
249
250 if( tscount > 1 )
251 fprintf(stderr, ">1 database specified with dependency list, using first only\n");
252
253 /* Get list of names */
254 rpmdb db = rpmtsGetRdb(ts[0]);
255 ARGV_t names = NULL;
256 rc = rpmdbMireApply(db, RPMTAG_NAME,
257 RPMMIRE_STRCMP, NULL, &names);
258 int nnames = argvCount(names);
259
260 /* Get list of NVRAs */
261 ARGV_t keys = NULL;
262 rc = rpmdbMireApply(db, RPMTAG_NVRA,
263 RPMMIRE_STRCMP, NULL, &keys);
264 if (keys) {
265 int i, j;
266 HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
267 int nkeys = argvCount(keys);
268 for(i=0; i<nkeys; i++) {
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500269 rpmmi mi = rpmmiInit(db, RPMTAG_NVRA, keys[i], 0);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500270 Header h;
271 if ((h = rpmmiNext(mi)) != NULL) {
272 /* Get name of package */
273 he->tag = RPMTAG_NAME;
274 rc = (headerGet(h, he, 0) != 1);
275 char *name = strdup((char *)he->p.ptr);
276 /* Get its requires */
277 he->tag = RPMTAG_REQUIRENAME;
278 if (rc = (headerGet(h, he, 0) != 1)) {
279 if (debugmode) {
280 printf("DEBUG: %s requires null\n", name);
281 }
282 rc = 0;
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500283 free(name);
284 (void)rpmmiFree(mi);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500285 continue;
286 }
287 ARGV_t reqs = (ARGV_t)he->p.ptr;
288 /* Get its requireflags */
289 he->tag = RPMTAG_REQUIREFLAGS;
290 rc = (headerGet(h, he, 0) != 1);
291 rpmuint32_t *reqflags = (rpmuint32_t *)he->p.ui32p;
292 for(j=0; j<he->c; j++) {
293 int k;
294 char *prov = NULL;
295 for(k=0; k<nnames; k++) {
296 if(strcmp(names[k], reqs[j]) == 0) {
297 prov = names[k];
298 break;
299 }
300 }
301 if(prov) {
302 if((int)reqflags[j] & 0x80000)
303 fprintf(outf, "%s|%s [REC]\n", name, prov);
304 else
305 fprintf(outf, "%s|%s\n", name, prov);
306 }
307 else {
308 rc = lookupProvider(ts[0], reqs[j], &prov);
309 if(rc==0 && prov) {
310 if((int)reqflags[j] & 0x80000)
311 fprintf(outf, "%s|%s [REC]\n", name, prov);
312 else
313 fprintf(outf, "%s|%s\n", name, prov);
314 free(prov);
315 }
316 }
317 }
318 free(name);
319 }
320 (void)rpmmiFree(mi);
321 }
322 }
323
324 return rc;
325}
326
327void usage()
328{
329 fprintf(stderr, "OpenEmbedded rpm resolver utility\n");
330 fprintf(stderr, "syntax: rpmresolve [-i] [-d] [-t] <dblistfile> <packagelistfile>\n");
331}
332
333int main(int argc, char **argv)
334{
335 rpmts *ts = NULL;
336 int tscount = 0;
337 int rc = 0;
338 int i;
339 int c;
340 int ignoremissing = 0;
341 int deplistmode = 0;
342 char *outfile = NULL;
343
344 debugmode = 0;
345 outf = stdout;
346
347 opterr = 0;
348 while ((c = getopt (argc, argv, "itdo:")) != -1) {
349 switch (c) {
350 case 'i':
351 ignoremissing = 1;
352 break;
353 case 't':
354 deplistmode = 1;
355 break;
356 case 'd':
357 debugmode = 1;
358 break;
359 case 'o':
360 outfile = strdup(optarg);
361 break;
362 case '?':
363 if(isprint(optopt))
364 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
365 else
366 fprintf(stderr, "Unknown option character `\\x%x'.\n",
367 optopt);
368 usage();
369 return 1;
370 default:
371 abort();
372 }
373 }
374
375 if( argc - optind < 1 ) {
376 usage();
377 return 1;
378 }
379
380 if( outfile ) {
381 if(debugmode)
382 printf("DEBUG: Using output file %s\n", outfile);
383 outf = fopen(outfile, "w");
384 }
385
386 const char *dblistfn = argv[optind];
387
388 rpmcliInit(argc, argv, NULL);
389
390 if(debugmode)
391 rpmSetVerbosity(RPMLOG_DEBUG);
392
393 rpmDefineMacro(NULL, "__dbi_txn create nofsync", RMIL_CMDLINE);
394
395 rc = loadTs(&ts, &tscount, dblistfn);
396 if( rc )
397 return 1;
398 if( tscount == 0 ) {
399 fprintf(stderr, "Please specify database list file or database location\n");
400 return 1;
401 }
402
403 if(deplistmode) {
404 rc = printDepList(ts, tscount);
405 }
406 else {
407 if( argc - optind < 2 ) {
408 fprintf(stderr, "Please specify package list file\n");
409 }
410 else {
411 const char *pkglistfn = argv[optind+1];
412 rc = processPackages(ts, tscount, pkglistfn, ignoremissing);
413 }
414 }
415
416 for(i=0; i<tscount; i++)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500417 (void)rpmtsFree(ts[i]);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500418 free(ts);
419
420 if( outfile ) {
421 fclose(outf);
422 free(outfile);
423 }
424
425 return rc;
426}