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