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