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