Merge branch 'master' of gitorious.org:opensuse/sat-solver
[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 "common_myfopen.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 = myfopen(argv[i])) == 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 = str2id(pool, "rpm", 0);
140   rpmarch = 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 = 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       solv->dontinstallrecommended = 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 (solv->decisionmap[p] <= 0)
223             {
224               cand.elements[j++] = p;
225               continue;
226             }
227 #if 0
228           Solvable *s = pool->solvables + p;
229           if (!strcmp(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
246       p = cand.elements[i];
247       if (nocheck && p >= nocheck)
248         continue;
249       if (exclude_pat)
250         {
251           char *ptr, *save = 0, *pattern;
252           int match = 0;
253           pattern = strdup(exclude_pat);
254
255           for (ptr = strtok_r(pattern, " ", &save);
256               ptr;
257               ptr = strtok_r(NULL, " ", &save))
258             {
259               if (*ptr && strstr(solvid2str(pool, p), ptr))
260                 {
261                   match = 1;
262                   break;
263                 }
264             }
265           free(pattern);
266           if (match)
267             continue;
268         }
269       s = pool->solvables + p;
270       solv = solver_create(pool);
271       queue_empty(&job);
272       queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
273       queue_push(&job, p);
274       if (rpmrel)
275         {
276           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
277           queue_push(&job, rpmrel);
278         }
279       if (archlock)
280         {
281           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
282           queue_push(&job, archlock);
283         }
284       solv->dontinstallrecommended = 1;
285       solver_solve(solv, &job);
286       if (solv->problems.count)
287         {
288           Id problem = 0;
289           Solvable *s2;
290
291           status = 1;
292           printf("can't install %s:\n", solvable2str(pool, s));
293           while ((problem = solver_next_problem(solv, problem)) != 0)
294             {
295               solver_findallproblemrules(solv, problem, &rids);
296               for (j = 0; j < rids.count; j++)
297                 {
298                   Id probr = rids.elements[j];
299                   int k;
300                   Queue rinfo;
301                   queue_init(&rinfo);
302
303                   solver_allruleinfos(solv, probr, &rinfo);
304                   for (k = 0; k < rinfo.count; k += 4)
305                     {
306                       Id dep, source, target;
307                       source = rinfo.elements[k + 1];
308                       target = rinfo.elements[k + 2];
309                       dep = rinfo.elements[k + 3];
310                       switch (rinfo.elements[k])
311                         {
312                         case SOLVER_PROBLEM_DISTUPGRADE_RULE:
313                           break;
314                         case SOLVER_PROBLEM_INFARCH_RULE:
315                           s = pool_id2solvable(pool, source);
316                           printf("  %s has inferior architecture\n", solvable2str(pool, s));
317                           break;
318                         case SOLVER_PROBLEM_UPDATE_RULE:
319                           break;
320                         case SOLVER_PROBLEM_JOB_RULE:
321                           break;
322                         case SOLVER_PROBLEM_RPM_RULE:
323                           printf("  some dependency problem\n");
324                           break;
325                         case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
326                           printf("  nothing provides requested %s\n", dep2str(pool, dep));
327                           break;
328                         case SOLVER_PROBLEM_NOT_INSTALLABLE:
329                           s = pool_id2solvable(pool, source);
330                           printf("  package %s is not installable\n", solvable2str(pool, s));
331                           break;
332                         case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
333                           s = pool_id2solvable(pool, source);
334                           printf("  nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
335                           if (ISRELDEP(dep))
336                             {
337                               Reldep *rd = GETRELDEP(pool, dep);
338                               if (!ISRELDEP(rd->name))
339                                 {
340                                   Id rp, rpp;
341                                   FOR_PROVIDES(rp, rpp, rd->name)
342                                     printf("    (we have %s)\n", solvable2str(pool, pool->solvables + rp));
343                                 }
344                             }
345                           break;
346                         case SOLVER_PROBLEM_SAME_NAME:
347                           s = pool_id2solvable(pool, source);
348                           s2 = pool_id2solvable(pool, target);
349                           printf("  cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
350                           break;
351                         case SOLVER_PROBLEM_PACKAGE_CONFLICT:
352                           s = pool_id2solvable(pool, source);
353                           s2 = pool_id2solvable(pool, target);
354                           printf("  package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
355                           break;
356                         case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
357                           s = pool_id2solvable(pool, source);
358                           s2 = pool_id2solvable(pool, target);
359                           printf("  package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
360                           break;
361                         case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
362                           s = pool_id2solvable(pool, source);
363                           printf("  package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
364                           break;
365                         case SOLVER_PROBLEM_SELF_CONFLICT:
366                           s = pool_id2solvable(pool, source);
367                           printf("  package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
368                           break;
369                         }
370                     }
371                 }
372             }
373         }
374 #if 0
375       else
376         {
377           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
378             {
379               solver_printdecisions(solv);
380             }
381         }
382 #endif
383       solver_free(solv);
384     }
385   exit(status);
386 }