- improve infarch/dup rule problem handling
[platform/upstream/libsolv.git] / tools / installcheck.c
1 #define _GNU_SOURCE
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <zlib.h>
8
9 #include "pool.h"
10 #include "poolarch.h"
11 #include "repo_solv.h"
12 #include "repo_susetags.h"
13 #include "repo_rpmmd.h"
14 #include "solver.h"
15
16 static ssize_t
17 cookie_gzread(void *cookie, char *buf, size_t nbytes)
18 {
19   return gzread((gzFile *)cookie, buf, nbytes);
20 }
21
22 static int
23 cookie_gzclose(void *cookie)
24 {
25   return gzclose((gzFile *)cookie);
26 }
27
28 FILE *
29 myfopen(const char *fn)
30 {
31   cookie_io_functions_t cio;
32   char *suf;
33   gzFile *gzf;
34
35   if (!fn)
36     return 0;
37   suf = strrchr(fn, '.');
38   if (!suf || strcmp(suf, ".gz") != 0)
39     return fopen(fn, "r");
40   gzf = gzopen(fn, "r");
41   if (!gzf)
42     return 0;
43   memset(&cio, 0, sizeof(cio));
44   cio.read = cookie_gzread;
45   cio.close = cookie_gzclose;
46   return  fopencookie(gzf, "r", cio);
47 }
48
49 int
50 main(int argc, char **argv)
51 {
52   Pool *pool;
53   Solver *solv;
54   Queue job;
55   Queue rids;
56   Queue cand;
57   Queue archlocks;
58   char *arch;
59   int i, j;
60   Id p;
61   Id rpmid, rpmarch, rpmrel, archlock;
62   int status = 0;
63   int nocheck = 0;
64
65   archlock = 0;
66   arch = argv[1];
67   pool = pool_create();
68   pool_setarch(pool, arch);
69   for (i = 2; i < argc; i++)
70     {
71       FILE *fp;
72       int l;
73
74       if (!strcmp(argv[i], "--nocheck"))
75         {
76           if (!nocheck)
77             nocheck = pool->nsolvables;
78           continue;
79         }
80       l = strlen(argv[i]);
81       if (!strcmp(argv[i], "-"))
82         fp = stdin;
83       else if ((fp = myfopen(argv[i])) == 0)
84         {
85           perror(argv[i]);
86           exit(1);
87         }
88       Repo *repo = repo_create(pool, argv[i]);
89       if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
90         {
91           repo_add_susetags(repo, fp, 0, 0, 0);
92         }
93       else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
94         {
95           repo_add_susetags(repo, fp, 0, 0, 0);
96         }
97       else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
98         {
99           repo_add_rpmmd(repo, fp, 0, 0);
100         }
101       else if (repo_add_solv(repo, fp))
102         {
103           fprintf(stderr, "could not add repo %s\n", argv[i]);
104           exit(1);
105         }
106       if (fp != stdin)
107         fclose(fp);
108     }
109   pool_addfileprovides(pool);
110   pool_createwhatprovides(pool);
111   rpmid = str2id(pool, "rpm", 0);
112   rpmarch = str2id(pool, arch, 0);
113   rpmrel = 0;
114   if (rpmid && rpmarch)
115     {
116       for (p = 1; p < pool->nsolvables; p++)
117         {
118           Solvable *s = pool->solvables + p;
119           if (s->name == rpmid && s->arch == rpmarch)
120             break;
121         }
122       if (p < pool->nsolvables)
123         rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
124     }
125   
126   queue_init(&job);
127   queue_init(&rids);
128   queue_init(&cand);
129   queue_init(&archlocks);
130   for (p = 1; p < pool->nsolvables; p++)
131     {
132       Solvable *s = pool->solvables + p;
133       if (!s->repo)
134         continue;
135       if (!pool_installable(pool, s))
136         continue;
137       if (rpmrel && s->arch != rpmarch)
138         {
139           Id rp, rpp;
140           FOR_PROVIDES(rp, rpp, s->name)
141             {
142               if (pool->solvables[rp].name != s->name)
143                 continue;
144               if (pool->solvables[rp].arch == rpmarch)
145                 break;
146             }
147           if (rp)
148             {
149               queue_push(&archlocks, p);
150               continue;
151             }
152         }
153       queue_push(&cand, p);
154     }
155   
156   if (archlocks.count)
157     {
158       archlock = pool_queuetowhatprovides(pool, &archlocks);
159     }
160   /* prune cand by doing weak installs */
161   while (cand.count)
162     {
163       solv = solver_create(pool);
164       queue_empty(&job);
165       for (i = 0; i < cand.count; i++)
166         {
167           p = cand.elements[i];
168           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
169           queue_push(&job, p);
170         }
171       if (rpmrel)
172         {
173           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
174           queue_push(&job, rpmrel);
175         }
176       if (archlock)
177         {
178           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
179           queue_push(&job, archlock);
180         }
181       solv->dontinstallrecommended = 1;
182       solver_solve(solv, &job);
183       /* prune... */
184       for (i = j = 0; i < cand.count; i++)
185         {
186           p = cand.elements[i];
187           if (solv->decisionmap[p] <= 0)
188             {
189               cand.elements[j++] = p;
190               continue;
191             }
192 #if 0
193           Solvable *s = pool->solvables + p;
194           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
195             {
196               cand.elements[j++] = p;
197               continue;
198             }
199 #endif
200         }
201       cand.count = j;
202       if (i == j)
203         break;
204     }
205
206   /* now check every candidate */
207   for (i = 0; i < cand.count; i++)
208     {
209       Solvable *s;
210
211       p = cand.elements[i];
212       if (nocheck && p >= nocheck)
213         continue;
214       s = pool->solvables + p;
215       solv = solver_create(pool);
216       queue_empty(&job);
217       queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
218       queue_push(&job, p);
219       if (rpmrel)
220         {
221           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
222           queue_push(&job, rpmrel);
223         }
224       if (archlock)
225         {
226           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
227           queue_push(&job, archlock);
228         }
229       solv->dontinstallrecommended = 1;
230       solver_solve(solv, &job);
231       if (solv->problems.count)
232         {
233           Id problem = 0;
234           Solvable *s2;
235
236           status = 1;
237           printf("can't install %s:\n", solvable2str(pool, s));
238           while ((problem = solver_next_problem(solv, problem)) != 0)
239             {
240               solver_findallproblemrules(solv, problem, &rids);
241               for (j = 0; j < rids.count; j++)
242                 {
243                   Id probr = rids.elements[j];
244                   Id dep, source, target;
245                   switch (solver_problemruleinfo(solv, &job, probr, &dep, &source, &target))
246                     {
247                     case SOLVER_PROBLEM_DISTUPGRADE_RULE:
248                       break;
249                     case SOLVER_PROBLEM_INFARCH_RULE:
250                       s = pool_id2solvable(pool, source);
251                       printf("  %s has inferior architecture\n", solvable2str(pool, s));
252                       break;
253                     case SOLVER_PROBLEM_UPDATE_RULE:
254                       break;
255                     case SOLVER_PROBLEM_JOB_RULE:
256                       break;
257                     case SOLVER_PROBLEM_RPM_RULE:
258                       printf("  some dependency problem\n");
259                       break;
260                     case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
261                       printf("  nothing provides requested %s\n", dep2str(pool, dep));
262                       break;
263                     case SOLVER_PROBLEM_NOT_INSTALLABLE:
264                       s = pool_id2solvable(pool, source);
265                       printf("  package %s is not installable\n", solvable2str(pool, s));
266                       break;
267                     case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
268                       s = pool_id2solvable(pool, source);
269                       printf("  nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
270                       if (ISRELDEP(dep))
271                         {
272                           Reldep *rd = GETRELDEP(pool, dep);
273                           if (!ISRELDEP(rd->name))
274                             {
275                               Id rp, rpp;
276                               FOR_PROVIDES(rp, rpp, rd->name)
277                                 printf("    (we have %s)\n", solvable2str(pool, pool->solvables + rp));
278                             }
279                         }
280                       break;
281                     case SOLVER_PROBLEM_SAME_NAME:
282                       s = pool_id2solvable(pool, source);
283                       s2 = pool_id2solvable(pool, target);
284                       printf("  cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
285                       break;
286                     case SOLVER_PROBLEM_PACKAGE_CONFLICT:
287                       s = pool_id2solvable(pool, source);
288                       s2 = pool_id2solvable(pool, target);
289                       printf("  package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
290                       break;
291                     case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
292                       s = pool_id2solvable(pool, source);
293                       s2 = pool_id2solvable(pool, target);
294                       printf("  package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
295                       break;
296                     case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
297                       s = pool_id2solvable(pool, source);
298                       printf("  package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
299                       break;
300                     case SOLVER_PROBLEM_SELF_CONFLICT:
301                       s = pool_id2solvable(pool, source);
302                       printf("  package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
303                       break;
304                     }
305                 }
306             }
307         }
308 #if 0
309       else
310         {
311           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
312             {
313               solver_printdecisions(solv);
314             }
315         }
316 #endif
317       solver_free(solv);
318     }
319   exit(status);
320 }