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