implement error message for SOLVER_RULE_UPDATE
[platform/upstream/libsolv.git] / tools / installcheck.c
1 /* vim: sw=2 et cino=>4,n-2,{1s
2  */
3
4 /*
5  * Copyright (c) 2009, Novell Inc.
6  *
7  * This program is licensed under the BSD license, read LICENSE.BSD
8  * for further information
9  */
10
11
12 #define _GNU_SOURCE
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <zlib.h>
19
20 #include "pool.h"
21 #include "poolarch.h"
22 #include "repo_solv.h"
23 #ifndef DEBIAN
24 #include "repo_susetags.h"
25 #include "repo_rpmmd.h"
26 #else
27 #include "repo_deb.h"
28 #endif
29 #include "solver.h"
30 #include "solv_xfopen.h"
31
32
33 void
34 usage(char** argv)
35 {
36   printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
37          "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
38          "packagenames to ignore\n"
39          "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
40          , argv[0]);
41   exit(1);
42 }
43
44
45 int
46 main(int argc, char **argv)
47 {
48   Pool *pool;
49   Solver *solv;
50   Queue job;
51   Queue rids;
52   Queue cand;
53   Queue archlocks;
54   char *arch, *exclude_pat;
55   int i, j;
56   Id p;
57   Id rpmid, rpmarch, rpmrel, archlock;
58   int status = 0;
59   int nocheck = 0;
60   int withsrc = 0;
61
62   exclude_pat = 0;
63   archlock = 0;
64   if (argc < 3)
65     usage(argv);
66
67   arch = argv[1];
68   pool = pool_create();
69   pool_setarch(pool, arch);
70   for (i = 2; i < argc; i++)
71     {
72       FILE *fp;
73       int l;
74
75       if (!strcmp(argv[i], "--withsrc"))
76         {
77           withsrc++;
78           continue;
79         }
80       if (!strcmp(argv[i], "--nocheck"))
81         {
82           if (!nocheck)
83             nocheck = pool->nsolvables;
84           continue;
85         }
86       if (!strcmp(argv[i], "--exclude"))
87         {
88           if (i + 1 >= argc)
89             {
90               printf("--exclude needs a whitespace separated list of substrings as parameter\n");
91               exit(1);
92             }
93           exclude_pat = argv[i + 1];
94           ++i;
95           continue;
96         }
97       l = strlen(argv[i]);
98       if (!strcmp(argv[i], "-"))
99         fp = stdin;
100       else if ((fp = solv_xfopen(argv[i], 0)) == 0)
101         {
102           perror(argv[i]);
103           exit(1);
104         }
105       Repo *repo = repo_create(pool, argv[i]);
106 #ifndef DEBIAN
107       if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
108         {
109           repo_add_susetags(repo, fp, 0, 0, 0);
110         }
111       else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
112         {
113           repo_add_susetags(repo, fp, 0, 0, 0);
114         }
115       else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
116         {
117           repo_add_rpmmd(repo, fp, 0, 0);
118         }
119 #else
120       if (l >= 8 && !strcmp(argv[i] + l - 8, "Packages"))
121         {
122           repo_add_debpackages(repo, fp, 0);
123         }
124       else if (l >= 11 && !strcmp(argv[i] + l - 11, "Packages.gz"))
125         {
126           repo_add_debpackages(repo, fp, 0);
127         }
128 #endif
129       else if (repo_add_solv(repo, fp))
130         {
131           fprintf(stderr, "could not add repo %s\n", argv[i]);
132           exit(1);
133         }
134       if (fp != stdin)
135         fclose(fp);
136     }
137   pool_addfileprovides(pool);
138   pool_createwhatprovides(pool);
139   rpmid = pool_str2id(pool, "rpm", 0);
140   rpmarch = pool_str2id(pool, arch, 0);
141   rpmrel = 0;
142 #ifndef DEBIAN
143   if (rpmid && rpmarch)
144     {
145       for (p = 1; p < pool->nsolvables; p++)
146         {
147           Solvable *s = pool->solvables + p;
148           if (s->name == rpmid && s->arch == rpmarch)
149             break;
150         }
151       if (p < pool->nsolvables)
152         rpmrel = pool_rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
153     }
154 #endif
155   
156   queue_init(&job);
157   queue_init(&rids);
158   queue_init(&cand);
159   queue_init(&archlocks);
160   for (p = 1; p < pool->nsolvables; p++)
161     {
162       Solvable *s = pool->solvables + p;
163       if (!s->repo)
164         continue;
165       if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
166         {
167           queue_push(&cand, p);
168           continue;
169         }
170       if (!pool_installable(pool, s))
171         continue;
172       if (rpmrel && s->arch != rpmarch)
173         {
174           Id rp, rpp;
175           FOR_PROVIDES(rp, rpp, s->name)
176             {
177               if (pool->solvables[rp].name != s->name)
178                 continue;
179               if (pool->solvables[rp].arch == rpmarch)
180                 break;
181             }
182           if (rp)
183             {
184               queue_push(&archlocks, p);
185               continue;
186             }
187         }
188       queue_push(&cand, p);
189     }
190   
191   if (archlocks.count)
192     {
193       archlock = pool_queuetowhatprovides(pool, &archlocks);
194     }
195   /* prune cand by doing weak installs */
196   while (cand.count)
197     {
198       solv = solver_create(pool);
199       queue_empty(&job);
200       for (i = 0; i < cand.count; i++)
201         {
202           p = cand.elements[i];
203           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
204           queue_push(&job, p);
205         }
206       if (rpmrel)
207         {
208           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
209           queue_push(&job, rpmrel);
210         }
211       if (archlock)
212         {
213           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
214           queue_push(&job, archlock);
215         }
216       solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
217       solver_solve(solv, &job);
218       /* prune... */
219       for (i = j = 0; i < cand.count; i++)
220         {
221           p = cand.elements[i];
222           if (solver_get_decisionlevel(solv, p) <= 0)
223             {
224               cand.elements[j++] = p;
225               continue;
226             }
227 #if 0
228           Solvable *s = pool->solvables + p;
229           if (!strcmp(pool_id2str(pool, s->name), "libusb-compat-devel"))
230             {
231               cand.elements[j++] = p;
232               continue;
233             }
234 #endif
235         }
236       cand.count = j;
237       if (i == j)
238         break;
239     }
240
241   /* now check every candidate */
242   for (i = 0; i < cand.count; i++)
243     {
244       Solvable *s;
245       int problemcount;
246
247       p = cand.elements[i];
248       if (nocheck && p >= nocheck)
249         continue;
250       if (exclude_pat)
251         {
252           char *ptr, *save = 0, *pattern;
253           int match = 0;
254           pattern = strdup(exclude_pat);
255
256           for (ptr = strtok_r(pattern, " ", &save);
257               ptr;
258               ptr = strtok_r(NULL, " ", &save))
259             {
260               if (*ptr && strstr(pool_solvid2str(pool, p), ptr))
261                 {
262                   match = 1;
263                   break;
264                 }
265             }
266           free(pattern);
267           if (match)
268             continue;
269         }
270       s = pool->solvables + p;
271       solv = solver_create(pool);
272       queue_empty(&job);
273       queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
274       queue_push(&job, p);
275       if (rpmrel)
276         {
277           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
278           queue_push(&job, rpmrel);
279         }
280       if (archlock)
281         {
282           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
283           queue_push(&job, archlock);
284         }
285       solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
286       problemcount = solver_solve(solv, &job);
287       if (problemcount)
288         {
289           Id problem = 0;
290           Solvable *s2;
291
292           status = 1;
293           printf("can't install %s:\n", pool_solvable2str(pool, s));
294           while ((problem = solver_next_problem(solv, problem)) != 0)
295             {
296               solver_findallproblemrules(solv, problem, &rids);
297               for (j = 0; j < rids.count; j++)
298                 {
299                   Id probr = rids.elements[j];
300                   int k;
301                   Queue rinfo;
302                   queue_init(&rinfo);
303
304                   solver_allruleinfos(solv, probr, &rinfo);
305                   for (k = 0; k < rinfo.count; k += 4)
306                     {
307                       Id dep, source, target;
308                       source = rinfo.elements[k + 1];
309                       target = rinfo.elements[k + 2];
310                       dep = rinfo.elements[k + 3];
311                       switch (rinfo.elements[k])
312                         {
313                         case SOLVER_RULE_DISTUPGRADE:
314                           break;
315                         case SOLVER_RULE_INFARCH:
316                           s = pool_id2solvable(pool, source);
317                           printf("  %s has inferior architecture\n", pool_solvable2str(pool, s));
318                           break;
319                         case SOLVER_RULE_UPDATE:
320                           s = pool_id2solvable(pool, source);
321                           printf("  %s can not be updated\n", pool_solvable2str(pool, s));
322                           break;
323                         case SOLVER_RULE_JOB:
324                           break;
325                         case SOLVER_RULE_RPM:
326                           printf("  some dependency problem\n");
327                           break;
328                         case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
329                           printf("  nothing provides requested %s\n", pool_dep2str(pool, dep));
330                           break;
331                         case SOLVER_RULE_RPM_NOT_INSTALLABLE:
332                           s = pool_id2solvable(pool, source);
333                           printf("  package %s is not installable\n", pool_solvable2str(pool, s));
334                           break;
335                         case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
336                           s = pool_id2solvable(pool, source);
337                           printf("  nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvable2str(pool, s));
338                           if (ISRELDEP(dep))
339                             {
340                               Reldep *rd = GETRELDEP(pool, dep);
341                               if (!ISRELDEP(rd->name))
342                                 {
343                                   Id rp, rpp;
344                                   FOR_PROVIDES(rp, rpp, rd->name)
345                                     printf("    (we have %s)\n", pool_solvable2str(pool, pool->solvables + rp));
346                                 }
347                             }
348                           break;
349                         case SOLVER_RULE_RPM_SAME_NAME:
350                           s = pool_id2solvable(pool, source);
351                           s2 = pool_id2solvable(pool, target);
352                           printf("  cannot install both %s and %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2));
353                           break;
354                         case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
355                           s = pool_id2solvable(pool, source);
356                           s2 = pool_id2solvable(pool, target);
357                           printf("  package %s conflicts with %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
358                           break;
359                         case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
360                           s = pool_id2solvable(pool, source);
361                           s2 = pool_id2solvable(pool, target);
362                           printf("  package %s obsoletes %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
363                           break;
364                         case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
365                           s = pool_id2solvable(pool, source);
366                           printf("  package %s requires %s, but none of the providers can be installed\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
367                           break;
368                         case SOLVER_RULE_RPM_SELF_CONFLICT:
369                           s = pool_id2solvable(pool, source);
370                           printf("  package %s conflicts with %s provided by itself\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
371                           break;
372                         }
373                     }
374                 }
375             }
376         }
377 #if 0
378       else
379         {
380           if (!strcmp(pool_id2str(pool, s->name), "libusb-compat-devel"))
381             {
382               solver_printdecisions(solv);
383             }
384         }
385 #endif
386       solver_free(solv);
387     }
388   exit(status);
389 }