3ef67b064e80d99081ea504918d3eec797390a29
[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 #ifdef ENABLE_SUSEREPO
24 #include "repo_susetags.h"
25 #endif
26 #ifdef ENABLE_RPMMD
27 #include "repo_rpmmd.h"
28 #endif
29 #ifdef ENABLE_DEBIAN
30 #include "repo_deb.h"
31 #endif
32 #ifdef ENABLE_ARCHREPO
33 #include "repo_arch.h"
34 #endif
35 #include "solver.h"
36 #include "solv_xfopen.h"
37
38
39 void
40 usage(char** argv)
41 {
42   printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
43          "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
44          "packagenames to ignore\n"
45          "\t--withobsoletes\t\tCheck for obsoletes on packages contained in repos\n"
46          "\t--nocheck\t\tDo not warn about all following repos (only use them to fulfill dependencies)\n"
47          "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
48          , argv[0]);
49   exit(1);
50 }
51
52
53 int
54 main(int argc, char **argv)
55 {
56   Pool *pool;
57   Solver *solv;
58   Repo *repo;
59   Queue job;
60   Queue rids;
61   Queue cand;
62   char *arch, *exclude_pat;
63   int i, j;
64   Id p;
65   Id archid, noarchid;
66   Id rpmrel;
67 #ifndef DEBIAN
68   Id rpmid;
69 #endif
70   int status = 0;
71   int nocheck = 0;
72   int withsrc = 0;
73   int obsoletepkgcheck = 0;
74
75   exclude_pat = 0;
76   if (argc < 3)
77     usage(argv);
78
79   arch = argv[1];
80   pool = pool_create();
81   pool_setarch(pool, arch);
82   noarchid = pool->solvables[SYSTEMSOLVABLE].arch;
83   for (i = 2; i < argc; i++)
84     {
85       FILE *fp;
86       int r, l;
87
88       if (!strcmp(argv[i], "--withsrc"))
89         {
90           withsrc++;
91           continue;
92         }
93       if (!strcmp(argv[i], "--withobsoletes"))
94         {
95           obsoletepkgcheck++;
96           continue;
97         }
98       if (!strcmp(argv[i], "--nocheck"))
99         {
100           if (!nocheck)
101             nocheck = pool->nsolvables;
102           continue;
103         }
104       if (!strcmp(argv[i], "--exclude"))
105         {
106           if (i + 1 >= argc)
107             {
108               printf("--exclude needs a whitespace separated list of substrings as parameter\n");
109               exit(1);
110             }
111           exclude_pat = argv[i + 1];
112           ++i;
113           continue;
114         }
115       l = strlen(argv[i]);
116       if (!strcmp(argv[i], "-"))
117         fp = stdin;
118       else if ((fp = solv_xfopen(argv[i], 0)) == 0)
119         {
120           perror(argv[i]);
121           exit(1);
122         }
123       repo = repo_create(pool, argv[i]);
124       r = 0;
125       if (0)
126         {
127         }
128 #ifdef ENABLE_SUSEREPO
129       else if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
130         {
131           r = repo_add_susetags(repo, fp, 0, 0, 0);
132         }
133       else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
134         {
135           r = repo_add_susetags(repo, fp, 0, 0, 0);
136         }
137 #endif
138 #ifdef ENABLE_RPMMD
139       else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
140         {
141           r = repo_add_rpmmd(repo, fp, 0, 0);
142         }
143 #endif
144 #ifdef ENABLE_DEBIAN
145       else if (l >= 8 && !strcmp(argv[i] + l - 8, "Packages"))
146         {
147           r = repo_add_debpackages(repo, fp, 0);
148         }
149       else if (l >= 11 && !strcmp(argv[i] + l - 11, "Packages.gz"))
150         {
151           r = repo_add_debpackages(repo, fp, 0);
152         }
153 #endif
154 #ifdef ENABLE_ARCHREPO
155       else if (l >= 10 && (!strcmp(argv[i] + l - 10, ".db.tar.gz") || !strcmp(argv[i] + l - 10, ".db.tar.xz")))
156         {
157           r = repo_add_arch_repo(repo, fp, 0);
158         }
159 #endif
160       else
161         r = repo_add_solv(repo, fp, 0);
162       if (r)
163         {
164           fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool));
165           exit(1);
166         }
167       if (fp != stdin)
168         fclose(fp);
169     }
170   pool_addfileprovides(pool);
171   pool_createwhatprovides(pool);
172   archid = pool_str2id(pool, arch, 0);
173 #ifndef DEBIAN
174   rpmid = pool_str2id(pool, "rpm", 0);
175   rpmrel = 0;
176   if (rpmid && archid)
177     {
178       for (p = 1; p < pool->nsolvables; p++)
179         {
180           Solvable *s = pool->solvables + p;
181           if (s->name == rpmid && s->arch == archid && pool_installable(pool, s))
182             break;
183         }
184       if (p < pool->nsolvables)
185         rpmrel = pool_rel2id(pool, rpmid, archid, REL_ARCH, 1);
186     }
187 #else
188   rpmrel = 0;
189 #endif
190   
191   queue_init(&job);
192   queue_init(&rids);
193   queue_init(&cand);
194   for (p = 1; p < (nocheck ? nocheck : pool->nsolvables); p++)
195     {
196       Solvable *s = pool->solvables + p;
197       if (!s->repo)
198         continue;
199       if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
200         {
201           queue_push(&cand, p);
202           continue;
203         }
204       if (!pool_installable(pool, s))
205         continue;
206       if (archid && s->arch != archid && s->arch != noarchid)
207         {
208           /* check if we will conflict with a infarch rule, if yes,
209            * don't bother checking the package */
210           Id rp, rpp;
211           FOR_PROVIDES(rp, rpp, s->name)
212             {
213               if (pool->solvables[rp].name != s->name)
214                 continue;
215               if (pool->solvables[rp].arch == archid)
216                 break;
217             }
218           if (rp)
219             continue;
220         }
221       queue_push(&cand, p);
222     }
223   if (obsoletepkgcheck)
224     {
225       int obsoleteusesprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
226       int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
227
228       for (i = 0; i < cand.count; i++)
229         {
230           Solvable *s;
231           s = pool->solvables + cand.elements[i];
232
233           if (s->obsoletes)
234             {
235               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
236
237               while ((obs = *obsp++) != 0)
238                 {
239                   Id op, opp;
240                   FOR_PROVIDES(op, opp, obs)
241                     {
242                       Solvable *os = pool->solvables + op;
243                       if (nocheck && op >= nocheck)
244                         continue;
245                       if (solvable_identical(s, os))
246                         continue;
247                       if (!obsoleteusesprovides && !pool_match_nevr(pool, os, obs))
248                         continue;
249                       if (obsoleteusescolors && !pool_colormatch(pool, s, os))
250                         continue;
251                       status = 2;
252                       printf("can't install %s:\n", pool_solvid2str(pool, op));
253                       printf("  package is obsoleted by %s\n", pool_solvable2str(pool, s));
254                     }
255                 }
256             }
257         }
258     }
259
260   solv = solver_create(pool);
261
262   /* prune cand by doing weak installs */
263   while (cand.count)
264     {
265       queue_empty(&job);
266       for (i = 0; i < cand.count; i++)
267         {
268           p = cand.elements[i];
269           queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK, p);
270         }
271       if (rpmrel)
272         queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
273       solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
274       solver_solve(solv, &job);
275       /* prune... */
276       for (i = j = 0; i < cand.count; i++)
277         {
278           p = cand.elements[i];
279           if (solver_get_decisionlevel(solv, p) <= 0)
280             {
281               cand.elements[j++] = p;
282               continue;
283             }
284 #if 0
285           Solvable *s = pool->solvables + p;
286           if (!strcmp(pool_id2str(pool, s->name), "libusb-compat-devel"))
287             {
288               cand.elements[j++] = p;
289               continue;
290             }
291 #endif
292         }
293       cand.count = j;
294       if (i == j)
295         break;
296     }
297
298   /* now check every candidate */
299   for (i = 0; i < cand.count; i++)
300     {
301       Solvable *s;
302       int problemcount;
303
304       p = cand.elements[i];
305       if (exclude_pat)
306         {
307           char *ptr, *save = 0, *pattern;
308           int match = 0;
309           pattern = solv_strdup(exclude_pat);
310
311           for (ptr = strtok_r(pattern, " ", &save);
312               ptr;
313               ptr = strtok_r(NULL, " ", &save))
314             {
315               if (*ptr && strstr(pool_solvid2str(pool, p), ptr))
316                 {
317                   match = 1;
318                   break;
319                 }
320             }
321           solv_free(pattern);
322           if (match)
323             continue;
324         }
325       s = pool->solvables + p;
326       queue_empty(&job);
327       queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE, p);
328       if (rpmrel)
329         queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
330       solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
331       problemcount = solver_solve(solv, &job);
332       if (problemcount)
333         {
334           Id problem = 0;
335           Solvable *s2;
336
337           status = 1;
338           printf("can't install %s:\n", pool_solvable2str(pool, s));
339           while ((problem = solver_next_problem(solv, problem)) != 0)
340             {
341               solver_findallproblemrules(solv, problem, &rids);
342               for (j = 0; j < rids.count; j++)
343                 {
344                   Id probr = rids.elements[j];
345                   int k;
346                   Queue rinfo;
347                   queue_init(&rinfo);
348
349                   solver_allruleinfos(solv, probr, &rinfo);
350                   for (k = 0; k < rinfo.count; k += 4)
351                     {
352                       Id dep, source, target;
353                       source = rinfo.elements[k + 1];
354                       target = rinfo.elements[k + 2];
355                       dep = rinfo.elements[k + 3];
356                       switch (rinfo.elements[k])
357                         {
358                         case SOLVER_RULE_DISTUPGRADE:
359                           break;
360                         case SOLVER_RULE_INFARCH:
361                           s = pool_id2solvable(pool, source);
362                           printf("  %s has inferior architecture\n", pool_solvable2str(pool, s));
363                           break;
364                         case SOLVER_RULE_UPDATE:
365                           s = pool_id2solvable(pool, source);
366                           printf("  %s can not be updated\n", pool_solvable2str(pool, s));
367                           break;
368                         case SOLVER_RULE_JOB:
369                         case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
370                         case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
371                         case SOLVER_RULE_JOB_UNSUPPORTED:
372                           break;
373                         case SOLVER_RULE_RPM:
374                           printf("  some dependency problem\n");
375                           break;
376                         case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
377                           printf("  nothing provides requested %s\n", pool_dep2str(pool, dep));
378                           break;
379                         case SOLVER_RULE_RPM_NOT_INSTALLABLE:
380                           s = pool_id2solvable(pool, source);
381                           printf("  package %s is not installable\n", pool_solvable2str(pool, s));
382                           break;
383                         case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
384                           s = pool_id2solvable(pool, source);
385                           printf("  nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvable2str(pool, s));
386                           if (ISRELDEP(dep))
387                             {
388                               Reldep *rd = GETRELDEP(pool, dep);
389                               if (!ISRELDEP(rd->name))
390                                 {
391                                   Id rp, rpp;
392                                   FOR_PROVIDES(rp, rpp, rd->name)
393                                     printf("    (we have %s)\n", pool_solvable2str(pool, pool->solvables + rp));
394                                 }
395                             }
396                           break;
397                         case SOLVER_RULE_RPM_SAME_NAME:
398                           s = pool_id2solvable(pool, source);
399                           s2 = pool_id2solvable(pool, target);
400                           printf("  cannot install both %s and %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2));
401                           break;
402                         case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
403                           s = pool_id2solvable(pool, source);
404                           s2 = pool_id2solvable(pool, target);
405                           printf("  package %s conflicts with %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
406                           break;
407                         case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
408                           s = pool_id2solvable(pool, source);
409                           s2 = pool_id2solvable(pool, target);
410                           printf("  package %s obsoletes %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
411                           break;
412                         case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
413                           s = pool_id2solvable(pool, source);
414                           printf("  package %s requires %s, but none of the providers can be installed\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
415                           break;
416                         case SOLVER_RULE_RPM_SELF_CONFLICT:
417                           s = pool_id2solvable(pool, source);
418                           printf("  package %s conflicts with %s provided by itself\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
419                           break;
420                         }
421                     }
422                 }
423             }
424         }
425 #if 0
426       else
427         {
428           if (!strcmp(pool_id2str(pool, s->name), "libusb-compat-devel"))
429             {
430               solver_printdecisions(solv);
431             }
432         }
433 #endif
434     }
435   solver_free(solv);
436   exit(status);
437 }