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