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